diff options
Diffstat (limited to 'core')
7 files changed, 351 insertions, 282 deletions
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 4dfe0de..5f515eb 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -425,6 +425,24 @@ public abstract class BatteryStats implements Parcelable { public abstract long getMobileRadioActiveTime(int which); public abstract int getMobileRadioActiveCount(int which); + /** + * Get the total cpu time (in microseconds) this UID had processes executing in userspace. + */ + public abstract long getUserCpuTimeUs(int which); + + /** + * Get the total cpu time (in microseconds) this UID had processes executing kernel syscalls. + */ + public abstract long getSystemCpuTimeUs(int which); + + /** + * Returns the approximate cpu time (in milliseconds) spent at a certain CPU speed. + * @param speedStep the index of the CPU speed. This is not the actual speed of the CPU. + * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. + * @see BatteryStats#getCpuSpeedSteps() + */ + public abstract long getTimeAtCpuSpeed(int step, int which); + public static abstract class Sensor { /* * FIXME: it's not correct to use this magic value because it @@ -506,15 +524,6 @@ public abstract class BatteryStats implements Parcelable { */ public abstract long getForegroundTime(int which); - /** - * Returns the approximate cpu time (in milliseconds) spent at a certain CPU speed. - * @param speedStep the index of the CPU speed. This is not the actual speed of the - * CPU. - * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. - * @see BatteryStats#getCpuSpeedSteps() - */ - public abstract long getTimeAtCpuSpeedStep(int speedStep, int which); - public abstract int countExcessivePowers(); public abstract ExcessivePower getExcessivePower(int i); @@ -3873,6 +3882,16 @@ public abstract class BatteryStats implements Parcelable { } } + final long userCpuTimeUs = u.getUserCpuTimeUs(which); + final long systemCpuTimeUs = u.getSystemCpuTimeUs(which); + if (userCpuTimeUs > 0 || systemCpuTimeUs > 0) { + sb.setLength(0); + sb.append(prefix); + sb.append(" Total cpu time: "); + formatTimeMs(sb, (userCpuTimeUs + systemCpuTimeUs) / 1000); + pw.println(sb.toString()); + } + final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats(); for (int ipr=processStats.size()-1; ipr>=0; ipr--) { diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java index a53d46c..ae1a563 100644 --- a/core/java/com/android/internal/os/BatteryStatsHelper.java +++ b/core/java/com/android/internal/os/BatteryStatsHelper.java @@ -742,7 +742,6 @@ public final class BatteryStatsHelper { parcel.setDataPosition(0); BatteryStatsImpl stats = com.android.internal.os.BatteryStatsImpl.CREATOR .createFromParcel(parcel); - stats.distributeWorkLocked(BatteryStats.STATS_SINCE_CHARGED); return stats; } catch (IOException e) { Log.w(TAG, "Unable to read statistics stream", e); diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 405c861..b72c774 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -104,7 +104,7 @@ public final class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version - private static final int VERSION = 125 + (USE_OLD_HISTORY ? 1000 : 0); + private static final int VERSION = 126 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; @@ -131,6 +131,9 @@ public final class BatteryStatsImpl extends BatteryStats { private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader(); private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats(); + private final KernelUidCpuTimeReader mKernelUidCpuTimeReader = new KernelUidCpuTimeReader(); + private final KernelCpuSpeedReader mKernelCpuSpeedReader = new KernelCpuSpeedReader(); + public interface BatteryCallback { public void batteryNeedsCpuUpdate(); public void batteryPowerChanged(boolean onBattery); @@ -796,20 +799,6 @@ public final class BatteryStatsImpl extends BatteryStats { } } - public static class SamplingCounter extends Counter { - SamplingCounter(TimeBase timeBase, Parcel in) { - super(timeBase, in); - } - - SamplingCounter(TimeBase timeBase) { - super(timeBase); - } - - public void addCountAtomic(long count) { - mCount.addAndGet((int)count); - } - } - public static class LongSamplingCounter extends LongCounter implements TimeBaseObs { final TimeBase mTimeBase; long mCount; @@ -2936,8 +2925,7 @@ public final class BatteryStatsImpl extends BatteryStats { public void finishAddingCpuLocked(int perc, int remainUTime, int remainSTtime, int totalUTime, int totalSTime, int statUserTime, int statSystemTime, - int statIOWaitTime, int statIrqTime, int statSoftIrqTime, int statIdleTime, - long[] cpuSpeedTimes) { + int statIOWaitTime, int statIrqTime, int statSoftIrqTime, int statIdleTime) { if (DEBUG) Slog.d(TAG, "Adding cpu: tuser=" + totalUTime + " tsys=" + totalSTime + " user=" + statUserTime + " sys=" + statSystemTime + " io=" + statIOWaitTime + " irq=" + statIrqTime @@ -2977,7 +2965,7 @@ public final class BatteryStatsImpl extends BatteryStats { remainSTtime -= mySTime; num--; Uid.Proc proc = uid.getProcessStatsLocked("*wakelock*"); - proc.addCpuTimeLocked(myUTime, mySTime, cpuSpeedTimes); + proc.addCpuTimeLocked(myUTime, mySTime); } } } @@ -2988,7 +2976,7 @@ public final class BatteryStatsImpl extends BatteryStats { Uid uid = getUidStatsLocked(Process.SYSTEM_UID); if (uid != null) { Uid.Proc proc = uid.getProcessStatsLocked("*lost*"); - proc.addCpuTimeLocked(remainUTime, remainSTtime, cpuSpeedTimes); + proc.addCpuTimeLocked(remainUTime, remainSTtime); } } } @@ -4416,6 +4404,10 @@ public final class BatteryStatsImpl extends BatteryStats { long mCurStepUserTime; long mCurStepSystemTime; + LongSamplingCounter mUserCpuTime = new LongSamplingCounter(mOnBatteryTimeBase); + LongSamplingCounter mSystemCpuTime = new LongSamplingCounter(mOnBatteryTimeBase); + LongSamplingCounter[] mSpeedBins; + /** * The statistics we have collected for this uid's wake locks. */ @@ -4473,6 +4465,7 @@ public final class BatteryStatsImpl extends BatteryStats { mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED, mWifiMulticastTimers, mOnBatteryTimeBase); mProcessStateTimer = new StopwatchTimer[NUM_PROCESS_STATE]; + mSpeedBins = new LongSamplingCounter[getCpuSpeedSteps()]; } @Override @@ -4943,6 +4936,26 @@ public final class BatteryStatsImpl extends BatteryStats { } @Override + public long getUserCpuTimeUs(int which) { + return mUserCpuTime.getCountLocked(which); + } + + @Override + public long getSystemCpuTimeUs(int which) { + return mSystemCpuTime.getCountLocked(which); + } + + @Override + public long getTimeAtCpuSpeed(int step, int which) { + if (step >= 0 && step < mSpeedBins.length) { + if (mSpeedBins[step] != null) { + return mSpeedBins[step].getCountLocked(which); + } + } + return 0; + } + + @Override public long getWifiControllerActivity(int type, int which) { if (type >= 0 && type < NUM_CONTROLLER_ACTIVITY_TYPES && mWifiControllerTime[type] != null) { @@ -5044,6 +5057,15 @@ public final class BatteryStatsImpl extends BatteryStats { } } + mUserCpuTime.reset(false); + mSystemCpuTime.reset(false); + for (int i = 0; i < mSpeedBins.length; i++) { + LongSamplingCounter c = mSpeedBins[i]; + if (c != null) { + c.reset(false); + } + } + final ArrayMap<String, Wakelock> wakeStats = mWakelockStats.getMap(); for (int iw=wakeStats.size()-1; iw>=0; iw--) { Wakelock wl = wakeStats.valueAt(iw); @@ -5177,6 +5199,15 @@ public final class BatteryStatsImpl extends BatteryStats { } } mPids.clear(); + + mUserCpuTime.detach(); + mSystemCpuTime.detach(); + for (int i = 0; i < mSpeedBins.length; i++) { + LongSamplingCounter c = mSpeedBins[i]; + if (c != null) { + c.detach(); + } + } } return !active; @@ -5335,6 +5366,20 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeInt(0); } } + + mUserCpuTime.writeToParcel(out); + mSystemCpuTime.writeToParcel(out); + + out.writeInt(mSpeedBins.length); + for (int i = 0; i < mSpeedBins.length; i++) { + LongSamplingCounter c = mSpeedBins[i]; + if (c != null) { + out.writeInt(1); + c.writeToParcel(out); + } else { + out.writeInt(0); + } + } } void readFromParcelLocked(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) { @@ -5500,6 +5545,18 @@ public final class BatteryStatsImpl extends BatteryStats { mBluetoothControllerTime[i] = null; } } + + mUserCpuTime = new LongSamplingCounter(mOnBatteryTimeBase, in); + mSystemCpuTime = new LongSamplingCounter(mOnBatteryTimeBase, in); + + int bins = in.readInt(); + int steps = getCpuSpeedSteps(); + mSpeedBins = new LongSamplingCounter[bins >= steps ? bins : steps]; + for (int i = 0; i < bins; i++) { + if (in.readInt() != 0) { + mSpeedBins[i] = new LongSamplingCounter(mOnBatteryTimeBase, in); + } + } } /** @@ -5780,14 +5837,11 @@ public final class BatteryStatsImpl extends BatteryStats { */ int mProcessState = PROCESS_STATE_NONE; - SamplingCounter[] mSpeedBins; - ArrayList<ExcessivePower> mExcessivePower; Proc(String name) { mName = name; mOnBatteryTimeBase.add(this); - mSpeedBins = new SamplingCounter[getCpuSpeedSteps()]; } public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) { @@ -5809,25 +5863,12 @@ public final class BatteryStatsImpl extends BatteryStats { mLoadedStarts = mLoadedNumCrashes = mLoadedNumAnrs = 0; mUnpluggedUserTime = mUnpluggedSystemTime = mUnpluggedForegroundTime = 0; mUnpluggedStarts = mUnpluggedNumCrashes = mUnpluggedNumAnrs = 0; - for (int i = 0; i < mSpeedBins.length; i++) { - SamplingCounter c = mSpeedBins[i]; - if (c != null) { - c.reset(false); - } - } mExcessivePower = null; } void detach() { mActive = false; mOnBatteryTimeBase.remove(this); - for (int i = 0; i < mSpeedBins.length; i++) { - SamplingCounter c = mSpeedBins[i]; - if (c != null) { - mOnBatteryTimeBase.remove(c); - mSpeedBins[i] = null; - } - } } public int countExcessivePowers() { @@ -5921,18 +5962,6 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeInt(mUnpluggedStarts); out.writeInt(mUnpluggedNumCrashes); out.writeInt(mUnpluggedNumAnrs); - - out.writeInt(mSpeedBins.length); - for (int i = 0; i < mSpeedBins.length; i++) { - SamplingCounter c = mSpeedBins[i]; - if (c != null) { - out.writeInt(1); - c.writeToParcel(out); - } else { - out.writeInt(0); - } - } - writeExcessivePowerToParcelLocked(out); } @@ -5955,39 +5984,12 @@ public final class BatteryStatsImpl extends BatteryStats { mUnpluggedStarts = in.readInt(); mUnpluggedNumCrashes = in.readInt(); mUnpluggedNumAnrs = in.readInt(); - - int bins = in.readInt(); - int steps = getCpuSpeedSteps(); - mSpeedBins = new SamplingCounter[bins >= steps ? bins : steps]; - for (int i = 0; i < bins; i++) { - if (in.readInt() != 0) { - mSpeedBins[i] = new SamplingCounter(mOnBatteryTimeBase, in); - } - } - readExcessivePowerFromParcelLocked(in); } - public BatteryStatsImpl getBatteryStats() { - return BatteryStatsImpl.this; - } - - public void addCpuTimeLocked(int utime, int stime, long[] speedStepBins) { + public void addCpuTimeLocked(int utime, int stime) { mUserTime += utime; - mCurStepUserTime += utime; mSystemTime += stime; - mCurStepSystemTime += stime; - - for (int i = 0; i < mSpeedBins.length && i < speedStepBins.length; i++) { - long amt = speedStepBins[i]; - if (amt != 0) { - SamplingCounter c = mSpeedBins[i]; - if (c == null) { - mSpeedBins[i] = c = new SamplingCounter(mOnBatteryTimeBase); - } - c.addCountAtomic(speedStepBins[i]); - } - } } public void addForegroundTimeLocked(long ttime) { @@ -6076,16 +6078,6 @@ public final class BatteryStatsImpl extends BatteryStats { } return val; } - - @Override - public long getTimeAtCpuSpeedStep(int speedStep, int which) { - if (speedStep < mSpeedBins.length) { - SamplingCounter c = mSpeedBins[speedStep]; - return c != null ? c.getCountLocked(which) : 0; - } else { - return 0; - } - } } /** @@ -7803,6 +7795,32 @@ public final class BatteryStatsImpl extends BatteryStats { } } + /** + * Read and distribute CPU usage across apps. + */ + public void updateCpuTimeLocked(boolean firstTime) { + final int cpuSpeedSteps = getCpuSpeedSteps(); + final long[] cpuSpeeds = mKernelCpuSpeedReader.readDelta(); + KernelUidCpuTimeReader.Callback callback = null; + if (mOnBatteryInternal && !firstTime) { + callback = new KernelUidCpuTimeReader.Callback() { + @Override + public void onUidCpuTime(int uid, long userTimeUs, long systemTimeUs) { + final Uid u = getUidStatsLocked(mapUid(uid)); + u.mUserCpuTime.addCountLocked(userTimeUs); + u.mSystemCpuTime.addCountLocked(systemTimeUs); + for (int i = 0; i < cpuSpeedSteps; i++) { + if (u.mSpeedBins[i] == null) { + u.mSpeedBins[i] = new LongSamplingCounter(mOnBatteryTimeBase); + } + u.mSpeedBins[i].addCountLocked(cpuSpeeds[i]); + } + } + }; + } + mKernelUidCpuTimeReader.readDelta(callback); + } + boolean setChargingLocked(boolean charging) { if (mCharging != charging) { mCharging = charging; @@ -8464,58 +8482,6 @@ public final class BatteryStatsImpl extends BatteryStats { return u.getServiceStatsLocked(pkg, name); } - /** - * Massage data to distribute any reasonable work down to more specific - * owners. Must only be called on a dead BatteryStats object! - */ - public void distributeWorkLocked(int which) { - // Aggregate all CPU time associated with WIFI. - Uid wifiUid = mUidStats.get(Process.WIFI_UID); - if (wifiUid != null) { - long uSecTime = computeBatteryRealtime(SystemClock.elapsedRealtime() * 1000, which); - for (int ip=wifiUid.mProcessStats.size()-1; ip>=0; ip--) { - Uid.Proc proc = wifiUid.mProcessStats.valueAt(ip); - long totalRunningTime = getGlobalWifiRunningTime(uSecTime, which); - for (int i=0; i<mUidStats.size(); i++) { - Uid uid = mUidStats.valueAt(i); - if (uid.mUid != Process.WIFI_UID) { - long uidRunningTime = uid.getWifiRunningTime(uSecTime, which); - if (uidRunningTime > 0) { - Uid.Proc uidProc = uid.getProcessStatsLocked("*wifi*"); - long time = proc.getUserTime(which); - time = (time*uidRunningTime)/totalRunningTime; - uidProc.mUserTime += time; - proc.mUserTime -= time; - time = proc.getSystemTime(which); - time = (time*uidRunningTime)/totalRunningTime; - uidProc.mSystemTime += time; - proc.mSystemTime -= time; - time = proc.getForegroundTime(which); - time = (time*uidRunningTime)/totalRunningTime; - uidProc.mForegroundTime += time; - proc.mForegroundTime -= time; - for (int sb=0; sb<proc.mSpeedBins.length; sb++) { - SamplingCounter sc = proc.mSpeedBins[sb]; - if (sc != null) { - time = sc.getCountLocked(which); - time = (time*uidRunningTime)/totalRunningTime; - SamplingCounter uidSc = uidProc.mSpeedBins[sb]; - if (uidSc == null) { - uidSc = new SamplingCounter(mOnBatteryTimeBase); - uidProc.mSpeedBins[sb] = uidSc; - } - uidSc.mCount.addAndGet((int)time); - sc.mCount.addAndGet((int)-time); - } - } - totalRunningTime -= uidRunningTime; - } - } - } - } - } - } - public void shutdownLocked() { recordShutdownLocked(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis()); writeSyncLocked(); @@ -8974,6 +8940,23 @@ public final class BatteryStatsImpl extends BatteryStats { u.mMobileRadioActiveCount.readSummaryFromParcelLocked(in); } + u.mUserCpuTime.readSummaryFromParcelLocked(in); + u.mSystemCpuTime.readSummaryFromParcelLocked(in); + + int NSB = in.readInt(); + if (NSB > 100) { + Slog.w(TAG, "File corrupt: too many speed bins " + NSB); + return; + } + + u.mSpeedBins = new LongSamplingCounter[NSB]; + for (int i=0; i<NSB; i++) { + if (in.readInt() != 0) { + u.mSpeedBins[i] = new LongSamplingCounter(mOnBatteryTimeBase); + u.mSpeedBins[i].readSummaryFromParcelLocked(in); + } + } + int NW = in.readInt(); if (NW > 100) { Slog.w(TAG, "File corrupt: too many wake locks " + NW); @@ -9031,18 +9014,6 @@ public final class BatteryStatsImpl extends BatteryStats { p.mStarts = p.mLoadedStarts = in.readInt(); p.mNumCrashes = p.mLoadedNumCrashes = in.readInt(); p.mNumAnrs = p.mLoadedNumAnrs = in.readInt(); - int NSB = in.readInt(); - if (NSB > 100) { - Slog.w(TAG, "File corrupt: too many speed bins " + NSB); - return; - } - p.mSpeedBins = new SamplingCounter[NSB]; - for (int i=0; i<NSB; i++) { - if (in.readInt() != 0) { - p.mSpeedBins[i] = new SamplingCounter(mOnBatteryTimeBase); - p.mSpeedBins[i].readSummaryFromParcelLocked(in); - } - } if (!p.readExcessivePowerFromParcelLocked(in)) { return; } @@ -9302,6 +9273,20 @@ public final class BatteryStatsImpl extends BatteryStats { u.mMobileRadioActiveCount.writeSummaryFromParcelLocked(out); } + u.mUserCpuTime.writeSummaryFromParcelLocked(out); + u.mSystemCpuTime.writeSummaryFromParcelLocked(out); + + out.writeInt(u.mSpeedBins.length); + for (int i = 0; i < u.mSpeedBins.length; i++) { + LongSamplingCounter speedBin = u.mSpeedBins[i]; + if (speedBin != null) { + out.writeInt(1); + speedBin.writeSummaryFromParcelLocked(out); + } else { + out.writeInt(0); + } + } + final ArrayMap<String, Uid.Wakelock> wakeStats = u.mWakelockStats.getMap(); int NW = wakeStats.size(); out.writeInt(NW); @@ -9368,16 +9353,6 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeInt(ps.mStarts); out.writeInt(ps.mNumCrashes); out.writeInt(ps.mNumAnrs); - final int N = ps.mSpeedBins.length; - out.writeInt(N); - for (int i=0; i<N; i++) { - if (ps.mSpeedBins[i] != null) { - out.writeInt(1); - ps.mSpeedBins[i].writeSummaryFromParcelLocked(out); - } else { - out.writeInt(0); - } - } ps.writeExcessivePowerToParcelLocked(out); } diff --git a/core/java/com/android/internal/os/CpuPowerCalculator.java b/core/java/com/android/internal/os/CpuPowerCalculator.java index 6c3f958..a3ef612 100644 --- a/core/java/com/android/internal/os/CpuPowerCalculator.java +++ b/core/java/com/android/internal/os/CpuPowerCalculator.java @@ -44,55 +44,57 @@ public class CpuPowerCalculator extends PowerCalculator { long rawUptimeUs, int statsType) { final int speedSteps = mSpeedStepTimes.length; + long totalTimeAtSpeeds = 0; + for (int step = 0; step < speedSteps; step++) { + mSpeedStepTimes[step] = u.getTimeAtCpuSpeed(step, statsType); + totalTimeAtSpeeds += mSpeedStepTimes[step]; + } + totalTimeAtSpeeds = Math.max(totalTimeAtSpeeds, 1); + + app.cpuTimeMs = (u.getUserCpuTimeUs(statsType) + u.getSystemCpuTimeUs(statsType)) / 1000; + if (DEBUG && app.cpuTimeMs != 0) { + Log.d(TAG, "UID " + u.getUid() + ": CPU time " + app.cpuTimeMs + " ms"); + } + + double cpuPowerMaMs = 0; + for (int step = 0; step < speedSteps; step++) { + final double ratio = (double) mSpeedStepTimes[step] / totalTimeAtSpeeds; + final double cpuSpeedStepPower = ratio * app.cpuTimeMs * mPowerCpuNormal[step]; + if (DEBUG && ratio != 0) { + Log.d(TAG, "UID " + u.getUid() + ": CPU step #" + + step + " ratio=" + BatteryStatsHelper.makemAh(ratio) + " power=" + + BatteryStatsHelper.makemAh(cpuSpeedStepPower / (60 * 60 * 1000))); + } + cpuPowerMaMs += cpuSpeedStepPower; + } + + if (DEBUG && cpuPowerMaMs != 0) { + Log.d(TAG, "UID " + u.getUid() + ": cpu total power=" + + BatteryStatsHelper.makemAh(cpuPowerMaMs / (60 * 60 * 1000))); + } + // Keep track of the package with highest drain. double highestDrain = 0; + app.cpuFgTimeMs = 0; final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats(); final int processStatsCount = processStats.size(); for (int i = 0; i < processStatsCount; i++) { final BatteryStats.Uid.Proc ps = processStats.valueAt(i); final String processName = processStats.keyAt(i); - app.cpuFgTimeMs += ps.getForegroundTime(statsType); - final long totalCpuTime = ps.getUserTime(statsType) + ps.getSystemTime(statsType); - app.cpuTimeMs += totalCpuTime; - - // Calculate the total CPU time spent at the various speed steps. - long totalTimeAtSpeeds = 0; - for (int step = 0; step < speedSteps; step++) { - mSpeedStepTimes[step] = ps.getTimeAtCpuSpeedStep(step, statsType); - totalTimeAtSpeeds += mSpeedStepTimes[step]; - } - totalTimeAtSpeeds = Math.max(totalTimeAtSpeeds, 1); - - // Then compute the ratio of time spent at each speed and figure out - // the total power consumption. - double cpuPower = 0; - for (int step = 0; step < speedSteps; step++) { - final double ratio = (double) mSpeedStepTimes[step] / totalTimeAtSpeeds; - final double cpuSpeedStepPower = ratio * totalCpuTime * mPowerCpuNormal[step]; - if (DEBUG && ratio != 0) { - Log.d(TAG, "UID " + u.getUid() + ": CPU step #" - + step + " ratio=" + BatteryStatsHelper.makemAh(ratio) + " power=" - + BatteryStatsHelper.makemAh(cpuSpeedStepPower / (60 * 60 * 1000))); - } - cpuPower += cpuSpeedStepPower; - } - if (DEBUG && cpuPower != 0) { - Log.d(TAG, String.format("process %s, cpu power=%s", - processName, BatteryStatsHelper.makemAh(cpuPower / (60 * 60 * 1000)))); - } - app.cpuPowerMah += cpuPower; + final long costValue = ps.getUserTime(statsType) + ps.getSystemTime(statsType) + + ps.getForegroundTime(statsType); // Each App can have multiple packages and with multiple running processes. // Keep track of the package who's process has the highest drain. if (app.packageWithHighestDrain == null || app.packageWithHighestDrain.startsWith("*")) { - highestDrain = cpuPower; + highestDrain = costValue; app.packageWithHighestDrain = processName; - } else if (highestDrain < cpuPower && !processName.startsWith("*")) { - highestDrain = cpuPower; + } else if (highestDrain < costValue && !processName.startsWith("*")) { + highestDrain = costValue; app.packageWithHighestDrain = processName; } } @@ -108,6 +110,6 @@ public class CpuPowerCalculator extends PowerCalculator { } // Convert the CPU power to mAh - app.cpuPowerMah /= (60 * 60 * 1000); + app.cpuPowerMah = cpuPowerMaMs / (60 * 60 * 1000); } } diff --git a/core/java/com/android/internal/os/KernelCpuSpeedReader.java b/core/java/com/android/internal/os/KernelCpuSpeedReader.java new file mode 100644 index 0000000..c30df28 --- /dev/null +++ b/core/java/com/android/internal/os/KernelCpuSpeedReader.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.os; + +import android.text.TextUtils; +import android.util.Slog; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.Arrays; + +/** + * Reads CPU time spent at various frequencies and provides a delta from the last call to + * {@link #readDelta}. Each line in the proc file has the format: + * + * freq time + * + * where time is measured in 1/100 seconds. + */ +public class KernelCpuSpeedReader { + private static final String TAG = "KernelCpuSpeedReader"; + private static final String sProcFile = + "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state"; + private static final int MAX_SPEEDS = 60; + + private long[] mLastSpeedTimes = new long[MAX_SPEEDS]; + private long[] mDeltaSpeedTimes = new long[MAX_SPEEDS]; + + /** + * The returned array is modified in subsequent calls to {@link #readDelta}. + * @return The time (in milliseconds) spent at different cpu speeds since the last call to + * {@link #readDelta}. + */ + public long[] readDelta() { + try (BufferedReader reader = new BufferedReader(new FileReader(sProcFile))) { + TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(' '); + String line; + int speedIndex = 0; + while ((line = reader.readLine()) != null) { + splitter.setString(line); + Long.parseLong(splitter.next()); + + // The proc file reports time in 1/100 sec, so convert to milliseconds. + long time = Long.parseLong(splitter.next()) * 10; + mDeltaSpeedTimes[speedIndex] = time - mLastSpeedTimes[speedIndex]; + mLastSpeedTimes[speedIndex] = time; + speedIndex++; + } + } catch (IOException e) { + Slog.e(TAG, "Failed to read cpu-freq", e); + Arrays.fill(mDeltaSpeedTimes, 0); + } + return mDeltaSpeedTimes; + } +} diff --git a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java new file mode 100644 index 0000000..197e5b1 --- /dev/null +++ b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.os; + +import android.annotation.Nullable; +import android.text.TextUtils; +import android.util.Slog; +import android.util.SparseLongArray; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; + +/** + * Reads /proc/uid_cputime/show_uid_stat which has the line format: + * + * uid: user_time_micro_seconds system_time_micro_seconds + * + * This provides the time a UID's processes spent executing in user-space and kernel-space. + * The file contains a monotonically increasing count of time for a single boot. This class + * maintains the previous results of a call to {@link #readDelta} in order to provide a proper + * delta. + */ +public class KernelUidCpuTimeReader { + private static final String TAG = "KernelUidCpuTimeReader"; + private static final String sProcFile = "/proc/uid_cputime/show_uid_stat"; + + /** + * Callback interface for processing each line of the proc file. + */ + public interface Callback { + void onUidCpuTime(int uid, long userTimeUs, long systemTimeUs); + } + + private SparseLongArray mLastUserTimeUs = new SparseLongArray(); + private SparseLongArray mLastSystemTimeUs = new SparseLongArray(); + + /** + * Reads the proc file, calling into the callback with a delta of time for each UID. + * @param callback The callback to invoke for each line of the proc file. If null, + * the data is consumed and subsequent calls to readDelta will provide + * a fresh delta. + */ + public void readDelta(@Nullable Callback callback) { + try (BufferedReader reader = new BufferedReader(new FileReader(sProcFile))) { + TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(' '); + String line; + while ((line = reader.readLine()) != null) { + splitter.setString(line); + final String uidStr = splitter.next(); + final int uid = Integer.parseInt(uidStr.substring(0, uidStr.length() - 1), 10); + final long userTimeUs = Long.parseLong(splitter.next(), 10); + final long systemTimeUs = Long.parseLong(splitter.next(), 10); + + if (callback != null) { + int index = mLastUserTimeUs.indexOfKey(uid); + if (index < 0) { + callback.onUidCpuTime(uid, userTimeUs, systemTimeUs); + } else { + callback.onUidCpuTime(uid, userTimeUs - mLastUserTimeUs.valueAt(index), + systemTimeUs - mLastSystemTimeUs.valueAt(index)); + } + } + mLastUserTimeUs.put(uid, userTimeUs); + mLastSystemTimeUs.put(uid, systemTimeUs); + } + } catch (IOException e) { + Slog.e(TAG, "Failed to read uid_cputime", e); + } + } +} diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java index 2983047..8393e2a 100644 --- a/core/java/com/android/internal/os/ProcessCpuTracker.java +++ b/core/java/com/android/internal/os/ProcessCpuTracker.java @@ -170,21 +170,6 @@ public class ProcessCpuTracker { private byte[] mBuffer = new byte[4096]; - /** - * The time in microseconds that the CPU has been running at each speed. - */ - private long[] mCpuSpeedTimes; - - /** - * The relative time in microseconds that the CPU has been running at each speed. - */ - private long[] mRelCpuSpeedTimes; - - /** - * The different speeds that the CPU can be running at. - */ - private long[] mCpuSpeeds; - public static class Stats { public final int pid; public final int uid; @@ -590,70 +575,6 @@ public class ProcessCpuTracker { } } - /** - * Returns the delta time (in clock ticks, or 1/100 sec) spent at each CPU - * speed, since the last call to this method. If this is the first call, it - * will return 1 for each value. - */ - public long[] getLastCpuSpeedTimes() { - if (mCpuSpeedTimes == null) { - mCpuSpeedTimes = getCpuSpeedTimes(null); - mRelCpuSpeedTimes = new long[mCpuSpeedTimes.length]; - for (int i = 0; i < mCpuSpeedTimes.length; i++) { - mRelCpuSpeedTimes[i] = 1; // Initialize - } - } else { - getCpuSpeedTimes(mRelCpuSpeedTimes); - for (int i = 0; i < mCpuSpeedTimes.length; i++) { - long temp = mRelCpuSpeedTimes[i]; - mRelCpuSpeedTimes[i] -= mCpuSpeedTimes[i]; - mCpuSpeedTimes[i] = temp; - } - } - return mRelCpuSpeedTimes; - } - - private long[] getCpuSpeedTimes(long[] out) { - long[] tempTimes = out; - long[] tempSpeeds = mCpuSpeeds; - final int MAX_SPEEDS = 60; - if (out == null) { - tempTimes = new long[MAX_SPEEDS]; // Hopefully no more than that - tempSpeeds = new long[MAX_SPEEDS]; - } - int speed = 0; - String file = readFile("/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state", '\0'); - // Note: file may be null on kernels without cpufreq (i.e. the emulator's) - if (file != null) { - StringTokenizer st = new StringTokenizer(file, "\n "); - while (st.hasMoreElements()) { - String token = st.nextToken(); - try { - long val = Long.parseLong(token); - tempSpeeds[speed] = val; - token = st.nextToken(); - val = Long.parseLong(token); - tempTimes[speed] = val; - speed++; - if (speed == MAX_SPEEDS) break; // No more - if (localLOGV && out == null) { - Slog.v(TAG, "First time : Speed/Time = " + tempSpeeds[speed - 1] - + "\t" + tempTimes[speed - 1]); - } - } catch (NumberFormatException nfe) { - Slog.i(TAG, "Unable to parse time_in_state"); - } - } - } - if (out == null) { - out = new long[speed]; - mCpuSpeeds = new long[speed]; - System.arraycopy(tempSpeeds, 0, mCpuSpeeds, 0, speed); - System.arraycopy(tempTimes, 0, out, 0, speed); - } - return out; - } - final public int getLastUserTime() { return mRelUserTime; } |