Merge "BatteryStats: Better big-little CPU accounting" into mnc-dr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
680553957e
@@ -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 {
|
||||
/*
|
||||
@@ -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) {
|
||||
|
||||
@@ -338,7 +338,7 @@ public final class BatteryStatsHelper {
|
||||
}
|
||||
|
||||
if (mCpuPowerCalculator == null) {
|
||||
mCpuPowerCalculator = new CpuPowerCalculator();
|
||||
mCpuPowerCalculator = new CpuPowerCalculator(mPowerProfile);
|
||||
}
|
||||
mCpuPowerCalculator.reset();
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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();
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5280,10 +5291,16 @@ 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 (c != null) {
|
||||
c.detach();
|
||||
|
||||
if (mCpuClusterSpeed != null) {
|
||||
for (LongSamplingCounter[] cpuSpeeds : mCpuClusterSpeed) {
|
||||
if (cpuSpeeds != null) {
|
||||
for (LongSamplingCounter c : cpuSpeeds) {
|
||||
if (c != null) {
|
||||
c.detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5461,15 +5478,27 @@ 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 (c != null) {
|
||||
out.writeInt(1);
|
||||
c.writeToParcel(out);
|
||||
} else {
|
||||
out.writeInt(0);
|
||||
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);
|
||||
} else {
|
||||
out.writeInt(0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.writeInt(0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.writeInt(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
if (in.readInt() != 0) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -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.
|
||||
*/
|
||||
@@ -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);
|
||||
@@ -9304,17 +9365,33 @@ public final class BatteryStatsImpl extends BatteryStats {
|
||||
u.mSystemCpuTime.readSummaryFromParcelLocked(in);
|
||||
u.mCpuPower.readSummaryFromParcelLocked(in);
|
||||
|
||||
int NSB = in.readInt();
|
||||
if (NSB > 100) {
|
||||
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);
|
||||
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 (mPowerProfile != null &&
|
||||
mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != NSB) {
|
||||
throw new ParcelFormatException("File corrupt: too many speed bins " + NSB);
|
||||
}
|
||||
|
||||
if (in.readInt() != 0) {
|
||||
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();
|
||||
@@ -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++) {
|
||||
@@ -9640,15 +9716,27 @@ 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) {
|
||||
out.writeInt(1);
|
||||
speedBin.writeSummaryFromParcelLocked(out);
|
||||
} else {
|
||||
out.writeInt(0);
|
||||
if (u.mCpuClusterSpeed != null) {
|
||||
out.writeInt(1);
|
||||
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();
|
||||
@@ -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++) {
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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
|
||||
*
|
||||
@@ -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}.
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
mDeltaSpeedTimes[speedIndex] = time - mLastSpeedTimes[speedIndex];
|
||||
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;
|
||||
|
||||
@@ -59,6 +59,7 @@ public class PowerProfile {
|
||||
/**
|
||||
* Power consumption when CPU is in power collapse mode.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String POWER_CPU_ACTIVE = "cpu.active";
|
||||
|
||||
/**
|
||||
@@ -163,6 +164,7 @@ public class PowerProfile {
|
||||
*/
|
||||
public static final String POWER_CAMERA = "camera.avg";
|
||||
|
||||
@Deprecated
|
||||
public static final String POWER_CPU_SPEEDS = "cpu.speeds";
|
||||
|
||||
/**
|
||||
@@ -191,6 +193,7 @@ public class PowerProfile {
|
||||
if (sPowerMap.size() == 0) {
|
||||
readPowerValuesFromXml(context);
|
||||
}
|
||||
initCpuClusters();
|
||||
}
|
||||
|
||||
private void readPowerValuesFromXml(Context context) {
|
||||
@@ -249,7 +252,7 @@ public class PowerProfile {
|
||||
}
|
||||
|
||||
// Now collect other config variables.
|
||||
int[] configResIds = new int[] {
|
||||
int[] configResIds = new int[]{
|
||||
com.android.internal.R.integer.config_bluetooth_idle_cur_ma,
|
||||
com.android.internal.R.integer.config_bluetooth_rx_cur_ma,
|
||||
com.android.internal.R.integer.config_bluetooth_tx_cur_ma,
|
||||
@@ -260,7 +263,7 @@ public class PowerProfile {
|
||||
com.android.internal.R.integer.config_wifi_operating_voltage_mv,
|
||||
};
|
||||
|
||||
String[] configResIdKeys = new String[] {
|
||||
String[] configResIdKeys = new String[]{
|
||||
POWER_BLUETOOTH_CONTROLLER_IDLE,
|
||||
POWER_BLUETOOTH_CONTROLLER_RX,
|
||||
POWER_BLUETOOTH_CONTROLLER_TX,
|
||||
@@ -279,6 +282,69 @@ public class PowerProfile {
|
||||
}
|
||||
}
|
||||
|
||||
private CpuClusterKey[] mCpuClusters;
|
||||
|
||||
private static final String POWER_CPU_CLUSTER_CORE_COUNT = "cpu.clusters.cores";
|
||||
private static final String POWER_CPU_CLUSTER_SPEED_PREFIX = "cpu.speeds.cluster";
|
||||
private static final String POWER_CPU_CLUSTER_ACTIVE_PREFIX = "cpu.active.cluster";
|
||||
|
||||
@SuppressWarnings("deprecated")
|
||||
private void initCpuClusters() {
|
||||
// Figure out how many CPU clusters we're dealing with
|
||||
final Object obj = sPowerMap.get(POWER_CPU_CLUSTER_CORE_COUNT);
|
||||
if (obj == null || !(obj instanceof Double[])) {
|
||||
// Default to single.
|
||||
mCpuClusters = new CpuClusterKey[1];
|
||||
mCpuClusters[0] = new CpuClusterKey(POWER_CPU_SPEEDS, POWER_CPU_ACTIVE, 1);
|
||||
|
||||
} else {
|
||||
final Double[] array = (Double[]) obj;
|
||||
mCpuClusters = new CpuClusterKey[array.length];
|
||||
for (int cluster = 0; cluster < array.length; cluster++) {
|
||||
int numCpusInCluster = (int) Math.round(array[cluster]);
|
||||
mCpuClusters[cluster] = new CpuClusterKey(
|
||||
POWER_CPU_CLUSTER_SPEED_PREFIX + cluster,
|
||||
POWER_CPU_CLUSTER_ACTIVE_PREFIX + cluster,
|
||||
numCpusInCluster);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class CpuClusterKey {
|
||||
private final String timeKey;
|
||||
private final String powerKey;
|
||||
private final int numCpus;
|
||||
|
||||
private CpuClusterKey(String timeKey, String powerKey, int numCpus) {
|
||||
this.timeKey = timeKey;
|
||||
this.powerKey = powerKey;
|
||||
this.numCpus = numCpus;
|
||||
}
|
||||
}
|
||||
|
||||
public int getNumCpuClusters() {
|
||||
return mCpuClusters.length;
|
||||
}
|
||||
|
||||
public int getNumCoresInCpuCluster(int index) {
|
||||
return mCpuClusters[index].numCpus;
|
||||
}
|
||||
|
||||
public int getNumSpeedStepsInCpuCluster(int index) {
|
||||
Object value = sPowerMap.get(mCpuClusters[index].timeKey);
|
||||
if (value != null && value instanceof Double[]) {
|
||||
return ((Double[])value).length;
|
||||
}
|
||||
return 1; // Only one speed
|
||||
}
|
||||
|
||||
public double getAveragePowerForCpu(int cluster, int step) {
|
||||
if (cluster >= 0 && cluster < mCpuClusters.length) {
|
||||
return getAveragePower(mCpuClusters[cluster].powerKey, step);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the average current in mA consumed by the subsystem, or the given
|
||||
* default value if the subsystem has no recorded value.
|
||||
@@ -344,16 +410,4 @@ public class PowerProfile {
|
||||
public double getBatteryCapacity() {
|
||||
return getAveragePower(POWER_BATTERY_CAPACITY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of speeds that the CPU can be run at.
|
||||
* @return
|
||||
*/
|
||||
public int getNumSpeedSteps() {
|
||||
Object value = sPowerMap.get(POWER_CPU_SPEEDS);
|
||||
if (value != null && value instanceof Double[]) {
|
||||
return ((Double[])value).length;
|
||||
}
|
||||
return 1; // Only one speed
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,17 +47,38 @@
|
||||
<value>0.2</value> <!-- ~2mA -->
|
||||
<value>0.1</value> <!-- ~1mA -->
|
||||
</array>
|
||||
<!-- Different CPU speeds as reported in
|
||||
/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state -->
|
||||
<array name="cpu.speeds">
|
||||
|
||||
<!-- A list of heterogeneous CPU clusters, where the value for each cluster represents the
|
||||
number of CPU cores for that cluster.
|
||||
|
||||
Ex:
|
||||
<array name="cpu.clusters.cores">
|
||||
<value>4</value> // cluster 0 has cpu0, cpu1, cpu2, cpu3
|
||||
<value>2</value> // cluster 1 has cpu4, cpu5
|
||||
</array> -->
|
||||
<array name="cpu.clusters.cores">
|
||||
<value>1</value> <!-- cluster 0 has cpu0 -->
|
||||
</array>
|
||||
|
||||
<!-- Different CPU speeds for cluster 0 as reported in
|
||||
/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state.
|
||||
|
||||
There must be one of these for each cluster, labeled:
|
||||
cpu.speeds.cluster0, cpu.speeds.cluster1, etc... -->
|
||||
<array name="cpu.speeds.cluster0">
|
||||
<value>400000</value> <!-- 400 MHz CPU speed -->
|
||||
</array>
|
||||
<!-- Current when CPU is idle -->
|
||||
<item name="cpu.idle">0.1</item>
|
||||
<!-- Current at each CPU speed, as per 'cpu.speeds' -->
|
||||
<array name="cpu.active">
|
||||
|
||||
<!-- Current at each CPU speed for cluster 0, as per 'cpu.speeds.cluster0'.
|
||||
Like cpu.speeds.cluster0, there must be one of these present for
|
||||
each heterogeneous CPU cluster. -->
|
||||
<array name="cpu.active.cluster0">
|
||||
<value>0.1</value> <!-- ~100mA -->
|
||||
</array>
|
||||
|
||||
<!-- Current when CPU is idle -->
|
||||
<item name="cpu.idle">0.1</item>
|
||||
|
||||
<!-- This is the battery capacity in mAh (measured at nominal voltage) -->
|
||||
<item name="battery.capacity">1000</item>
|
||||
|
||||
|
||||
@@ -171,12 +171,11 @@ public final class BatteryStatsService extends IBatteryStats.Stub
|
||||
|
||||
public void publish(Context context) {
|
||||
mContext = context;
|
||||
ServiceManager.addService(BatteryStats.SERVICE_NAME, asBinder());
|
||||
mStats.setNumSpeedSteps(new PowerProfile(mContext).getNumSpeedSteps());
|
||||
mStats.setRadioScanningTimeout(mContext.getResources().getInteger(
|
||||
com.android.internal.R.integer.config_radioScanningTimeout)
|
||||
* 1000L);
|
||||
mStats.setPowerProfile(new PowerProfile(context));
|
||||
ServiceManager.addService(BatteryStats.SERVICE_NAME, asBinder());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user