summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java254
-rw-r--r--core/java/com/android/internal/power/MeasuredEnergyStats.java4
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java32
-rw-r--r--core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java2
-rw-r--r--core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java2
-rw-r--r--services/core/java/com/android/server/am/BatteryExternalStatsWorker.java12
-rw-r--r--services/core/java/com/android/server/am/MeasuredEnergySnapshot.java29
7 files changed, 287 insertions, 48 deletions
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 73527d4a80d8..8c0ce6b54283 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -169,7 +169,7 @@ public class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- static final int VERSION = 193;
+ static final int VERSION = 194;
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
@@ -1009,6 +1009,8 @@ public class BatteryStatsImpl extends BatteryStats {
protected @Nullable MeasuredEnergyStats mGlobalMeasuredEnergyStats;
/** Last known screen state. Needed for apportioning display energy. */
int mScreenStateAtLastEnergyMeasurement = Display.STATE_UNKNOWN;
+ /** Cpu Power calculator for attributing measured cpu energy to uids */
+ @Nullable CpuPowerCalculator mCpuPowerCalculator = null;
/**
* These provide time bases that discount the time the device is plugged
@@ -12170,6 +12172,84 @@ public class BatteryStatsImpl extends BatteryStats {
}
/**
+ * Accumulate Cpu energy and distribute it to the correct state and the apps.
+ * Only call if device is on battery.
+ *
+ * @param clusterEnergiesUJ amount of energy (microjoules) used by each Cpu Cluster
+ * @param accumulator collection of calculated uid cpu power consumption to smear
+ * clusterEnergiesUJ against.
+ */
+ @GuardedBy("this")
+ private void updateCpuEnergyLocked(@NonNull long[] clusterEnergiesUJ,
+ @NonNull CpuDeltaPowerAccumulator accumulator) {
+ if (DEBUG_ENERGY) {
+ Slog.d(TAG,
+ "Updating cpu cluster stats: " + clusterEnergiesUJ.toString());
+ }
+ if (mGlobalMeasuredEnergyStats == null) {
+ return;
+ }
+
+ final int numClusters = clusterEnergiesUJ.length;
+ long totalCpuEnergyUJ = 0;
+ for (int i = 0; i < numClusters; i++) {
+ totalCpuEnergyUJ += clusterEnergiesUJ[i];
+ }
+ if (totalCpuEnergyUJ <= 0) return;
+
+ mGlobalMeasuredEnergyStats.updateStandardBucket(MeasuredEnergyStats.ENERGY_BUCKET_CPU,
+ totalCpuEnergyUJ);
+
+ // Calculate the measured energy/calculated charge ratio for each cluster to normalize
+ // each uid's estimated power usage against actual power usage for a given cluster.
+ final double[] clusterEnergyChargeRatio = new double[numClusters];
+ for (int cluster = 0; cluster < numClusters; cluster++) {
+ final double totalClusterChargeMah = accumulator.totalClusterChargesMah[cluster];
+ if (totalClusterChargeMah <= 0.0) {
+ // This cluster did not have any work on it, since last update.
+ // Avoid dividing by zero.
+ clusterEnergyChargeRatio[cluster] = 0.0;
+ } else {
+ clusterEnergyChargeRatio[cluster] =
+ clusterEnergiesUJ[cluster] / accumulator.totalClusterChargesMah[cluster];
+ }
+ }
+
+ // Assign and distribute power usage to apps based on their calculated cpu cluster charge.
+ final long uidChargeArraySize = accumulator.perUidCpuClusterChargesMah.size();
+ for (int i = 0; i < uidChargeArraySize; i++) {
+ final Uid uid = accumulator.perUidCpuClusterChargesMah.keyAt(i);
+ final double[] uidClusterChargesMah = accumulator.perUidCpuClusterChargesMah.valueAt(i);
+
+ // Iterate each cpu cluster and sum the proportional measured cpu cluster energy to
+ // get the total cpu energy used by a uid.
+ long uidCpuEnergyUJ = 0;
+ for (int cluster = 0; cluster < numClusters; cluster++) {
+ final double uidClusterChargeMah = uidClusterChargesMah[cluster];
+
+ // Proportionally allocate the measured cpu cluster energy to a uid using the
+ // measured energy/calculated charge ratio. Add 0.5 to round the proportional
+ // energy double to the nearest long value.
+ final long uidClusterEnergyUJ =
+ (long) (uidClusterChargeMah * clusterEnergyChargeRatio[cluster]
+ + 0.5);
+
+ uidCpuEnergyUJ += uidClusterEnergyUJ;
+ }
+
+ if (uidCpuEnergyUJ < 0) {
+ Slog.wtf(TAG,
+ "Unexpected proportional measured energy (" + uidCpuEnergyUJ + ") for uid "
+ + uid.mUid);
+ continue;
+ }
+
+ uid.addEnergyToStandardBucketLocked(uidCpuEnergyUJ,
+ MeasuredEnergyStats.ENERGY_BUCKET_CPU);
+ }
+ }
+
+ /**
* Accumulate Display energy and distribute it to the correct state and the apps.
*
* NOTE: The algorithm used makes the strong assumption that app foreground activity time
@@ -12416,6 +12496,64 @@ public class BatteryStatsImpl extends BatteryStats {
}
/**
+ * Object for calculating and accumulating the estimated cpu power used while reading the
+ * various cpu kernel files.
+ */
+ @VisibleForTesting
+ public static class CpuDeltaPowerAccumulator {
+ // Keeps track of total charge used per cluster.
+ public final double[] totalClusterChargesMah;
+ // Keeps track of charge used per cluster per uid.
+ public final ArrayMap<Uid, double[]> perUidCpuClusterChargesMah;
+
+ private final CpuPowerCalculator mCalculator;
+ private Uid mCachedUid = null;
+ private double[] mUidClusterCache = null;
+
+ CpuDeltaPowerAccumulator(CpuPowerCalculator calculator, int nClusters) {
+ mCalculator = calculator;
+ totalClusterChargesMah = new double[nClusters];
+ perUidCpuClusterChargesMah = new ArrayMap<>();
+ }
+
+ /** Add per cpu cluster durations to the currently cached uid. */
+ public void addCpuClusterDurationsMs(Uid uid, long[] durationsMs) {
+ final double[] uidChargesMah = getOrCreateUidCpuClusterCharges(uid);
+ for (int cluster = 0; cluster < durationsMs.length; cluster++) {
+ final double estimatedDeltaMah = mCalculator.calculatePerCpuClusterPowerMah(cluster,
+ durationsMs[cluster]);
+ uidChargesMah[cluster] += estimatedDeltaMah;
+ totalClusterChargesMah[cluster] += estimatedDeltaMah;
+ }
+ }
+
+ /** Add per speed per cpu cluster durations to the currently cached uid. */
+ public void addCpuClusterSpeedDurationsMs(Uid uid, int cluster, int speed,
+ long durationsMs) {
+ final double[] uidChargesMah = getOrCreateUidCpuClusterCharges(uid);
+ final double estimatedDeltaMah = mCalculator.calculatePerCpuFreqPowerMah(cluster, speed,
+ durationsMs);
+ uidChargesMah[cluster] += estimatedDeltaMah;
+ totalClusterChargesMah[cluster] += estimatedDeltaMah;
+ }
+
+ private double[] getOrCreateUidCpuClusterCharges(Uid uid) {
+ // Repeated additions on the same uid is very likely.
+ // Skip a lookup if getting the same uid as the last get.
+ if (uid == mCachedUid) return mUidClusterCache;
+
+ double[] uidChargesMah = perUidCpuClusterChargesMah.get(uid);
+ if (uidChargesMah == null) {
+ uidChargesMah = new double[totalClusterChargesMah.length];
+ perUidCpuClusterChargesMah.put(uid, uidChargesMah);
+ }
+ mCachedUid = uid;
+ mUidClusterCache = uidChargesMah;
+ return uidChargesMah;
+ }
+ }
+
+ /**
* Read and distribute CPU usage across apps. If their are partial wakelocks being held
* and we are on battery with screen off, we give more of the cpu time to those apps holding
* wakelocks. If the screen is on, we just assign the actual cpu time an app used.
@@ -12424,7 +12562,8 @@ public class BatteryStatsImpl extends BatteryStats {
* buckets.
*/
@GuardedBy("this")
- public void updateCpuTimeLocked(boolean onBattery, boolean onBatteryScreenOff) {
+ public void updateCpuTimeLocked(boolean onBattery, boolean onBatteryScreenOff,
+ long[] measuredCpuClusterEnergiesUJ) {
if (mPowerProfile == null) {
return;
}
@@ -12478,21 +12617,48 @@ public class BatteryStatsImpl extends BatteryStats {
mUserInfoProvider.refreshUserIds();
final SparseLongArray updatedUids = mCpuUidFreqTimeReader.perClusterTimesAvailable()
? null : new SparseLongArray();
+
+ final CpuDeltaPowerAccumulator powerAccumulator;
+ if (mGlobalMeasuredEnergyStats != null
+ && mGlobalMeasuredEnergyStats.isStandardBucketSupported(
+ MeasuredEnergyStats.ENERGY_BUCKET_CPU) && mCpuPowerCalculator != null) {
+ if (measuredCpuClusterEnergiesUJ == null) {
+ Slog.wtf(TAG,
+ "ENERGY_BUCKET_CPU supported but no measured Cpu Cluster energy reported "
+ + "on updateCpuTimeLocked!");
+ powerAccumulator = null;
+ } else {
+ // Cpu Measured Energy is supported, create an object to accumulate the estimated
+ // energy consumption since the last cpu update
+ final int numClusters = mPowerProfile.getNumCpuClusters();
+ powerAccumulator = new CpuDeltaPowerAccumulator(mCpuPowerCalculator, numClusters);
+ }
+ } else {
+ powerAccumulator = null;
+ }
+
readKernelUidCpuTimesLocked(partialTimersToConsider, updatedUids, onBattery);
// updatedUids=null means /proc/uid_time_in_state provides snapshots of per-cluster cpu
// freqs, so no need to approximate these values.
if (updatedUids != null) {
- updateClusterSpeedTimes(updatedUids, onBattery);
+ updateClusterSpeedTimes(updatedUids, onBattery, powerAccumulator);
}
- readKernelUidCpuFreqTimesLocked(partialTimersToConsider, onBattery, onBatteryScreenOff);
+ readKernelUidCpuFreqTimesLocked(partialTimersToConsider, onBattery, onBatteryScreenOff,
+ powerAccumulator);
mNumAllUidCpuTimeReads += 2;
if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) {
+ // Cpu Active times do not get any info ony how to attribute measured Cpu Cluster
+ // energy, so not need to provide the powerAccumulator
readKernelUidCpuActiveTimesLocked(onBattery);
- readKernelUidCpuClusterTimesLocked(onBattery);
+ readKernelUidCpuClusterTimesLocked(onBattery, powerAccumulator);
mNumAllUidCpuTimeReads += 2;
}
updateSystemServerThreadStats();
+
+ if (powerAccumulator != null) {
+ updateCpuEnergyLocked(measuredCpuClusterEnergiesUJ, powerAccumulator);
+ }
}
/**
@@ -12579,12 +12745,16 @@ public class BatteryStatsImpl extends BatteryStats {
/**
* Take snapshot of cpu times (aggregated over all uids) at different frequencies and
- * calculate cpu times spent by each uid at different frequencies.
+ * calculate cpu times spent by each uid at different frequencies. Will also add estimated
+ * power consumptions, if powerAccumulator data structure is provided.
*
- * @param updatedUids The uids for which times spent at different frequencies are calculated.
+ * @param updatedUids The uids for which times spent at different frequencies are calculated.
+ * @param onBattery whether or not this is onBattery
+ * @param powerAccumulator object to accumulate the estimated cluster energy.
*/
@VisibleForTesting
- public void updateClusterSpeedTimes(@NonNull SparseLongArray updatedUids, boolean onBattery) {
+ public void updateClusterSpeedTimes(@NonNull SparseLongArray updatedUids, boolean onBattery,
+ @Nullable CpuDeltaPowerAccumulator powerAccumulator) {
long totalCpuClustersTimeMs = 0;
// Read the time spent for each cluster at various cpu frequencies.
final long[][] clusterSpeedTimesMs = new long[mKernelCpuSpeedReaders.length][];
@@ -12626,9 +12796,15 @@ public class BatteryStatsImpl extends BatteryStats {
if (cpuSpeeds[speed] == null) {
cpuSpeeds[speed] = new LongSamplingCounter(mOnBatteryTimeBase);
}
- cpuSpeeds[speed].addCountLocked(appCpuTimeUs
+ final long deltaSpeedCount = appCpuTimeUs
* clusterSpeedTimesMs[cluster][speed]
- / totalCpuClustersTimeMs, onBattery);
+ / totalCpuClustersTimeMs;
+ cpuSpeeds[speed].addCountLocked(deltaSpeedCount, onBattery);
+
+ if (powerAccumulator != null) {
+ powerAccumulator.addCpuClusterSpeedDurationsMs(u, cluster,
+ speed, deltaSpeedCount);
+ }
}
}
}
@@ -12750,13 +12926,18 @@ public class BatteryStatsImpl extends BatteryStats {
/**
* Take a snapshot of the cpu times spent by each uid in each freq and update the
- * corresponding counters.
+ * corresponding counters. Will also add estimated power consumptions, if powerAccumulator
+ * data structure is provided.
*
* @param partialTimers The wakelock holders among which the cpu freq times will be distributed.
+ * @param onBattery whether or not this is onBattery
+ * @param onBatteryScreenOff whether or not this is onBattery with the screen off.
+ * @param powerAccumulator object to accumulate the estimated cluster energy.
*/
@VisibleForTesting
public void readKernelUidCpuFreqTimesLocked(@Nullable ArrayList<StopwatchTimer> partialTimers,
- boolean onBattery, boolean onBatteryScreenOff) {
+ boolean onBattery, boolean onBatteryScreenOff,
+ @Nullable CpuDeltaPowerAccumulator powerAccumulator) {
final boolean perClusterTimesAvailable =
mCpuUidFreqTimeReader.perClusterTimesAvailable();
final int numWakelocks = partialTimers == null ? 0 : partialTimers.size();
@@ -12765,7 +12946,9 @@ public class BatteryStatsImpl extends BatteryStats {
final long startTimeMs = mClocks.uptimeMillis();
final long elapsedRealtimeMs = mClocks.elapsedRealtime();
final List<Integer> uidsToRemove = new ArrayList<>();
- mCpuUidFreqTimeReader.readDelta(false, (uid, cpuFreqTimeMs) -> {
+ // If power is being accumulated for attribution, data needs to be read immediately.
+ final boolean forceRead = powerAccumulator != null;
+ mCpuUidFreqTimeReader.readDelta(forceRead, (uid, cpuFreqTimeMs) -> {
uid = mapUid(uid);
if (Process.isIsolated(uid)) {
uidsToRemove.add(uid);
@@ -12828,6 +13011,11 @@ public class BatteryStatsImpl extends BatteryStats {
appAllocationUs = cpuFreqTimeMs[freqIndex] * 1000;
}
cpuTimesUs[speed].addCountLocked(appAllocationUs, onBattery);
+
+ if (powerAccumulator != null) {
+ powerAccumulator.addCpuClusterSpeedDurationsMs(u, cluster,
+ speed, appAllocationUs / 1000);
+ }
freqIndex++;
}
}
@@ -12868,6 +13056,11 @@ public class BatteryStatsImpl extends BatteryStats {
mWakeLockAllocationsUs[cluster][speed] / (numWakelocks - i);
cpuTimeUs[speed].addCountLocked(allocationUs, onBattery);
mWakeLockAllocationsUs[cluster][speed] -= allocationUs;
+
+ if (powerAccumulator != null) {
+ powerAccumulator.addCpuClusterSpeedDurationsMs(u, cluster,
+ speed, allocationUs / 1000);
+ }
}
}
}
@@ -12910,14 +13103,21 @@ public class BatteryStatsImpl extends BatteryStats {
/**
* Take a snapshot of the cpu cluster times spent by each uid and update the corresponding
- * counters.
+ * counters. Will also add estimated power consumptions, if powerAccumulator data structure
+ * is provided.
+ *
+ * @param onBattery whether or not this is onBattery
+ * @param powerAccumulator object to accumulate the estimated cluster energy.
*/
@VisibleForTesting
- public void readKernelUidCpuClusterTimesLocked(boolean onBattery) {
+ public void readKernelUidCpuClusterTimesLocked(boolean onBattery,
+ @Nullable CpuDeltaPowerAccumulator powerAccumulator) {
final long startTimeMs = mClocks.uptimeMillis();
final long elapsedRealtimeMs = mClocks.elapsedRealtime();
final List<Integer> uidsToRemove = new ArrayList<>();
- mCpuUidClusterTimeReader.readDelta(false, (uid, cpuClusterTimesMs) -> {
+ // If power is being accumulated for attribution, data needs to be read immediately.
+ final boolean forceRead = powerAccumulator != null;
+ mCpuUidClusterTimeReader.readDelta(forceRead, (uid, cpuClusterTimesMs) -> {
uid = mapUid(uid);
if (Process.isIsolated(uid)) {
uidsToRemove.add(uid);
@@ -12931,6 +13131,10 @@ public class BatteryStatsImpl extends BatteryStats {
}
final Uid u = getUidStatsLocked(uid, elapsedRealtimeMs, startTimeMs);
u.mCpuClusterTimesMs.addCountLocked(cpuClusterTimesMs, onBattery);
+
+ if (powerAccumulator != null) {
+ powerAccumulator.addCpuClusterDurationsMs(u, cpuClusterTimesMs);
+ }
});
for (int uid : uidsToRemove) {
mCpuUidClusterTimeReader.removeUid(uid);
@@ -14000,13 +14204,19 @@ public class BatteryStatsImpl extends BatteryStats {
// Measured energy buckets no longer supported, wipe out the existing data.
supportedBucketMismatch = true;
}
- } else if (mGlobalMeasuredEnergyStats == null) {
- mGlobalMeasuredEnergyStats
- = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
- return;
} else {
- supportedBucketMismatch = !mGlobalMeasuredEnergyStats.isSupportEqualTo(
- supportedStandardBuckets, numCustomBuckets);
+ if (mGlobalMeasuredEnergyStats == null) {
+ mGlobalMeasuredEnergyStats =
+ new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+ return;
+ } else {
+ supportedBucketMismatch = !mGlobalMeasuredEnergyStats.isSupportEqualTo(
+ supportedStandardBuckets, numCustomBuckets);
+ }
+
+ if (supportedStandardBuckets[MeasuredEnergyStats.ENERGY_BUCKET_CPU]) {
+ mCpuPowerCalculator = new CpuPowerCalculator(mPowerProfile);
+ }
}
if (supportedBucketMismatch) {
diff --git a/core/java/com/android/internal/power/MeasuredEnergyStats.java b/core/java/com/android/internal/power/MeasuredEnergyStats.java
index d49203c731e9..a86c00f75ef7 100644
--- a/core/java/com/android/internal/power/MeasuredEnergyStats.java
+++ b/core/java/com/android/internal/power/MeasuredEnergyStats.java
@@ -51,13 +51,15 @@ public class MeasuredEnergyStats {
public static final int ENERGY_BUCKET_SCREEN_ON = 0;
public static final int ENERGY_BUCKET_SCREEN_DOZE = 1;
public static final int ENERGY_BUCKET_SCREEN_OTHER = 2;
- public static final int NUMBER_STANDARD_ENERGY_BUCKETS = 3; // Buckets above this are custom.
+ public static final int ENERGY_BUCKET_CPU = 3;
+ public static final int NUMBER_STANDARD_ENERGY_BUCKETS = 4; // Buckets above this are custom.
@IntDef(prefix = {"ENERGY_BUCKET_"}, value = {
ENERGY_BUCKET_UNKNOWN,
ENERGY_BUCKET_SCREEN_ON,
ENERGY_BUCKET_SCREEN_DOZE,
ENERGY_BUCKET_SCREEN_OTHER,
+ ENERGY_BUCKET_CPU,
})
@Retention(RetentionPolicy.SOURCE)
public @interface StandardEnergyBucket {
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
index ff728d651067..4319740ffdf3 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
@@ -121,7 +121,7 @@ public class BatteryStatsCpuTimesTest {
when(mCpuUidFreqTimeReader.readFreqs(mPowerProfile)).thenReturn(freqs);
// RUN
- mBatteryStatsImpl.updateCpuTimeLocked(false, false);
+ mBatteryStatsImpl.updateCpuTimeLocked(false, false, null);
// VERIFY
assertArrayEquals("Unexpected cpu freqs", freqs, mBatteryStatsImpl.getCpuFreqs());
@@ -141,7 +141,7 @@ public class BatteryStatsCpuTimesTest {
mBatteryStatsImpl.setOnBatteryInternal(true);
// RUN
- mBatteryStatsImpl.updateCpuTimeLocked(true, false);
+ mBatteryStatsImpl.updateCpuTimeLocked(true, false, null);
// VERIFY
verify(mUserInfoProvider).refreshUserIds();
@@ -221,7 +221,7 @@ public class BatteryStatsCpuTimesTest {
}
// RUN
- mBatteryStatsImpl.updateClusterSpeedTimes(updatedUids, true);
+ mBatteryStatsImpl.updateClusterSpeedTimes(updatedUids, true, null);
// VERIFY
int totalClustersTimeMs = 0;
@@ -563,7 +563,7 @@ public class BatteryStatsCpuTimesTest {
any(KernelCpuUidFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false, null);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -596,7 +596,7 @@ public class BatteryStatsCpuTimesTest {
any(KernelCpuUidFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true, null);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -647,7 +647,7 @@ public class BatteryStatsCpuTimesTest {
when(mCpuUidFreqTimeReader.perClusterTimesAvailable()).thenReturn(true);
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false, null);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -690,7 +690,7 @@ public class BatteryStatsCpuTimesTest {
any(KernelCpuUidFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true, null);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -757,7 +757,7 @@ public class BatteryStatsCpuTimesTest {
when(mCpuUidFreqTimeReader.perClusterTimesAvailable()).thenReturn(true);
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(partialTimers, true, false);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(partialTimers, true, false, null);
// VERIFY
final long[][] expectedWakeLockUidTimesUs = new long[clusterFreqs.length][];
@@ -846,7 +846,7 @@ public class BatteryStatsCpuTimesTest {
any(KernelCpuUidFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false, null);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -879,7 +879,7 @@ public class BatteryStatsCpuTimesTest {
any(KernelCpuUidFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true, null);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -923,7 +923,7 @@ public class BatteryStatsCpuTimesTest {
any(KernelCpuUidFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false, null);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -963,7 +963,7 @@ public class BatteryStatsCpuTimesTest {
any(KernelCpuUidFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false, null);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -1020,7 +1020,7 @@ public class BatteryStatsCpuTimesTest {
any(KernelCpuUidFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false, null);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -1169,7 +1169,7 @@ public class BatteryStatsCpuTimesTest {
any(KernelCpuUidClusterTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true);
+ mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true, null);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -1199,7 +1199,7 @@ public class BatteryStatsCpuTimesTest {
any(KernelCpuUidClusterTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true);
+ mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true, null);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -1244,7 +1244,7 @@ public class BatteryStatsCpuTimesTest {
any(KernelCpuUidClusterTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true);
+ mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true, null);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
diff --git a/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
index e691beb09a70..70888905d7c8 100644
--- a/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
@@ -126,7 +126,7 @@ public class CpuPowerCalculatorTest {
return null;
}).when(mMockKernelCpuUidClusterTimeReader).readDelta(any());
- mStatsRule.getBatteryStats().updateCpuTimeLocked(true, true);
+ mStatsRule.getBatteryStats().updateCpuTimeLocked(true, true, null);
mStatsRule.getUidStats(APP_UID1).getProcessStatsLocked("foo").addCpuTimeLocked(4321, 1234);
mStatsRule.getUidStats(APP_UID1).getProcessStatsLocked("bar").addCpuTimeLocked(5432, 2345);
diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
index b5282e9a625a..6edbbb0ad789 100644
--- a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
@@ -91,7 +91,7 @@ public class SystemServicePowerCalculatorTest {
new long[] {10000, 20000, 30000, 40000}
);
- mMockBatteryStats.readKernelUidCpuFreqTimesLocked(null, true, false);
+ mMockBatteryStats.readKernelUidCpuFreqTimesLocked(null, true, false, null);
int workSourceUid1 = 100;
int workSourceUid2 = 200;
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index fc28bfbea710..175596bc1ff4 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -620,7 +620,14 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
onBattery = mStats.isOnBatteryLocked();
onBatteryScreenOff = mStats.isOnBatteryScreenOffLocked();
}
- mStats.updateCpuTimeLocked(onBattery, onBatteryScreenOff);
+
+ final long[] cpuClusterEnergiesUJ;
+ if (measuredEnergyDeltas == null) {
+ cpuClusterEnergiesUJ = null;
+ } else {
+ cpuClusterEnergiesUJ = measuredEnergyDeltas.cpuClusterEnergiesUJ;
+ }
+ mStats.updateCpuTimeLocked(onBattery, onBatteryScreenOff, cpuClusterEnergiesUJ);
}
if (updateFlags == UPDATE_ALL) {
@@ -805,6 +812,9 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
buckets[MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_DOZE] = true;
buckets[MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_OTHER] = true;
break;
+ case EnergyConsumerType.CPU_CLUSTER:
+ buckets[MeasuredEnergyStats.ENERGY_BUCKET_CPU] = true;
+ break;
}
}
return buckets;
diff --git a/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java b/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java
index 9e0aa32a0b9e..6efaa735cc61 100644
--- a/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java
+++ b/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java
@@ -43,6 +43,9 @@ public class MeasuredEnergySnapshot {
/** Map of {@link EnergyConsumer#id} to its corresponding {@link EnergyConsumer}. */
private final SparseArray<EnergyConsumer> mEnergyConsumers;
+ /** Number of ordinals for {@link EnergyConsumerType#CPU_CLUSTER}. */
+ private final int mNumCpuClusterOrdinals;
+
/** Number of ordinals for {@link EnergyConsumerType#OTHER}. */
private final int mNumOtherOrdinals;
@@ -78,7 +81,9 @@ public class MeasuredEnergySnapshot {
mEnergyConsumers = idToConsumerMap;
mMeasuredEnergySnapshots = new SparseLongArray(mEnergyConsumers.size());
- mNumOtherOrdinals = calculateNumOtherOrdinals(idToConsumerMap);
+ mNumCpuClusterOrdinals = calculateNumOrdinals(EnergyConsumerType.CPU_CLUSTER,
+ idToConsumerMap);
+ mNumOtherOrdinals = calculateNumOrdinals(EnergyConsumerType.OTHER, idToConsumerMap);
mAttributionSnapshots = new SparseArray<>(mNumOtherOrdinals);
}
@@ -95,6 +100,9 @@ public class MeasuredEnergySnapshot {
/** The energyUJ for {@link EnergyConsumerType#DISPLAY}. */
public long displayEnergyUJ = UNAVAILABLE;
+ /** The energyUJ for {@link EnergyConsumerType#CPU_CLUSTER}s. */
+ public long[] cpuClusterEnergiesUJ = null;
+
/** Map of {@link EnergyConsumerType#OTHER} ordinals to their total energyUJ. */
public @Nullable long[] otherTotalEnergyUJ = null;
@@ -163,6 +171,14 @@ public class MeasuredEnergySnapshot {
case EnergyConsumerType.DISPLAY:
output.displayEnergyUJ = deltaUJ;
break;
+
+ case EnergyConsumerType.CPU_CLUSTER:
+ if (output.cpuClusterEnergiesUJ == null) {
+ output.cpuClusterEnergiesUJ = new long[mNumCpuClusterOrdinals];
+ }
+ output.cpuClusterEnergiesUJ[ordinal] = deltaUJ;
+ break;
+
case EnergyConsumerType.OTHER:
if (output.otherTotalEnergyUJ == null) {
output.otherTotalEnergyUJ = new long[getNumOtherOrdinals()];
@@ -262,15 +278,16 @@ public class MeasuredEnergySnapshot {
pw.println();
}
- /** Determines the number of ordinals for {@link EnergyConsumerType#OTHER}. */
- private static int calculateNumOtherOrdinals(SparseArray<EnergyConsumer> idToConsumer) {
+ /** Determines the number of ordinals for a given {@link EnergyConsumerType}. */
+ private static int calculateNumOrdinals(@EnergyConsumerType int type,
+ SparseArray<EnergyConsumer> idToConsumer) {
if (idToConsumer == null) return 0;
- int numOtherOrdinals = 0;
+ int numOrdinals = 0;
final int size = idToConsumer.size();
for (int idx = 0; idx < size; idx++) {
final EnergyConsumer consumer = idToConsumer.valueAt(idx);
- if (consumer.type == EnergyConsumerType.OTHER) numOtherOrdinals++;
+ if (consumer.type == type) numOrdinals++;
}
- return numOtherOrdinals;
+ return numOrdinals;
}
}