Merge "Utilize measured cpu batteryconsumption in CpuPowerCalculator" into sc-dev

This commit is contained in:
TreeHugger Robot
2021-03-12 20:51:44 +00:00
committed by Android (Google) Code Review
4 changed files with 162 additions and 50 deletions

View File

@@ -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

View File

@@ -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];

View File

@@ -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.
*

View File

@@ -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();
}
}