Merge "Simplify SystemServicePowerCalculator" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
d77bb6a44b
@@ -48,6 +48,7 @@ public abstract class BatteryConsumer {
|
||||
POWER_COMPONENT_SENSORS,
|
||||
POWER_COMPONENT_GNSS,
|
||||
POWER_COMPONENT_SCREEN,
|
||||
POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public static @interface PowerComponent {
|
||||
@@ -65,8 +66,12 @@ public abstract class BatteryConsumer {
|
||||
public static final int POWER_COMPONENT_SENSORS = 9;
|
||||
public static final int POWER_COMPONENT_GNSS = 10;
|
||||
public static final int POWER_COMPONENT_SCREEN = 13;
|
||||
// Power that is re-attributed to other battery consumers. For example, for System Server
|
||||
// this represents the power attributed to apps requesting system services.
|
||||
// The value should be negative or zero.
|
||||
public static final int POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS = 14;
|
||||
|
||||
public static final int POWER_COMPONENT_COUNT = 14;
|
||||
public static final int POWER_COMPONENT_COUNT = 15;
|
||||
|
||||
public static final int FIRST_CUSTOM_POWER_COMPONENT_ID = 1000;
|
||||
public static final int LAST_CUSTOM_POWER_COMPONENT_ID = 9999;
|
||||
@@ -236,5 +241,13 @@ public abstract class BatteryConsumer {
|
||||
componentUsageTimeMillis);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total power accumulated by this builder so far. It may change
|
||||
* by the time the {@code build()} method is called.
|
||||
*/
|
||||
public double getTotalPower() {
|
||||
return mPowerComponentsBuilder.getTotalPower();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,11 +38,7 @@ class PowerComponents {
|
||||
mCustomPowerComponentCount = builder.mCustomPowerComponentCount;
|
||||
mPowerComponents = builder.mPowerComponents;
|
||||
mTimeComponents = builder.mTimeComponents;
|
||||
double totalPower = 0;
|
||||
for (int i = mPowerComponents.length - 1; i >= 0; i--) {
|
||||
totalPower += mPowerComponents[i];
|
||||
}
|
||||
mTotalPowerConsumed = totalPower;
|
||||
mTotalPowerConsumed = builder.getTotalPower();
|
||||
}
|
||||
|
||||
PowerComponents(@NonNull Parcel source) {
|
||||
@@ -263,6 +259,18 @@ class PowerComponents {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total power accumulated by this builder so far. It may change
|
||||
* by the time the {@code build()} method is called.
|
||||
*/
|
||||
public double getTotalPower() {
|
||||
double totalPower = 0;
|
||||
for (int i = mPowerComponents.length - 1; i >= 0; i--) {
|
||||
totalPower += mPowerComponents[i];
|
||||
}
|
||||
return totalPower;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a read-only object out of the Builder values.
|
||||
*/
|
||||
|
||||
@@ -135,6 +135,11 @@ public class BatterySipper implements Comparable<BatterySipper> {
|
||||
public double systemServiceCpuPowerMah;
|
||||
public double[] customMeasuredPowerMah;
|
||||
|
||||
// Power that is re-attributed to other sippers. For example, for System Server
|
||||
// this represents the power attributed to apps requesting system services.
|
||||
// The value should be negative or zero.
|
||||
public double powerReattributedToOtherSippersMah;
|
||||
|
||||
// Do not include this sipper in results because it is included
|
||||
// in an aggregate sipper.
|
||||
public boolean isAggregated;
|
||||
@@ -263,6 +268,7 @@ public class BatterySipper implements Comparable<BatterySipper> {
|
||||
}
|
||||
}
|
||||
}
|
||||
powerReattributedToOtherSippersMah += other.powerReattributedToOtherSippersMah;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -281,6 +287,10 @@ public class BatterySipper implements Comparable<BatterySipper> {
|
||||
totalPowerMah += customMeasuredPowerMah[idx];
|
||||
}
|
||||
}
|
||||
|
||||
// powerAttributedToOtherSippersMah is negative or zero
|
||||
totalPowerMah = totalPowerMah + powerReattributedToOtherSippersMah;
|
||||
|
||||
totalSmearedPowerMah = totalPowerMah + screenPowerMah + proportionalSmearMah;
|
||||
|
||||
return totalPowerMah;
|
||||
|
||||
@@ -70,11 +70,14 @@ public class BatteryUsageStatsProvider {
|
||||
mPowerCalculators.add(new PhonePowerCalculator(mPowerProfile));
|
||||
mPowerCalculators.add(new ScreenPowerCalculator(mPowerProfile));
|
||||
mPowerCalculators.add(new AmbientDisplayPowerCalculator(mPowerProfile));
|
||||
mPowerCalculators.add(new SystemServicePowerCalculator(mPowerProfile));
|
||||
mPowerCalculators.add(new IdlePowerCalculator(mPowerProfile));
|
||||
mPowerCalculators.add(new CustomMeasuredPowerCalculator(mPowerProfile));
|
||||
|
||||
mPowerCalculators.add(new UserPowerCalculator());
|
||||
|
||||
// It is important that SystemServicePowerCalculator be applied last,
|
||||
// because it re-attributes some of the power estimated by the other
|
||||
// calculators.
|
||||
mPowerCalculators.add(new SystemServicePowerCalculator(mPowerProfile));
|
||||
}
|
||||
}
|
||||
return mPowerCalculators;
|
||||
@@ -128,7 +131,8 @@ public class BatteryUsageStatsProvider {
|
||||
final long uptimeUs = SystemClock.uptimeMillis() * 1000;
|
||||
|
||||
final List<PowerCalculator> powerCalculators = getPowerCalculators();
|
||||
for (PowerCalculator powerCalculator : powerCalculators) {
|
||||
for (int i = 0, count = powerCalculators.size(); i < count; i++) {
|
||||
PowerCalculator powerCalculator = powerCalculators.get(i);
|
||||
powerCalculator.calculate(batteryUsageStatsBuilder, mStats, realtimeUs, uptimeUs,
|
||||
query);
|
||||
}
|
||||
|
||||
@@ -20,12 +20,12 @@ import android.os.BatteryConsumer;
|
||||
import android.os.BatteryStats;
|
||||
import android.os.BatteryUsageStats;
|
||||
import android.os.BatteryUsageStatsQuery;
|
||||
import android.os.Process;
|
||||
import android.os.UidBatteryConsumer;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -36,87 +36,112 @@ public class SystemServicePowerCalculator extends PowerCalculator {
|
||||
private static final boolean DEBUG = false;
|
||||
private static final String TAG = "SystemServicePowerCalc";
|
||||
|
||||
private static final long MICROSEC_IN_HR = (long) 60 * 60 * 1000 * 1000;
|
||||
|
||||
private final PowerProfile mPowerProfile;
|
||||
|
||||
// Tracks system server CPU [cluster][speed] power in milliAmp-microseconds
|
||||
// Data organized like this:
|
||||
// Power estimators per CPU cluster, per CPU frequency. The array is flattened according
|
||||
// to this layout:
|
||||
// {cluster1-speed1, cluster1-speed2, ..., cluster2-speed1, cluster2-speed2, ...}
|
||||
private double[] mSystemServicePowerMaUs;
|
||||
private final UsageBasedPowerEstimator[] mPowerEstimators;
|
||||
|
||||
public SystemServicePowerCalculator(PowerProfile powerProfile) {
|
||||
mPowerProfile = powerProfile;
|
||||
int numFreqs = 0;
|
||||
final int numCpuClusters = powerProfile.getNumCpuClusters();
|
||||
for (int cluster = 0; cluster < numCpuClusters; cluster++) {
|
||||
numFreqs += powerProfile.getNumSpeedStepsInCpuCluster(cluster);
|
||||
}
|
||||
|
||||
mPowerEstimators = new UsageBasedPowerEstimator[numFreqs];
|
||||
int index = 0;
|
||||
for (int cluster = 0; cluster < numCpuClusters; cluster++) {
|
||||
final int numSpeeds = powerProfile.getNumSpeedStepsInCpuCluster(cluster);
|
||||
for (int speed = 0; speed < numSpeeds; speed++) {
|
||||
mPowerEstimators[index++] = new UsageBasedPowerEstimator(
|
||||
powerProfile.getAveragePowerForCpuCore(cluster, speed));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
|
||||
long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
|
||||
calculateSystemServicePower(batteryStats);
|
||||
super.calculate(builder, batteryStats, rawRealtimeUs, rawUptimeUs, query);
|
||||
}
|
||||
double systemServicePowerMah = calculateSystemServicePower(batteryStats);
|
||||
final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =
|
||||
builder.getUidBatteryConsumerBuilders();
|
||||
final UidBatteryConsumer.Builder systemServerConsumer = uidBatteryConsumerBuilders.get(
|
||||
Process.SYSTEM_UID);
|
||||
|
||||
@Override
|
||||
protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
|
||||
long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
|
||||
app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES,
|
||||
calculateSystemServerCpuPowerMah(u));
|
||||
if (systemServerConsumer != null) {
|
||||
systemServicePowerMah = Math.min(systemServicePowerMah,
|
||||
systemServerConsumer.getTotalPower());
|
||||
|
||||
// The system server power needs to be adjusted because part of it got
|
||||
// distributed to applications
|
||||
systemServerConsumer.setConsumedPower(
|
||||
BatteryConsumer.POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS,
|
||||
-systemServicePowerMah);
|
||||
}
|
||||
|
||||
for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
|
||||
final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
|
||||
if (app != systemServerConsumer) {
|
||||
final BatteryStats.Uid uid = app.getBatteryStatsUid();
|
||||
app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES,
|
||||
systemServicePowerMah * uid.getProportionalSystemServiceUsage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
|
||||
long rawRealtimeUs, long rawUptimeUs, int statsType,
|
||||
SparseArray<UserHandle> asUsers) {
|
||||
calculateSystemServicePower(batteryStats);
|
||||
super.calculate(sippers, batteryStats, rawRealtimeUs, rawUptimeUs, statsType, asUsers);
|
||||
double systemServicePowerMah = calculateSystemServicePower(batteryStats);
|
||||
BatterySipper systemServerSipper = null;
|
||||
for (int i = sippers.size() - 1; i >= 0; i--) {
|
||||
final BatterySipper app = sippers.get(i);
|
||||
if (app.drainType == BatterySipper.DrainType.APP) {
|
||||
if (app.getUid() == Process.SYSTEM_UID) {
|
||||
systemServerSipper = app;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (systemServerSipper != null) {
|
||||
systemServicePowerMah = Math.min(systemServicePowerMah, systemServerSipper.sumPower());
|
||||
|
||||
// The system server power needs to be adjusted because part of it got
|
||||
// distributed to applications
|
||||
systemServerSipper.powerReattributedToOtherSippersMah = -systemServicePowerMah;
|
||||
}
|
||||
|
||||
for (int i = sippers.size() - 1; i >= 0; i--) {
|
||||
final BatterySipper app = sippers.get(i);
|
||||
if (app.drainType == BatterySipper.DrainType.APP) {
|
||||
if (app != systemServerSipper) {
|
||||
final BatteryStats.Uid uid = app.uidObj;
|
||||
app.systemServiceCpuPowerMah =
|
||||
systemServicePowerMah * uid.getProportionalSystemServiceUsage();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {
|
||||
app.systemServiceCpuPowerMah = calculateSystemServerCpuPowerMah(u);
|
||||
}
|
||||
|
||||
private void calculateSystemServicePower(BatteryStats batteryStats) {
|
||||
private double calculateSystemServicePower(BatteryStats batteryStats) {
|
||||
final long[] systemServiceTimeAtCpuSpeeds = batteryStats.getSystemServiceTimeAtCpuSpeeds();
|
||||
if (systemServiceTimeAtCpuSpeeds == null) {
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mSystemServicePowerMaUs == null) {
|
||||
mSystemServicePowerMaUs = new double[systemServiceTimeAtCpuSpeeds.length];
|
||||
}
|
||||
int index = 0;
|
||||
final int numCpuClusters = mPowerProfile.getNumCpuClusters();
|
||||
for (int cluster = 0; cluster < numCpuClusters; cluster++) {
|
||||
final int numSpeeds = mPowerProfile.getNumSpeedStepsInCpuCluster(cluster);
|
||||
for (int speed = 0; speed < numSpeeds; speed++) {
|
||||
mSystemServicePowerMaUs[index] =
|
||||
systemServiceTimeAtCpuSpeeds[index]
|
||||
* mPowerProfile.getAveragePowerForCpuCore(cluster, speed);
|
||||
index++;
|
||||
}
|
||||
// TODO(179210707): additionally account for CPU active and per cluster battery use
|
||||
|
||||
double powerMah = 0;
|
||||
for (int i = 0; i < mPowerEstimators.length; i++) {
|
||||
powerMah += mPowerEstimators[i].calculatePower(systemServiceTimeAtCpuSpeeds[i]);
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "System service power per CPU cluster and frequency:"
|
||||
+ Arrays.toString(mSystemServicePowerMaUs));
|
||||
Log.d(TAG, "System service power:" + powerMah);
|
||||
}
|
||||
}
|
||||
|
||||
private double calculateSystemServerCpuPowerMah(BatteryStats.Uid u) {
|
||||
double cpuPowerMaUs = 0;
|
||||
final double proportionalUsage = u.getProportionalSystemServiceUsage();
|
||||
if (proportionalUsage > 0 && mSystemServicePowerMaUs != null) {
|
||||
for (int i = 0; i < mSystemServicePowerMaUs.length; i++) {
|
||||
cpuPowerMaUs += mSystemServicePowerMaUs[i] * proportionalUsage;
|
||||
}
|
||||
}
|
||||
return cpuPowerMaUs / MICROSEC_IN_HR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
mSystemServicePowerMaUs = null;
|
||||
return powerMah;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,16 @@ package com.android.internal.os;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.os.BatteryConsumer;
|
||||
import android.os.BatteryStats;
|
||||
import android.os.BatteryUsageStatsQuery;
|
||||
import android.os.Binder;
|
||||
import android.os.Process;
|
||||
import android.os.UidBatteryConsumer;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.test.filters.SmallTest;
|
||||
@@ -39,34 +46,48 @@ import java.util.Collection;
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class SystemServicePowerCalculatorTest {
|
||||
|
||||
private static final double PRECISION = 0.0000001;
|
||||
private static final double PRECISION = 0.000001;
|
||||
|
||||
@Rule
|
||||
public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule();
|
||||
public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
|
||||
.setAveragePower(PowerProfile.POWER_CPU_ACTIVE, 720)
|
||||
.setNumCpuClusters(2)
|
||||
.setNumSpeedStepsInCpuCluster(0, 2)
|
||||
.setNumSpeedStepsInCpuCluster(1, 2)
|
||||
.setAveragePowerForCpuCluster(0, 360)
|
||||
.setAveragePowerForCpuCluster(1, 480)
|
||||
.setAveragePowerForCpuCore(0, 0, 300)
|
||||
.setAveragePowerForCpuCore(0, 1, 400)
|
||||
.setAveragePowerForCpuCore(1, 0, 500)
|
||||
.setAveragePowerForCpuCore(1, 1, 600);
|
||||
|
||||
private BatteryStatsImpl.UserInfoProvider mMockUserInfoProvider;
|
||||
private MockBatteryStatsImpl mMockBatteryStats;
|
||||
private MockKernelCpuUidFreqTimeReader mMockCpuUidFreqTimeReader;
|
||||
private MockSystemServerCpuThreadReader mMockSystemServerCpuThreadReader;
|
||||
|
||||
@Before
|
||||
public void setUp() throws IOException {
|
||||
mMockUserInfoProvider = mock(BatteryStatsImpl.UserInfoProvider.class);
|
||||
mMockSystemServerCpuThreadReader = new MockSystemServerCpuThreadReader();
|
||||
mMockCpuUidFreqTimeReader = new MockKernelCpuUidFreqTimeReader();
|
||||
mMockBatteryStats = mStatsRule.getBatteryStats()
|
||||
.setSystemServerCpuThreadReader(mMockSystemServerCpuThreadReader)
|
||||
.setKernelCpuUidFreqTimeReader(mMockCpuUidFreqTimeReader)
|
||||
.setUserInfoProvider(new MockUserInfoProvider());
|
||||
.setUserInfoProvider(mMockUserInfoProvider);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculateApp() {
|
||||
// Test Power Profile has two CPU clusters with 3 and 4 speeds, thus 7 freq times total
|
||||
public void testPowerProfileBasedModel() {
|
||||
when(mMockUserInfoProvider.exists(anyInt())).thenReturn(true);
|
||||
|
||||
// Test Power Profile has two CPU clusters with 2 speeds each, thus 4 freq times total
|
||||
mMockSystemServerCpuThreadReader.setCpuTimes(
|
||||
new long[] {30000, 40000, 50000, 60000, 70000, 80000, 90000},
|
||||
new long[] {20000, 30000, 40000, 50000, 60000, 70000, 80000});
|
||||
new long[] {30000, 40000, 50000, 60000},
|
||||
new long[] {20000, 30000, 40000, 50000});
|
||||
|
||||
mMockCpuUidFreqTimeReader.setSystemServerCpuTimes(
|
||||
new long[] {10000, 20000, 30000, 40000, 50000, 60000, 70000}
|
||||
new long[] {10000, 20000, 30000, 40000}
|
||||
);
|
||||
|
||||
mMockBatteryStats.readKernelUidCpuFreqTimesLocked(null, true, false);
|
||||
@@ -101,14 +122,17 @@ public class SystemServicePowerCalculatorTest {
|
||||
SystemServicePowerCalculator calculator = new SystemServicePowerCalculator(
|
||||
mStatsRule.getPowerProfile());
|
||||
|
||||
mStatsRule.apply(calculator);
|
||||
mStatsRule.apply(new FakeCpuPowerCalculator(), calculator);
|
||||
|
||||
assertThat(mStatsRule.getUidBatteryConsumer(workSourceUid1)
|
||||
.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES))
|
||||
.isWithin(PRECISION).of(0.00016269);
|
||||
.isWithin(PRECISION).of(1.888888);
|
||||
assertThat(mStatsRule.getUidBatteryConsumer(workSourceUid2)
|
||||
.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES))
|
||||
.isWithin(PRECISION).of(0.00146426);
|
||||
.isWithin(PRECISION).of(17.0);
|
||||
assertThat(mStatsRule.getUidBatteryConsumer(Process.SYSTEM_UID)
|
||||
.getConsumedPower(BatteryConsumer.POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS))
|
||||
.isWithin(PRECISION).of(-18.888888);
|
||||
}
|
||||
|
||||
private static class MockKernelCpuUidFreqTimeReader extends
|
||||
@@ -137,7 +161,7 @@ public class SystemServicePowerCalculatorTest {
|
||||
}
|
||||
|
||||
private static class MockSystemServerCpuThreadReader extends SystemServerCpuThreadReader {
|
||||
private SystemServiceCpuThreadTimes mThreadTimes = new SystemServiceCpuThreadTimes();
|
||||
private final SystemServiceCpuThreadTimes mThreadTimes = new SystemServiceCpuThreadTimes();
|
||||
|
||||
MockSystemServerCpuThreadReader() {
|
||||
super(null);
|
||||
@@ -154,16 +178,15 @@ public class SystemServicePowerCalculatorTest {
|
||||
}
|
||||
}
|
||||
|
||||
private static class MockUserInfoProvider extends BatteryStatsImpl.UserInfoProvider {
|
||||
@Nullable
|
||||
private static class FakeCpuPowerCalculator extends PowerCalculator {
|
||||
@Override
|
||||
protected int[] getUserIds() {
|
||||
return new int[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(int userId) {
|
||||
return true;
|
||||
protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
|
||||
long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
|
||||
if (u.getUid() == Process.SYSTEM_UID) {
|
||||
// SystemServer must be attributed at least as much power as the total
|
||||
// of all system services requested by apps.
|
||||
app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, 1000000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user