Merge "Utilize measured cpu batteryconsumption in CpuPowerCalculator" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
ff51356f0d
@@ -994,6 +994,15 @@ public abstract class BatteryStats implements Parcelable {
|
||||
*/
|
||||
public abstract long getScreenOnMeasuredBatteryConsumptionUC();
|
||||
|
||||
/**
|
||||
* Returns the battery consumption (in microcoulombs) of the uid's cpu usage, derived from
|
||||
* on device power measurement data.
|
||||
* Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public abstract long getCpuMeasuredBatteryConsumptionUC();
|
||||
|
||||
/**
|
||||
* Returns the battery consumption (in microcoulombs) used by this uid for each
|
||||
* {@link android.hardware.power.stats.EnergyConsumer.ordinal} of (custom) energy consumer
|
||||
@@ -2520,6 +2529,15 @@ public abstract class BatteryStats implements Parcelable {
|
||||
*/
|
||||
public abstract long getScreenDozeMeasuredBatteryConsumptionUC();
|
||||
|
||||
/**
|
||||
* Returns the battery consumption (in microcoulombs) of the cpu, derived from on device power
|
||||
* measurement data.
|
||||
* Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public abstract long getCpuMeasuredBatteryConsumptionUC();
|
||||
|
||||
/**
|
||||
* Returns the battery consumption (in microcoulombs) that each
|
||||
* {@link android.hardware.power.stats.EnergyConsumer.ordinal} of (custom) energy consumer
|
||||
|
||||
@@ -6976,6 +6976,11 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
return getPowerBucketConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_SCREEN_DOZE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCpuMeasuredBatteryConsumptionUC() {
|
||||
return getPowerBucketConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_CPU);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the consumption (in microcoulombs) that the given standard power bucket consumed.
|
||||
* Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable
|
||||
@@ -8482,6 +8487,11 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
return getMeasuredBatteryConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCpuMeasuredBatteryConsumptionUC() {
|
||||
return getMeasuredBatteryConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_CPU);
|
||||
}
|
||||
|
||||
void initNetworkActivityLocked() {
|
||||
detachIfNotNull(mNetworkByteActivityCounters);
|
||||
mNetworkByteActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
|
||||
|
||||
@@ -85,12 +85,14 @@ public class CpuPowerCalculator extends PowerCalculator {
|
||||
builder.getUidBatteryConsumerBuilders();
|
||||
for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
|
||||
final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
|
||||
calculateApp(app, app.getBatteryStatsUid(), result);
|
||||
calculateApp(app, app.getBatteryStatsUid(), query, result);
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u, Result result) {
|
||||
calculatePowerAndDuration(u, BatteryStats.STATS_SINCE_CHARGED, result);
|
||||
private void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
|
||||
BatteryUsageStatsQuery query, Result result) {
|
||||
calculatePowerAndDuration(u, BatteryStats.STATS_SINCE_CHARGED,
|
||||
query.shouldForceUsePowerProfileModel(), result);
|
||||
|
||||
app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, result.powerMah)
|
||||
.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU, result.durationMs)
|
||||
@@ -112,7 +114,7 @@ public class CpuPowerCalculator extends PowerCalculator {
|
||||
}
|
||||
|
||||
private void calculateApp(BatterySipper app, BatteryStats.Uid u, int statsType, Result result) {
|
||||
calculatePowerAndDuration(u, statsType, result);
|
||||
calculatePowerAndDuration(u, statsType, false, result);
|
||||
|
||||
app.cpuPowerMah = result.powerMah;
|
||||
app.cpuTimeMs = result.durationMs;
|
||||
@@ -120,46 +122,16 @@ public class CpuPowerCalculator extends PowerCalculator {
|
||||
app.packageWithHighestDrain = result.packageWithHighestDrain;
|
||||
}
|
||||
|
||||
private void calculatePowerAndDuration(BatteryStats.Uid u, int statsType, Result result) {
|
||||
private void calculatePowerAndDuration(BatteryStats.Uid u, int statsType,
|
||||
boolean forceUsePowerProfileModel, Result result) {
|
||||
long durationMs = (u.getUserCpuTimeUs(statsType) + u.getSystemCpuTimeUs(statsType)) / 1000;
|
||||
|
||||
// Constant battery drain when CPU is active
|
||||
double powerMah = calculateActiveCpuPowerMah(u.getCpuActiveTime());
|
||||
|
||||
// Additional per-cluster battery drain
|
||||
long[] cpuClusterTimes = u.getCpuClusterTimes();
|
||||
if (cpuClusterTimes != null) {
|
||||
if (cpuClusterTimes.length == mNumCpuClusters) {
|
||||
for (int cluster = 0; cluster < mNumCpuClusters; cluster++) {
|
||||
double power = calculatePerCpuClusterPowerMah(cluster,
|
||||
cpuClusterTimes[cluster]);
|
||||
powerMah += power;
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster
|
||||
+ " clusterTimeMs=" + cpuClusterTimes[cluster]
|
||||
+ " power=" + formatCharge(power));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "UID " + u.getUid() + " CPU cluster # mismatch: Power Profile # "
|
||||
+ mNumCpuClusters + " actual # " + cpuClusterTimes.length);
|
||||
}
|
||||
}
|
||||
|
||||
// Additional per-frequency battery drain
|
||||
for (int cluster = 0; cluster < mNumCpuClusters; cluster++) {
|
||||
final int speedsForCluster = mPerCpuFreqPowerEstimators[cluster].length;
|
||||
for (int speed = 0; speed < speedsForCluster; speed++) {
|
||||
final long timeUs = u.getTimeAtCpuSpeed(cluster, speed, statsType);
|
||||
final double power = calculatePerCpuFreqPowerMah(cluster, speed,
|
||||
timeUs / 1000);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster + " step #"
|
||||
+ speed + " timeUs=" + timeUs + " power="
|
||||
+ formatCharge(power));
|
||||
}
|
||||
powerMah += power;
|
||||
}
|
||||
final double powerMah;
|
||||
final long consumptionUC = u.getCpuMeasuredBatteryConsumptionUC();
|
||||
if (forceUsePowerProfileModel || consumptionUC == BatteryStats.POWER_DATA_UNAVAILABLE) {
|
||||
powerMah = calculateUidModeledPowerMah(u, statsType);
|
||||
} else {
|
||||
powerMah = uCtoMah(consumptionUC);
|
||||
}
|
||||
|
||||
if (DEBUG && (durationMs != 0 || powerMah != 0)) {
|
||||
@@ -208,6 +180,48 @@ public class CpuPowerCalculator extends PowerCalculator {
|
||||
result.packageWithHighestDrain = packageWithHighestDrain;
|
||||
}
|
||||
|
||||
private double calculateUidModeledPowerMah(BatteryStats.Uid u, int statsType) {
|
||||
// Constant battery drain when CPU is active
|
||||
double powerMah = calculateActiveCpuPowerMah(u.getCpuActiveTime());
|
||||
|
||||
// Additional per-cluster battery drain
|
||||
long[] cpuClusterTimes = u.getCpuClusterTimes();
|
||||
if (cpuClusterTimes != null) {
|
||||
if (cpuClusterTimes.length == mNumCpuClusters) {
|
||||
for (int cluster = 0; cluster < mNumCpuClusters; cluster++) {
|
||||
double power = calculatePerCpuClusterPowerMah(cluster,
|
||||
cpuClusterTimes[cluster]);
|
||||
powerMah += power;
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster
|
||||
+ " clusterTimeMs=" + cpuClusterTimes[cluster]
|
||||
+ " power=" + formatCharge(power));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "UID " + u.getUid() + " CPU cluster # mismatch: Power Profile # "
|
||||
+ mNumCpuClusters + " actual # " + cpuClusterTimes.length);
|
||||
}
|
||||
}
|
||||
|
||||
// Additional per-frequency battery drain
|
||||
for (int cluster = 0; cluster < mNumCpuClusters; cluster++) {
|
||||
final int speedsForCluster = mPerCpuFreqPowerEstimators[cluster].length;
|
||||
for (int speed = 0; speed < speedsForCluster; speed++) {
|
||||
final long timeUs = u.getTimeAtCpuSpeed(cluster, speed, statsType);
|
||||
final double power = calculatePerCpuFreqPowerMah(cluster, speed,
|
||||
timeUs / 1000);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster + " step #"
|
||||
+ speed + " timeUs=" + timeUs + " power="
|
||||
+ formatCharge(power));
|
||||
}
|
||||
powerMah += power;
|
||||
}
|
||||
}
|
||||
return powerMah;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates active CPU power consumption.
|
||||
*
|
||||
|
||||
@@ -19,18 +19,22 @@ package com.android.internal.os;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.os.BatteryConsumer;
|
||||
import android.os.BatteryUsageStatsQuery;
|
||||
import android.os.Process;
|
||||
import android.os.UidBatteryConsumer;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.internal.power.MeasuredEnergyStats;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
@@ -81,6 +85,10 @@ public class CpuPowerCalculatorTest {
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
final boolean[] supportedPowerBuckets =
|
||||
new boolean[MeasuredEnergyStats.NUMBER_STANDARD_POWER_BUCKETS];
|
||||
supportedPowerBuckets[MeasuredEnergyStats.POWER_BUCKET_CPU] = true;
|
||||
|
||||
mStatsRule.getBatteryStats()
|
||||
.setUserInfoProvider(mMockUserInfoProvider)
|
||||
.setKernelCpuSpeedReaders(mMockKernelCpuSpeedReaders)
|
||||
@@ -88,7 +96,8 @@ public class CpuPowerCalculatorTest {
|
||||
.setKernelCpuUidClusterTimeReader(mMockKernelCpuUidClusterTimeReader)
|
||||
.setKernelCpuUidUserSysTimeReader(mMockKernelCpuUidUserSysTimeReader)
|
||||
.setKernelCpuUidActiveTimeReader(mMockKerneCpuUidActiveTimeReader)
|
||||
.setSystemServerCpuThreadReader(mMockSystemServerCpuThreadReader);
|
||||
.setSystemServerCpuThreadReader(mMockSystemServerCpuThreadReader)
|
||||
.initMeasuredEnergyStatsLocked(supportedPowerBuckets, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -103,28 +112,28 @@ public class CpuPowerCalculatorTest {
|
||||
|
||||
// User/System CPU time
|
||||
doAnswer(invocation -> {
|
||||
final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(0);
|
||||
final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(1);
|
||||
// User/system time in microseconds
|
||||
callback.onUidCpuTime(APP_UID1, new long[]{1111000, 2222000});
|
||||
callback.onUidCpuTime(APP_UID2, new long[]{3333000, 4444000});
|
||||
return null;
|
||||
}).when(mMockKernelCpuUidUserSysTimeReader).readDelta(any());
|
||||
}).when(mMockKernelCpuUidUserSysTimeReader).readDelta(anyBoolean(), any());
|
||||
|
||||
// Active CPU time
|
||||
doAnswer(invocation -> {
|
||||
final KernelCpuUidTimeReader.Callback<Long> callback = invocation.getArgument(0);
|
||||
final KernelCpuUidTimeReader.Callback<Long> callback = invocation.getArgument(1);
|
||||
callback.onUidCpuTime(APP_UID1, 1111L);
|
||||
callback.onUidCpuTime(APP_UID2, 3333L);
|
||||
return null;
|
||||
}).when(mMockKerneCpuUidActiveTimeReader).readDelta(any());
|
||||
}).when(mMockKerneCpuUidActiveTimeReader).readDelta(anyBoolean(), any());
|
||||
|
||||
// Per-cluster CPU time
|
||||
doAnswer(invocation -> {
|
||||
final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(0);
|
||||
final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(1);
|
||||
callback.onUidCpuTime(APP_UID1, new long[]{1111, 2222});
|
||||
callback.onUidCpuTime(APP_UID2, new long[]{3333, 4444});
|
||||
return null;
|
||||
}).when(mMockKernelCpuUidClusterTimeReader).readDelta(any());
|
||||
}).when(mMockKernelCpuUidClusterTimeReader).readDelta(anyBoolean(), any());
|
||||
|
||||
mStatsRule.getBatteryStats().updateCpuTimeLocked(true, true, null);
|
||||
|
||||
@@ -134,7 +143,8 @@ public class CpuPowerCalculatorTest {
|
||||
CpuPowerCalculator calculator =
|
||||
new CpuPowerCalculator(mStatsRule.getPowerProfile());
|
||||
|
||||
mStatsRule.apply(calculator);
|
||||
mStatsRule.apply(new BatteryUsageStatsQuery.Builder().powerProfileModeledOnly().build(),
|
||||
calculator);
|
||||
|
||||
UidBatteryConsumer uidConsumer1 = mStatsRule.getUidBatteryConsumer(APP_UID1);
|
||||
assertThat(uidConsumer1.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU))
|
||||
@@ -150,4 +160,64 @@ public class CpuPowerCalculatorTest {
|
||||
.isWithin(PRECISION).of(2.672322);
|
||||
assertThat(uidConsumer2.getPackageWithHighestDrain()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMeasuredEnergyBasedModel() {
|
||||
when(mMockUserInfoProvider.exists(anyInt())).thenReturn(true);
|
||||
|
||||
when(mMockKernelCpuSpeedReaders[0].readDelta()).thenReturn(new long[]{1000, 2000});
|
||||
when(mMockKernelCpuSpeedReaders[1].readDelta()).thenReturn(new long[]{3000, 4000});
|
||||
|
||||
when(mMockCpuUidFreqTimeReader.perClusterTimesAvailable()).thenReturn(false);
|
||||
|
||||
// User/System CPU time
|
||||
doAnswer(invocation -> {
|
||||
final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(1);
|
||||
// User/system time in microseconds
|
||||
callback.onUidCpuTime(APP_UID1, new long[]{1111000, 2222000});
|
||||
callback.onUidCpuTime(APP_UID2, new long[]{3333000, 4444000});
|
||||
return null;
|
||||
}).when(mMockKernelCpuUidUserSysTimeReader).readDelta(anyBoolean(), any());
|
||||
|
||||
// Active CPU time
|
||||
doAnswer(invocation -> {
|
||||
final KernelCpuUidTimeReader.Callback<Long> callback = invocation.getArgument(1);
|
||||
callback.onUidCpuTime(APP_UID1, 1111L);
|
||||
callback.onUidCpuTime(APP_UID2, 3333L);
|
||||
return null;
|
||||
}).when(mMockKerneCpuUidActiveTimeReader).readDelta(anyBoolean(), any());
|
||||
|
||||
// Per-cluster CPU time
|
||||
doAnswer(invocation -> {
|
||||
final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(1);
|
||||
callback.onUidCpuTime(APP_UID1, new long[]{1111, 2222});
|
||||
callback.onUidCpuTime(APP_UID2, new long[]{3333, 4444});
|
||||
return null;
|
||||
}).when(mMockKernelCpuUidClusterTimeReader).readDelta(anyBoolean(), any());
|
||||
|
||||
final long[] clusterChargesUC = new long[]{13577531, 24688642};
|
||||
mStatsRule.getBatteryStats().updateCpuTimeLocked(true, true, clusterChargesUC);
|
||||
|
||||
mStatsRule.getUidStats(APP_UID1).getProcessStatsLocked("foo").addCpuTimeLocked(4321, 1234);
|
||||
mStatsRule.getUidStats(APP_UID1).getProcessStatsLocked("bar").addCpuTimeLocked(5432, 2345);
|
||||
|
||||
CpuPowerCalculator calculator =
|
||||
new CpuPowerCalculator(mStatsRule.getPowerProfile());
|
||||
|
||||
mStatsRule.apply(calculator);
|
||||
|
||||
UidBatteryConsumer uidConsumer1 = mStatsRule.getUidBatteryConsumer(APP_UID1);
|
||||
assertThat(uidConsumer1.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU))
|
||||
.isEqualTo(3333);
|
||||
assertThat(uidConsumer1.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU))
|
||||
.isWithin(PRECISION).of(3.18877);
|
||||
assertThat(uidConsumer1.getPackageWithHighestDrain()).isEqualTo("bar");
|
||||
|
||||
UidBatteryConsumer uidConsumer2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
|
||||
assertThat(uidConsumer2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU))
|
||||
.isEqualTo(7777);
|
||||
assertThat(uidConsumer2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU))
|
||||
.isWithin(PRECISION).of(7.44072);
|
||||
assertThat(uidConsumer2.getPackageWithHighestDrain()).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user