Loading core/java/android/os/BatteryStats.java +6 −7 Original line number Diff line number Diff line Loading @@ -463,13 +463,15 @@ public abstract class BatteryStats implements Parcelable { public abstract long getCpuPowerMaUs(int which); /** * Returns the approximate cpu time (in milliseconds) spent at a certain CPU speed. * Returns the approximate cpu time (in milliseconds) spent at a certain CPU speed for a * given CPU cluster. * @param cluster the index of the CPU cluster. * @param step 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() * @see PowerProfile.getNumCpuClusters() * @see PowerProfile.getNumSpeedStepsInCpuCluster(int) */ @Deprecated public abstract long getTimeAtCpuSpeed(int step, int which); public abstract long getTimeAtCpuSpeed(int cluster, int step, int which); public static abstract class Sensor { /* Loading Loading @@ -2276,9 +2278,6 @@ public abstract class BatteryStats implements Parcelable { public abstract Map<String, ? extends Timer> getKernelWakelockStats(); /** Returns the number of different speeds that the CPU can run at */ public abstract int getCpuSpeedSteps(); public abstract void writeToParcelWithoutUids(Parcel out, int flags); private final static void formatTimeRaw(StringBuilder out, long seconds) { Loading core/java/com/android/internal/os/BatteryStatsHelper.java +1 −1 Original line number Diff line number Diff line Loading @@ -338,7 +338,7 @@ public final class BatteryStatsHelper { } if (mCpuPowerCalculator == null) { mCpuPowerCalculator = new CpuPowerCalculator(); mCpuPowerCalculator = new CpuPowerCalculator(mPowerProfile); } mCpuPowerCalculator.reset(); Loading core/java/com/android/internal/os/BatteryStatsImpl.java +159 −75 Original line number Diff line number Diff line Loading @@ -105,7 +105,7 @@ public final class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version private static final int VERSION = 130 + (USE_OLD_HISTORY ? 1000 : 0); private static final int VERSION = 131 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; Loading @@ -118,8 +118,6 @@ public final class BatteryStatsImpl extends BatteryStats { // in to one common name. private static final int MAX_WAKELOCKS_PER_UID = 100; private static int sNumSpeedSteps; private final JournaledFile mFile; public final AtomicFile mCheckinFile; public final AtomicFile mDailyFile; Loading @@ -133,7 +131,7 @@ public final class BatteryStatsImpl extends BatteryStats { private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats(); private final KernelUidCpuTimeReader mKernelUidCpuTimeReader = new KernelUidCpuTimeReader(); private final KernelCpuSpeedReader mKernelCpuSpeedReader = new KernelCpuSpeedReader(); private KernelCpuSpeedReader[] mKernelCpuSpeedReaders; public interface BatteryCallback { public void batteryNeedsCpuUpdate(); Loading Loading @@ -4411,7 +4409,7 @@ public final class BatteryStatsImpl extends BatteryStats { LongSamplingCounter mUserCpuTime = new LongSamplingCounter(mOnBatteryTimeBase); LongSamplingCounter mSystemCpuTime = new LongSamplingCounter(mOnBatteryTimeBase); LongSamplingCounter mCpuPower = new LongSamplingCounter(mOnBatteryTimeBase); LongSamplingCounter[] mSpeedBins; LongSamplingCounter[][] mCpuClusterSpeed; /** * The statistics we have collected for this uid's wake locks. Loading Loading @@ -4470,7 +4468,6 @@ 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 Loading Loading @@ -5008,10 +5005,18 @@ public final class BatteryStatsImpl extends BatteryStats { } @Override public long getTimeAtCpuSpeed(int step, int which) { if (step >= 0 && step < mSpeedBins.length) { if (mSpeedBins[step] != null) { return mSpeedBins[step].getCountLocked(which); public long getTimeAtCpuSpeed(int cluster, int step, int which) { if (mCpuClusterSpeed != null) { if (cluster >= 0 && cluster < mCpuClusterSpeed.length) { final LongSamplingCounter[] cpuSpeeds = mCpuClusterSpeed[cluster]; if (cpuSpeeds != null) { if (step >= 0 && step < cpuSpeeds.length) { final LongSamplingCounter c = cpuSpeeds[step]; if (c != null) { return c.getCountLocked(which); } } } } } return 0; Loading Loading @@ -5128,10 +5133,16 @@ public final class BatteryStatsImpl extends BatteryStats { mUserCpuTime.reset(false); mSystemCpuTime.reset(false); mCpuPower.reset(false); for (int i = 0; i < mSpeedBins.length; i++) { LongSamplingCounter c = mSpeedBins[i]; if (c != null) { c.reset(false); if (mCpuClusterSpeed != null) { for (LongSamplingCounter[] speeds : mCpuClusterSpeed) { if (speeds != null) { for (LongSamplingCounter speed : speeds) { if (speed != null) { speed.reset(false); } } } } } Loading Loading @@ -5280,13 +5291,19 @@ public final class BatteryStatsImpl extends BatteryStats { mUserCpuTime.detach(); mSystemCpuTime.detach(); mCpuPower.detach(); for (int i = 0; i < mSpeedBins.length; i++) { LongSamplingCounter c = mSpeedBins[i]; if (mCpuClusterSpeed != null) { for (LongSamplingCounter[] cpuSpeeds : mCpuClusterSpeed) { if (cpuSpeeds != null) { for (LongSamplingCounter c : cpuSpeeds) { if (c != null) { c.detach(); } } } } } } return !active; } Loading Loading @@ -5461,9 +5478,14 @@ public final class BatteryStatsImpl extends BatteryStats { mSystemCpuTime.writeToParcel(out); mCpuPower.writeToParcel(out); out.writeInt(mSpeedBins.length); for (int i = 0; i < mSpeedBins.length; i++) { LongSamplingCounter c = mSpeedBins[i]; if (mCpuClusterSpeed != null) { out.writeInt(1); out.writeInt(mCpuClusterSpeed.length); for (LongSamplingCounter[] cpuSpeeds : mCpuClusterSpeed) { if (cpuSpeeds != null) { out.writeInt(1); out.writeInt(cpuSpeeds.length); for (LongSamplingCounter c : cpuSpeeds) { if (c != null) { out.writeInt(1); c.writeToParcel(out); Loading @@ -5471,6 +5493,13 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeInt(0); } } } else { out.writeInt(0); } } } else { out.writeInt(0); } } void readFromParcelLocked(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) { Loading Loading @@ -5653,13 +5682,32 @@ public final class BatteryStatsImpl extends BatteryStats { mSystemCpuTime = new LongSamplingCounter(mOnBatteryTimeBase, in); mCpuPower = 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); int numCpuClusters = in.readInt(); if (mPowerProfile != null && mPowerProfile.getNumCpuClusters() != numCpuClusters) { throw new ParcelFormatException("Incompatible number of cpu clusters"); } mCpuClusterSpeed = new LongSamplingCounter[numCpuClusters][]; for (int cluster = 0; cluster < numCpuClusters; cluster++) { if (in.readInt() != 0) { int numSpeeds = in.readInt(); if (mPowerProfile != null && mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != numSpeeds) { throw new ParcelFormatException("Incompatible number of cpu speeds"); } final LongSamplingCounter[] cpuSpeeds = new LongSamplingCounter[numSpeeds]; mCpuClusterSpeed[cluster] = cpuSpeeds; for (int speed = 0; speed < numSpeeds; speed++) { if (in.readInt() != 0) { cpuSpeeds[speed] = new LongSamplingCounter(mOnBatteryTimeBase, in); } } } } } else { mCpuClusterSpeed = null; } } Loading Loading @@ -6874,6 +6922,19 @@ public final class BatteryStatsImpl extends BatteryStats { public void setPowerProfile(PowerProfile profile) { synchronized (this) { mPowerProfile = profile; // We need to initialize the KernelCpuSpeedReaders to read from // the first cpu of each core. Once we have the PowerProfile, we have access to this // information. final int numClusters = mPowerProfile.getNumCpuClusters(); mKernelCpuSpeedReaders = new KernelCpuSpeedReader[numClusters]; int firstCpuOfCluster = 0; for (int i = 0; i < numClusters; i++) { final int numSpeedSteps = mPowerProfile.getNumSpeedStepsInCpuCluster(i); mKernelCpuSpeedReaders[i] = new KernelCpuSpeedReader(firstCpuOfCluster, numSpeedSteps); firstCpuOfCluster += mPowerProfile.getNumCoresInCpuCluster(i); } } } Loading @@ -6881,10 +6942,6 @@ public final class BatteryStatsImpl extends BatteryStats { mCallback = cb; } public void setNumSpeedSteps(int steps) { if (sNumSpeedSteps == 0) sNumSpeedSteps = steps; } public void setRadioScanningTimeout(long timeout) { if (mPhoneSignalScanningTimer != null) { mPhoneSignalScanningTimer.setTimeout(timeout); Loading Loading @@ -7997,9 +8054,11 @@ public final class BatteryStatsImpl extends BatteryStats { // If no app is holding a wakelock, then the distribution is normal. final int wakelockWeight = 50; // Read the time spent at various cpu frequencies. final int cpuSpeedSteps = getCpuSpeedSteps(); final long[] cpuSpeeds = mKernelCpuSpeedReader.readDelta(); // Read the time spent for each cluster at various cpu frequencies. final long[][] clusterSpeeds = new long[mKernelCpuSpeedReaders.length][]; for (int cluster = 0; cluster < mKernelCpuSpeedReaders.length; cluster++) { clusterSpeeds[cluster] = mKernelCpuSpeedReaders[cluster].readDelta(); } int numWakelocks = 0; Loading Loading @@ -8072,11 +8131,23 @@ public final class BatteryStatsImpl extends BatteryStats { // Add the cpu speeds to this UID. These are used as a ratio // for computing the power this UID used. for (int i = 0; i < cpuSpeedSteps; i++) { if (u.mSpeedBins[i] == null) { u.mSpeedBins[i] = new LongSamplingCounter(mOnBatteryTimeBase); if (u.mCpuClusterSpeed == null) { u.mCpuClusterSpeed = new LongSamplingCounter[clusterSpeeds.length][]; } for (int cluster = 0; cluster < clusterSpeeds.length; cluster++) { if (u.mCpuClusterSpeed[cluster] == null) { u.mCpuClusterSpeed[cluster] = new LongSamplingCounter[clusterSpeeds[cluster].length]; } final LongSamplingCounter[] cpuSpeeds = u.mCpuClusterSpeed[cluster]; for (int speed = 0; speed < clusterSpeeds[cluster].length; speed++) { if (cpuSpeeds[speed] == null) { cpuSpeeds[speed] = new LongSamplingCounter(mOnBatteryTimeBase); } cpuSpeeds[speed].addCountLocked(clusterSpeeds[cluster][speed]); } u.mSpeedBins[i].addCountLocked(cpuSpeeds[i]); } } }); Loading Loading @@ -8776,11 +8847,6 @@ public final class BatteryStatsImpl extends BatteryStats { } } @Override public int getCpuSpeedSteps() { return sNumSpeedSteps; } /** * Retrieve the statistics object for a particular uid, creating if needed. */ Loading Loading @@ -9216,11 +9282,6 @@ public final class BatteryStatsImpl extends BatteryStats { } } sNumSpeedSteps = in.readInt(); if (sNumSpeedSteps < 0 || sNumSpeedSteps > 100) { throw new ParcelFormatException("Bad speed steps in data: " + sNumSpeedSteps); } final int NU = in.readInt(); if (NU > 10000) { throw new ParcelFormatException("File corrupt: too many uids " + NU); Loading Loading @@ -9304,18 +9365,34 @@ public final class BatteryStatsImpl extends BatteryStats { u.mSystemCpuTime.readSummaryFromParcelLocked(in); u.mCpuPower.readSummaryFromParcelLocked(in); if (in.readInt() != 0) { final int numClusters = in.readInt(); if (mPowerProfile != null && mPowerProfile.getNumCpuClusters() != numClusters) { throw new ParcelFormatException("Incompatible cpu cluster arrangement"); } u.mCpuClusterSpeed = new LongSamplingCounter[numClusters][]; for (int cluster = 0; cluster < numClusters; cluster++) { int NSB = in.readInt(); if (NSB > 100) { if (mPowerProfile != null && mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != NSB) { throw new ParcelFormatException("File corrupt: too many speed bins " + NSB); } 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); u.mCpuClusterSpeed[cluster] = new LongSamplingCounter[NSB]; for (int speed = 0; speed < NSB; speed++) { if (in.readInt() != 0) { u.mCpuClusterSpeed[cluster][speed] = new LongSamplingCounter( mOnBatteryTimeBase); u.mCpuClusterSpeed[cluster][speed].readSummaryFromParcelLocked(in); } } } } } else { u.mCpuClusterSpeed = null; } int NW = in.readInt(); if (NW > 100) { Loading Loading @@ -9531,7 +9608,6 @@ public final class BatteryStatsImpl extends BatteryStats { } } out.writeInt(sNumSpeedSteps); final int NU = mUidStats.size(); out.writeInt(NU); for (int iu = 0; iu < NU; iu++) { Loading Loading @@ -9640,16 +9716,28 @@ public final class BatteryStatsImpl extends BatteryStats { u.mSystemCpuTime.writeSummaryFromParcelLocked(out); u.mCpuPower.writeSummaryFromParcelLocked(out); out.writeInt(u.mSpeedBins.length); for (int i = 0; i < u.mSpeedBins.length; i++) { LongSamplingCounter speedBin = u.mSpeedBins[i]; if (speedBin != null) { if (u.mCpuClusterSpeed != null) { out.writeInt(1); speedBin.writeSummaryFromParcelLocked(out); out.writeInt(u.mCpuClusterSpeed.length); for (LongSamplingCounter[] cpuSpeeds : u.mCpuClusterSpeed) { if (cpuSpeeds != null) { out.writeInt(1); out.writeInt(cpuSpeeds.length); for (LongSamplingCounter c : cpuSpeeds) { if (c != null) { out.writeInt(1); c.writeSummaryFromParcelLocked(out); } else { out.writeInt(0); } } } else { out.writeInt(0); } } } else { out.writeInt(0); } final ArrayMap<String, Uid.Wakelock> wakeStats = u.mWakelockStats.getMap(); int NW = wakeStats.size(); Loading Loading @@ -9897,8 +9985,6 @@ public final class BatteryStatsImpl extends BatteryStats { mFlashlightTurnedOnTimers.clear(); mCameraTurnedOnTimers.clear(); sNumSpeedSteps = in.readInt(); int numUids = in.readInt(); mUidStats.clear(); for (int i = 0; i < numUids; i++) { Loading Loading @@ -10037,8 +10123,6 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeInt(0); } out.writeInt(sNumSpeedSteps); if (inclUids) { int size = mUidStats.size(); out.writeInt(size); Loading core/java/com/android/internal/os/CpuPowerCalculator.java +36 −1 Original line number Diff line number Diff line Loading @@ -22,12 +22,47 @@ import android.util.Log; public class CpuPowerCalculator extends PowerCalculator { private static final String TAG = "CpuPowerCalculator"; private static final boolean DEBUG = BatteryStatsHelper.DEBUG; private final PowerProfile mProfile; public CpuPowerCalculator(PowerProfile profile) { mProfile = profile; } @Override public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, long rawUptimeUs, int statsType) { app.cpuTimeMs = (u.getUserCpuTimeUs(statsType) + u.getSystemCpuTimeUs(statsType)) / 1000; app.cpuPowerMah = (double) u.getCpuPowerMaUs(statsType) / (60.0 * 60.0 * 1000.0 * 1000.0); // Aggregate total time spent on each cluster. long totalTime = 0; final int numClusters = mProfile.getNumCpuClusters(); for (int cluster = 0; cluster < numClusters; cluster++) { final int speedsForCluster = mProfile.getNumSpeedStepsInCpuCluster(cluster); for (int speed = 0; speed < speedsForCluster; speed++) { totalTime += u.getTimeAtCpuSpeed(cluster, speed, statsType); } } totalTime = Math.max(totalTime, 1); double cpuPowerMaMs = 0; for (int cluster = 0; cluster < numClusters; cluster++) { final int speedsForCluster = mProfile.getNumSpeedStepsInCpuCluster(cluster); for (int speed = 0; speed < speedsForCluster; speed++) { final double ratio = (double) u.getTimeAtCpuSpeed(cluster, speed, statsType) / totalTime; final double cpuSpeedStepPower = ratio * app.cpuTimeMs * mProfile.getAveragePowerForCpu(cluster, speed); if (DEBUG && ratio != 0) { Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster + " step #" + speed + " ratio=" + BatteryStatsHelper.makemAh(ratio) + " power=" + BatteryStatsHelper.makemAh(cpuSpeedStepPower / (60 * 60 * 1000))); } cpuPowerMaMs += cpuSpeedStepPower; } } app.cpuPowerMah = cpuPowerMaMs / (60 * 60 * 1000); if (DEBUG && (app.cpuTimeMs != 0 || app.cpuPowerMah != 0)) { Log.d(TAG, "UID " + u.getUid() + ": CPU time=" + app.cpuTimeMs + " ms power=" + BatteryStatsHelper.makemAh(app.cpuPowerMah)); Loading core/java/com/android/internal/os/KernelCpuSpeedReader.java +24 −10 Original line number Diff line number Diff line Loading @@ -24,8 +24,8 @@ 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: * Reads CPU time of a specific core 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 * Loading @@ -33,12 +33,20 @@ import java.util.Arrays; */ 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]; private final String mProcFile; private final long[] mLastSpeedTimes; private final long[] mDeltaSpeedTimes; /** * @param cpuNumber The cpu (cpu0, cpu1, etc) whose state to read. */ public KernelCpuSpeedReader(int cpuNumber, int numSpeedSteps) { mProcFile = String.format("/sys/devices/system/cpu/cpu%d/cpufreq/stats/time_in_state", cpuNumber); mLastSpeedTimes = new long[numSpeedSteps]; mDeltaSpeedTimes = new long[numSpeedSteps]; } /** * The returned array is modified in subsequent calls to {@link #readDelta}. Loading @@ -46,7 +54,7 @@ public class KernelCpuSpeedReader { * {@link #readDelta}. */ public long[] readDelta() { try (BufferedReader reader = new BufferedReader(new FileReader(sProcFile))) { try (BufferedReader reader = new BufferedReader(new FileReader(mProcFile))) { TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(' '); String line; int speedIndex = 0; Loading @@ -56,12 +64,18 @@ public class KernelCpuSpeedReader { // The proc file reports time in 1/100 sec, so convert to milliseconds. long time = Long.parseLong(splitter.next()) * 10; if (time < mLastSpeedTimes[speedIndex]) { // The stats reset when the cpu hotplugged. That means that the time // we read is offset from 0, so the time is the delta. mDeltaSpeedTimes[speedIndex] = time; } else { mDeltaSpeedTimes[speedIndex] = time - mLastSpeedTimes[speedIndex]; } mLastSpeedTimes[speedIndex] = time; speedIndex++; } } catch (IOException e) { Slog.e(TAG, "Failed to read cpu-freq", e); Slog.e(TAG, "Failed to read cpu-freq: " + e.getMessage()); Arrays.fill(mDeltaSpeedTimes, 0); } return mDeltaSpeedTimes; Loading Loading
core/java/android/os/BatteryStats.java +6 −7 Original line number Diff line number Diff line Loading @@ -463,13 +463,15 @@ public abstract class BatteryStats implements Parcelable { public abstract long getCpuPowerMaUs(int which); /** * Returns the approximate cpu time (in milliseconds) spent at a certain CPU speed. * Returns the approximate cpu time (in milliseconds) spent at a certain CPU speed for a * given CPU cluster. * @param cluster the index of the CPU cluster. * @param step 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() * @see PowerProfile.getNumCpuClusters() * @see PowerProfile.getNumSpeedStepsInCpuCluster(int) */ @Deprecated public abstract long getTimeAtCpuSpeed(int step, int which); public abstract long getTimeAtCpuSpeed(int cluster, int step, int which); public static abstract class Sensor { /* Loading Loading @@ -2276,9 +2278,6 @@ public abstract class BatteryStats implements Parcelable { public abstract Map<String, ? extends Timer> getKernelWakelockStats(); /** Returns the number of different speeds that the CPU can run at */ public abstract int getCpuSpeedSteps(); public abstract void writeToParcelWithoutUids(Parcel out, int flags); private final static void formatTimeRaw(StringBuilder out, long seconds) { Loading
core/java/com/android/internal/os/BatteryStatsHelper.java +1 −1 Original line number Diff line number Diff line Loading @@ -338,7 +338,7 @@ public final class BatteryStatsHelper { } if (mCpuPowerCalculator == null) { mCpuPowerCalculator = new CpuPowerCalculator(); mCpuPowerCalculator = new CpuPowerCalculator(mPowerProfile); } mCpuPowerCalculator.reset(); Loading
core/java/com/android/internal/os/BatteryStatsImpl.java +159 −75 Original line number Diff line number Diff line Loading @@ -105,7 +105,7 @@ public final class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version private static final int VERSION = 130 + (USE_OLD_HISTORY ? 1000 : 0); private static final int VERSION = 131 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; Loading @@ -118,8 +118,6 @@ public final class BatteryStatsImpl extends BatteryStats { // in to one common name. private static final int MAX_WAKELOCKS_PER_UID = 100; private static int sNumSpeedSteps; private final JournaledFile mFile; public final AtomicFile mCheckinFile; public final AtomicFile mDailyFile; Loading @@ -133,7 +131,7 @@ public final class BatteryStatsImpl extends BatteryStats { private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats(); private final KernelUidCpuTimeReader mKernelUidCpuTimeReader = new KernelUidCpuTimeReader(); private final KernelCpuSpeedReader mKernelCpuSpeedReader = new KernelCpuSpeedReader(); private KernelCpuSpeedReader[] mKernelCpuSpeedReaders; public interface BatteryCallback { public void batteryNeedsCpuUpdate(); Loading Loading @@ -4411,7 +4409,7 @@ public final class BatteryStatsImpl extends BatteryStats { LongSamplingCounter mUserCpuTime = new LongSamplingCounter(mOnBatteryTimeBase); LongSamplingCounter mSystemCpuTime = new LongSamplingCounter(mOnBatteryTimeBase); LongSamplingCounter mCpuPower = new LongSamplingCounter(mOnBatteryTimeBase); LongSamplingCounter[] mSpeedBins; LongSamplingCounter[][] mCpuClusterSpeed; /** * The statistics we have collected for this uid's wake locks. Loading Loading @@ -4470,7 +4468,6 @@ 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 Loading Loading @@ -5008,10 +5005,18 @@ public final class BatteryStatsImpl extends BatteryStats { } @Override public long getTimeAtCpuSpeed(int step, int which) { if (step >= 0 && step < mSpeedBins.length) { if (mSpeedBins[step] != null) { return mSpeedBins[step].getCountLocked(which); public long getTimeAtCpuSpeed(int cluster, int step, int which) { if (mCpuClusterSpeed != null) { if (cluster >= 0 && cluster < mCpuClusterSpeed.length) { final LongSamplingCounter[] cpuSpeeds = mCpuClusterSpeed[cluster]; if (cpuSpeeds != null) { if (step >= 0 && step < cpuSpeeds.length) { final LongSamplingCounter c = cpuSpeeds[step]; if (c != null) { return c.getCountLocked(which); } } } } } return 0; Loading Loading @@ -5128,10 +5133,16 @@ public final class BatteryStatsImpl extends BatteryStats { mUserCpuTime.reset(false); mSystemCpuTime.reset(false); mCpuPower.reset(false); for (int i = 0; i < mSpeedBins.length; i++) { LongSamplingCounter c = mSpeedBins[i]; if (c != null) { c.reset(false); if (mCpuClusterSpeed != null) { for (LongSamplingCounter[] speeds : mCpuClusterSpeed) { if (speeds != null) { for (LongSamplingCounter speed : speeds) { if (speed != null) { speed.reset(false); } } } } } Loading Loading @@ -5280,13 +5291,19 @@ public final class BatteryStatsImpl extends BatteryStats { mUserCpuTime.detach(); mSystemCpuTime.detach(); mCpuPower.detach(); for (int i = 0; i < mSpeedBins.length; i++) { LongSamplingCounter c = mSpeedBins[i]; if (mCpuClusterSpeed != null) { for (LongSamplingCounter[] cpuSpeeds : mCpuClusterSpeed) { if (cpuSpeeds != null) { for (LongSamplingCounter c : cpuSpeeds) { if (c != null) { c.detach(); } } } } } } return !active; } Loading Loading @@ -5461,9 +5478,14 @@ public final class BatteryStatsImpl extends BatteryStats { mSystemCpuTime.writeToParcel(out); mCpuPower.writeToParcel(out); out.writeInt(mSpeedBins.length); for (int i = 0; i < mSpeedBins.length; i++) { LongSamplingCounter c = mSpeedBins[i]; if (mCpuClusterSpeed != null) { out.writeInt(1); out.writeInt(mCpuClusterSpeed.length); for (LongSamplingCounter[] cpuSpeeds : mCpuClusterSpeed) { if (cpuSpeeds != null) { out.writeInt(1); out.writeInt(cpuSpeeds.length); for (LongSamplingCounter c : cpuSpeeds) { if (c != null) { out.writeInt(1); c.writeToParcel(out); Loading @@ -5471,6 +5493,13 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeInt(0); } } } else { out.writeInt(0); } } } else { out.writeInt(0); } } void readFromParcelLocked(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) { Loading Loading @@ -5653,13 +5682,32 @@ public final class BatteryStatsImpl extends BatteryStats { mSystemCpuTime = new LongSamplingCounter(mOnBatteryTimeBase, in); mCpuPower = 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); int numCpuClusters = in.readInt(); if (mPowerProfile != null && mPowerProfile.getNumCpuClusters() != numCpuClusters) { throw new ParcelFormatException("Incompatible number of cpu clusters"); } mCpuClusterSpeed = new LongSamplingCounter[numCpuClusters][]; for (int cluster = 0; cluster < numCpuClusters; cluster++) { if (in.readInt() != 0) { int numSpeeds = in.readInt(); if (mPowerProfile != null && mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != numSpeeds) { throw new ParcelFormatException("Incompatible number of cpu speeds"); } final LongSamplingCounter[] cpuSpeeds = new LongSamplingCounter[numSpeeds]; mCpuClusterSpeed[cluster] = cpuSpeeds; for (int speed = 0; speed < numSpeeds; speed++) { if (in.readInt() != 0) { cpuSpeeds[speed] = new LongSamplingCounter(mOnBatteryTimeBase, in); } } } } } else { mCpuClusterSpeed = null; } } Loading Loading @@ -6874,6 +6922,19 @@ public final class BatteryStatsImpl extends BatteryStats { public void setPowerProfile(PowerProfile profile) { synchronized (this) { mPowerProfile = profile; // We need to initialize the KernelCpuSpeedReaders to read from // the first cpu of each core. Once we have the PowerProfile, we have access to this // information. final int numClusters = mPowerProfile.getNumCpuClusters(); mKernelCpuSpeedReaders = new KernelCpuSpeedReader[numClusters]; int firstCpuOfCluster = 0; for (int i = 0; i < numClusters; i++) { final int numSpeedSteps = mPowerProfile.getNumSpeedStepsInCpuCluster(i); mKernelCpuSpeedReaders[i] = new KernelCpuSpeedReader(firstCpuOfCluster, numSpeedSteps); firstCpuOfCluster += mPowerProfile.getNumCoresInCpuCluster(i); } } } Loading @@ -6881,10 +6942,6 @@ public final class BatteryStatsImpl extends BatteryStats { mCallback = cb; } public void setNumSpeedSteps(int steps) { if (sNumSpeedSteps == 0) sNumSpeedSteps = steps; } public void setRadioScanningTimeout(long timeout) { if (mPhoneSignalScanningTimer != null) { mPhoneSignalScanningTimer.setTimeout(timeout); Loading Loading @@ -7997,9 +8054,11 @@ public final class BatteryStatsImpl extends BatteryStats { // If no app is holding a wakelock, then the distribution is normal. final int wakelockWeight = 50; // Read the time spent at various cpu frequencies. final int cpuSpeedSteps = getCpuSpeedSteps(); final long[] cpuSpeeds = mKernelCpuSpeedReader.readDelta(); // Read the time spent for each cluster at various cpu frequencies. final long[][] clusterSpeeds = new long[mKernelCpuSpeedReaders.length][]; for (int cluster = 0; cluster < mKernelCpuSpeedReaders.length; cluster++) { clusterSpeeds[cluster] = mKernelCpuSpeedReaders[cluster].readDelta(); } int numWakelocks = 0; Loading Loading @@ -8072,11 +8131,23 @@ public final class BatteryStatsImpl extends BatteryStats { // Add the cpu speeds to this UID. These are used as a ratio // for computing the power this UID used. for (int i = 0; i < cpuSpeedSteps; i++) { if (u.mSpeedBins[i] == null) { u.mSpeedBins[i] = new LongSamplingCounter(mOnBatteryTimeBase); if (u.mCpuClusterSpeed == null) { u.mCpuClusterSpeed = new LongSamplingCounter[clusterSpeeds.length][]; } for (int cluster = 0; cluster < clusterSpeeds.length; cluster++) { if (u.mCpuClusterSpeed[cluster] == null) { u.mCpuClusterSpeed[cluster] = new LongSamplingCounter[clusterSpeeds[cluster].length]; } final LongSamplingCounter[] cpuSpeeds = u.mCpuClusterSpeed[cluster]; for (int speed = 0; speed < clusterSpeeds[cluster].length; speed++) { if (cpuSpeeds[speed] == null) { cpuSpeeds[speed] = new LongSamplingCounter(mOnBatteryTimeBase); } cpuSpeeds[speed].addCountLocked(clusterSpeeds[cluster][speed]); } u.mSpeedBins[i].addCountLocked(cpuSpeeds[i]); } } }); Loading Loading @@ -8776,11 +8847,6 @@ public final class BatteryStatsImpl extends BatteryStats { } } @Override public int getCpuSpeedSteps() { return sNumSpeedSteps; } /** * Retrieve the statistics object for a particular uid, creating if needed. */ Loading Loading @@ -9216,11 +9282,6 @@ public final class BatteryStatsImpl extends BatteryStats { } } sNumSpeedSteps = in.readInt(); if (sNumSpeedSteps < 0 || sNumSpeedSteps > 100) { throw new ParcelFormatException("Bad speed steps in data: " + sNumSpeedSteps); } final int NU = in.readInt(); if (NU > 10000) { throw new ParcelFormatException("File corrupt: too many uids " + NU); Loading Loading @@ -9304,18 +9365,34 @@ public final class BatteryStatsImpl extends BatteryStats { u.mSystemCpuTime.readSummaryFromParcelLocked(in); u.mCpuPower.readSummaryFromParcelLocked(in); if (in.readInt() != 0) { final int numClusters = in.readInt(); if (mPowerProfile != null && mPowerProfile.getNumCpuClusters() != numClusters) { throw new ParcelFormatException("Incompatible cpu cluster arrangement"); } u.mCpuClusterSpeed = new LongSamplingCounter[numClusters][]; for (int cluster = 0; cluster < numClusters; cluster++) { int NSB = in.readInt(); if (NSB > 100) { if (mPowerProfile != null && mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != NSB) { throw new ParcelFormatException("File corrupt: too many speed bins " + NSB); } 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); u.mCpuClusterSpeed[cluster] = new LongSamplingCounter[NSB]; for (int speed = 0; speed < NSB; speed++) { if (in.readInt() != 0) { u.mCpuClusterSpeed[cluster][speed] = new LongSamplingCounter( mOnBatteryTimeBase); u.mCpuClusterSpeed[cluster][speed].readSummaryFromParcelLocked(in); } } } } } else { u.mCpuClusterSpeed = null; } int NW = in.readInt(); if (NW > 100) { Loading Loading @@ -9531,7 +9608,6 @@ public final class BatteryStatsImpl extends BatteryStats { } } out.writeInt(sNumSpeedSteps); final int NU = mUidStats.size(); out.writeInt(NU); for (int iu = 0; iu < NU; iu++) { Loading Loading @@ -9640,16 +9716,28 @@ public final class BatteryStatsImpl extends BatteryStats { u.mSystemCpuTime.writeSummaryFromParcelLocked(out); u.mCpuPower.writeSummaryFromParcelLocked(out); out.writeInt(u.mSpeedBins.length); for (int i = 0; i < u.mSpeedBins.length; i++) { LongSamplingCounter speedBin = u.mSpeedBins[i]; if (speedBin != null) { if (u.mCpuClusterSpeed != null) { out.writeInt(1); speedBin.writeSummaryFromParcelLocked(out); out.writeInt(u.mCpuClusterSpeed.length); for (LongSamplingCounter[] cpuSpeeds : u.mCpuClusterSpeed) { if (cpuSpeeds != null) { out.writeInt(1); out.writeInt(cpuSpeeds.length); for (LongSamplingCounter c : cpuSpeeds) { if (c != null) { out.writeInt(1); c.writeSummaryFromParcelLocked(out); } else { out.writeInt(0); } } } else { out.writeInt(0); } } } else { out.writeInt(0); } final ArrayMap<String, Uid.Wakelock> wakeStats = u.mWakelockStats.getMap(); int NW = wakeStats.size(); Loading Loading @@ -9897,8 +9985,6 @@ public final class BatteryStatsImpl extends BatteryStats { mFlashlightTurnedOnTimers.clear(); mCameraTurnedOnTimers.clear(); sNumSpeedSteps = in.readInt(); int numUids = in.readInt(); mUidStats.clear(); for (int i = 0; i < numUids; i++) { Loading Loading @@ -10037,8 +10123,6 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeInt(0); } out.writeInt(sNumSpeedSteps); if (inclUids) { int size = mUidStats.size(); out.writeInt(size); Loading
core/java/com/android/internal/os/CpuPowerCalculator.java +36 −1 Original line number Diff line number Diff line Loading @@ -22,12 +22,47 @@ import android.util.Log; public class CpuPowerCalculator extends PowerCalculator { private static final String TAG = "CpuPowerCalculator"; private static final boolean DEBUG = BatteryStatsHelper.DEBUG; private final PowerProfile mProfile; public CpuPowerCalculator(PowerProfile profile) { mProfile = profile; } @Override public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, long rawUptimeUs, int statsType) { app.cpuTimeMs = (u.getUserCpuTimeUs(statsType) + u.getSystemCpuTimeUs(statsType)) / 1000; app.cpuPowerMah = (double) u.getCpuPowerMaUs(statsType) / (60.0 * 60.0 * 1000.0 * 1000.0); // Aggregate total time spent on each cluster. long totalTime = 0; final int numClusters = mProfile.getNumCpuClusters(); for (int cluster = 0; cluster < numClusters; cluster++) { final int speedsForCluster = mProfile.getNumSpeedStepsInCpuCluster(cluster); for (int speed = 0; speed < speedsForCluster; speed++) { totalTime += u.getTimeAtCpuSpeed(cluster, speed, statsType); } } totalTime = Math.max(totalTime, 1); double cpuPowerMaMs = 0; for (int cluster = 0; cluster < numClusters; cluster++) { final int speedsForCluster = mProfile.getNumSpeedStepsInCpuCluster(cluster); for (int speed = 0; speed < speedsForCluster; speed++) { final double ratio = (double) u.getTimeAtCpuSpeed(cluster, speed, statsType) / totalTime; final double cpuSpeedStepPower = ratio * app.cpuTimeMs * mProfile.getAveragePowerForCpu(cluster, speed); if (DEBUG && ratio != 0) { Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster + " step #" + speed + " ratio=" + BatteryStatsHelper.makemAh(ratio) + " power=" + BatteryStatsHelper.makemAh(cpuSpeedStepPower / (60 * 60 * 1000))); } cpuPowerMaMs += cpuSpeedStepPower; } } app.cpuPowerMah = cpuPowerMaMs / (60 * 60 * 1000); if (DEBUG && (app.cpuTimeMs != 0 || app.cpuPowerMah != 0)) { Log.d(TAG, "UID " + u.getUid() + ": CPU time=" + app.cpuTimeMs + " ms power=" + BatteryStatsHelper.makemAh(app.cpuPowerMah)); Loading
core/java/com/android/internal/os/KernelCpuSpeedReader.java +24 −10 Original line number Diff line number Diff line Loading @@ -24,8 +24,8 @@ 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: * Reads CPU time of a specific core 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 * Loading @@ -33,12 +33,20 @@ import java.util.Arrays; */ 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]; private final String mProcFile; private final long[] mLastSpeedTimes; private final long[] mDeltaSpeedTimes; /** * @param cpuNumber The cpu (cpu0, cpu1, etc) whose state to read. */ public KernelCpuSpeedReader(int cpuNumber, int numSpeedSteps) { mProcFile = String.format("/sys/devices/system/cpu/cpu%d/cpufreq/stats/time_in_state", cpuNumber); mLastSpeedTimes = new long[numSpeedSteps]; mDeltaSpeedTimes = new long[numSpeedSteps]; } /** * The returned array is modified in subsequent calls to {@link #readDelta}. Loading @@ -46,7 +54,7 @@ public class KernelCpuSpeedReader { * {@link #readDelta}. */ public long[] readDelta() { try (BufferedReader reader = new BufferedReader(new FileReader(sProcFile))) { try (BufferedReader reader = new BufferedReader(new FileReader(mProcFile))) { TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(' '); String line; int speedIndex = 0; Loading @@ -56,12 +64,18 @@ public class KernelCpuSpeedReader { // The proc file reports time in 1/100 sec, so convert to milliseconds. long time = Long.parseLong(splitter.next()) * 10; if (time < mLastSpeedTimes[speedIndex]) { // The stats reset when the cpu hotplugged. That means that the time // we read is offset from 0, so the time is the delta. mDeltaSpeedTimes[speedIndex] = time; } else { mDeltaSpeedTimes[speedIndex] = time - mLastSpeedTimes[speedIndex]; } mLastSpeedTimes[speedIndex] = time; speedIndex++; } } catch (IOException e) { Slog.e(TAG, "Failed to read cpu-freq", e); Slog.e(TAG, "Failed to read cpu-freq: " + e.getMessage()); Arrays.fill(mDeltaSpeedTimes, 0); } return mDeltaSpeedTimes; Loading