summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/os/BatteryStats.java37
-rw-r--r--core/java/com/android/internal/os/BatteryStatsHelper.java1
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java293
-rw-r--r--core/java/com/android/internal/os/CpuPowerCalculator.java70
-rw-r--r--core/java/com/android/internal/os/KernelCpuSpeedReader.java69
-rw-r--r--core/java/com/android/internal/os/KernelUidCpuTimeReader.java84
-rw-r--r--core/java/com/android/internal/os/ProcessCpuTracker.java79
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;
}