Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ff51356f authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

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

parents aef42e77 02bc36cb
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -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
+10 −0
Original line number Diff line number Diff line
@@ -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];
+56 −42
Original line number Diff line number Diff line
@@ -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));
                    }
                }
        final double powerMah;
        final long consumptionUC = u.getCpuMeasuredBatteryConsumptionUC();
        if (forceUsePowerProfileModel || consumptionUC == BatteryStats.POWER_DATA_UNAVAILABLE) {
            powerMah = calculateUidModeledPowerMah(u, statsType);
        } 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;
            }
            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.
     *
+78 −8
Original line number Diff line number Diff line
@@ -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();
    }
}