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

Commit 3b367873 authored by Dmitri Plotnikov's avatar Dmitri Plotnikov Committed by Android (Google) Code Review
Browse files

Merge "Update CpuPowerCalculator to do per process state attribution"

parents 2c71e418 f4f95283
Loading
Loading
Loading
Loading
+5 −0
Original line number Original line Diff line number Diff line
@@ -756,6 +756,11 @@ public abstract class BatteryConsumer {
            mPowerComponentsBuilder = new PowerComponents.Builder(data);
            mPowerComponentsBuilder = new PowerComponents.Builder(data);
        }
        }


        @Nullable
        public Key[] getKeys(@PowerComponent int componentId) {
            return mData.getKeys(componentId);
        }

        @Nullable
        @Nullable
        public Key getKey(@PowerComponent int componentId, @ProcessState int processState) {
        public Key getKey(@PowerComponent int componentId, @ProcessState int processState) {
            return mData.getKey(componentId, processState);
            return mData.getKey(componentId, processState);
+11 −0
Original line number Original line Diff line number Diff line
@@ -660,6 +660,7 @@ public abstract class BatteryStats implements Parcelable {
            mapUidProcessStateToBatteryConsumerProcessState(int processState) {
            mapUidProcessStateToBatteryConsumerProcessState(int processState) {
        switch (processState) {
        switch (processState) {
            case BatteryStats.Uid.PROCESS_STATE_TOP:
            case BatteryStats.Uid.PROCESS_STATE_TOP:
            case BatteryStats.Uid.PROCESS_STATE_FOREGROUND:
                return BatteryConsumer.PROCESS_STATE_FOREGROUND;
                return BatteryConsumer.PROCESS_STATE_FOREGROUND;
            case BatteryStats.Uid.PROCESS_STATE_BACKGROUND:
            case BatteryStats.Uid.PROCESS_STATE_BACKGROUND:
            case BatteryStats.Uid.PROCESS_STATE_TOP_SLEEPING:
            case BatteryStats.Uid.PROCESS_STATE_TOP_SLEEPING:
@@ -1027,6 +1028,16 @@ public abstract class BatteryStats implements Parcelable {
         */
         */
        public abstract long getCpuMeasuredBatteryConsumptionUC();
        public abstract long getCpuMeasuredBatteryConsumptionUC();


        /**
         * Returns the battery consumption (in microcoulombs) of the uid's cpu usage when in the
         * specified process state.
         * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
         *
         * {@hide}
         */
        public abstract long getCpuMeasuredBatteryConsumptionUC(
                @BatteryConsumer.ProcessState int processState);

        /**
        /**
         * Returns the battery consumption (in microcoulombs) of the uid's GNSS usage, derived from
         * Returns the battery consumption (in microcoulombs) of the uid's GNSS usage, derived from
         * on device power measurement data.
         * on device power measurement data.
+4 −0
Original line number Original line Diff line number Diff line
@@ -111,6 +111,10 @@ public final class BatteryUsageStatsQuery implements Parcelable {
        return (mFlags & FLAG_BATTERY_USAGE_STATS_POWER_PROFILE_MODEL) != 0;
        return (mFlags & FLAG_BATTERY_USAGE_STATS_POWER_PROFILE_MODEL) != 0;
    }
    }


    public boolean isProcessStateDataNeeded() {
        return (mFlags & FLAG_BATTERY_USAGE_STATS_INCLUDE_PROCESS_STATE_DATA) != 0;
    }

    /**
    /**
     * Returns the client's tolerance for stale battery stats. The data is allowed to be up to
     * Returns the client's tolerance for stale battery stats. The data is allowed to be up to
     * this many milliseconds out-of-date.
     * this many milliseconds out-of-date.
+28 −0
Original line number Original line Diff line number Diff line
@@ -588,6 +588,10 @@ public class BatteryStatsImpl extends BatteryStats {
                    procState = u.mProcessState;
                    procState = u.mProcessState;
                }
                }
                if (procState == ActivityManager.PROCESS_STATE_NONEXISTENT) {
                    continue;
                }
                final long timestampMs = mClock.elapsedRealtime();
                final long timestampMs = mClock.elapsedRealtime();
                final LongArrayMultiStateCounter onBatteryCounter =
                final LongArrayMultiStateCounter onBatteryCounter =
                        u.getProcStateTimeCounter().getCounter();
                        u.getProcStateTimeCounter().getCounter();
@@ -8599,6 +8603,23 @@ public class BatteryStatsImpl extends BatteryStats {
            return mUidMeasuredEnergyStats.getAccumulatedStandardBucketCharge(bucket);
            return mUidMeasuredEnergyStats.getAccumulatedStandardBucketCharge(bucket);
        }
        }
        /**
         * Returns the battery consumption (in microcoulombs) of this uid for a standard power
         * bucket and a process state, such as Uid.PROCESS_STATE_TOP.
         */
        @GuardedBy("mBsi")
        public long getMeasuredBatteryConsumptionUC(@StandardPowerBucket int bucket,
                int processState) {
            if (mBsi.mGlobalMeasuredEnergyStats == null
                    || !mBsi.mGlobalMeasuredEnergyStats.isStandardBucketSupported(bucket)) {
                return POWER_DATA_UNAVAILABLE;
            }
            if (mUidMeasuredEnergyStats == null) {
                return 0L; // It is supported, but was never filled, so it must be 0
            }
            return mUidMeasuredEnergyStats.getAccumulatedStandardBucketCharge(bucket, processState);
        }
        @GuardedBy("mBsi")
        @GuardedBy("mBsi")
        @Override
        @Override
        public long[] getCustomConsumerMeasuredBatteryConsumptionUC() {
        public long[] getCustomConsumerMeasuredBatteryConsumptionUC() {
@@ -8625,6 +8646,13 @@ public class BatteryStatsImpl extends BatteryStats {
        }
        }
        @GuardedBy("mBsi")
        @GuardedBy("mBsi")
        @Override
        public long getCpuMeasuredBatteryConsumptionUC(
                @BatteryConsumer.ProcessState int processState) {
            return getMeasuredBatteryConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_CPU,
                    processState);
        }
        @Override
        @Override
        public long getGnssMeasuredBatteryConsumptionUC() {
        public long getGnssMeasuredBatteryConsumptionUC() {
            return getMeasuredBatteryConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_GNSS);
            return getMeasuredBatteryConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_GNSS);
+121 −29
Original line number Original line Diff line number Diff line
@@ -25,11 +25,13 @@ import android.util.ArrayMap;
import android.util.Log;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseArray;


import java.util.Arrays;
import java.util.List;
import java.util.List;


public class CpuPowerCalculator extends PowerCalculator {
public class CpuPowerCalculator extends PowerCalculator {
    private static final String TAG = "CpuPowerCalculator";
    private static final String TAG = "CpuPowerCalculator";
    private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
    private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
    private static final BatteryConsumer.Key[] UNINITIALIZED_KEYS = new BatteryConsumer.Key[0];
    private final int mNumCpuClusters;
    private final int mNumCpuClusters;


    // Time-in-state based CPU power estimation model computes the estimated power
    // Time-in-state based CPU power estimation model computes the estimated power
@@ -44,13 +46,16 @@ public class CpuPowerCalculator extends PowerCalculator {
    private final UsageBasedPowerEstimator[] mPerClusterPowerEstimators;
    private final UsageBasedPowerEstimator[] mPerClusterPowerEstimators;
    // Multiple estimators per cluster: one per available scaling frequency. Note that different
    // Multiple estimators per cluster: one per available scaling frequency. Note that different
    // clusters have different sets of frequencies and corresponding power consumption averages.
    // clusters have different sets of frequencies and corresponding power consumption averages.
    private final UsageBasedPowerEstimator[][] mPerCpuFreqPowerEstimators;
    private final UsageBasedPowerEstimator[][] mPerCpuFreqPowerEstimatorsByCluster;
    // Flattened array of estimators across clusters
    private final UsageBasedPowerEstimator[] mPerCpuFreqPowerEstimators;


    private static class Result {
    private static class Result {
        public long durationMs;
        public long durationMs;
        public double powerMah;
        public double powerMah;
        public long durationFgMs;
        public long durationFgMs;
        public String packageWithHighestDrain;
        public String packageWithHighestDrain;
        public double[] perProcStatePowerMah;
    }
    }


    public CpuPowerCalculator(PowerProfile profile) {
    public CpuPowerCalculator(PowerProfile profile) {
@@ -65,14 +70,23 @@ public class CpuPowerCalculator extends PowerCalculator {
                    profile.getAveragePowerForCpuCluster(cluster));
                    profile.getAveragePowerForCpuCluster(cluster));
        }
        }


        mPerCpuFreqPowerEstimators = new UsageBasedPowerEstimator[mNumCpuClusters][];
        int freqCount = 0;
        for (int cluster = 0; cluster < mNumCpuClusters; cluster++) {
            freqCount += profile.getNumSpeedStepsInCpuCluster(cluster);
        }

        mPerCpuFreqPowerEstimatorsByCluster = new UsageBasedPowerEstimator[mNumCpuClusters][];
        mPerCpuFreqPowerEstimators = new UsageBasedPowerEstimator[freqCount];
        int index = 0;
        for (int cluster = 0; cluster < mNumCpuClusters; cluster++) {
        for (int cluster = 0; cluster < mNumCpuClusters; cluster++) {
            final int speedsForCluster = profile.getNumSpeedStepsInCpuCluster(cluster);
            final int speedsForCluster = profile.getNumSpeedStepsInCpuCluster(cluster);
            mPerCpuFreqPowerEstimators[cluster] = new UsageBasedPowerEstimator[speedsForCluster];
            mPerCpuFreqPowerEstimatorsByCluster[cluster] =
                    new UsageBasedPowerEstimator[speedsForCluster];
            for (int speed = 0; speed < speedsForCluster; speed++) {
            for (int speed = 0; speed < speedsForCluster; speed++) {
                mPerCpuFreqPowerEstimators[cluster][speed] =
                final UsageBasedPowerEstimator estimator = new UsageBasedPowerEstimator(
                        new UsageBasedPowerEstimator(
                        profile.getAveragePowerForCpuCore(cluster, speed));
                        profile.getAveragePowerForCpuCore(cluster, speed));
                mPerCpuFreqPowerEstimatorsByCluster[cluster][speed] = estimator;
                mPerCpuFreqPowerEstimators[index++] = estimator;
            }
            }
        }
        }
    }
    }
@@ -82,12 +96,20 @@ public class CpuPowerCalculator extends PowerCalculator {
            long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
            long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
        double totalPowerMah = 0;
        double totalPowerMah = 0;


        BatteryConsumer.Key[] keys = UNINITIALIZED_KEYS;
        Result result = new Result();
        Result result = new Result();
        final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =
        final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =
                builder.getUidBatteryConsumerBuilders();
                builder.getUidBatteryConsumerBuilders();
        for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
        for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
            final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
            final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
            calculateApp(app, app.getBatteryStatsUid(), query, result);
            if (keys == UNINITIALIZED_KEYS) {
                if (query.isProcessStateDataNeeded()) {
                    keys = app.getKeys(BatteryConsumer.POWER_COMPONENT_CPU);
                } else {
                    keys = null;
                }
            }
            calculateApp(app, app.getBatteryStatsUid(), query, result, keys);
            totalPowerMah += result.powerMah;
            totalPowerMah += result.powerMah;
        }
        }


@@ -105,7 +127,7 @@ public class CpuPowerCalculator extends PowerCalculator {
    }
    }


    private void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
    private void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
            BatteryUsageStatsQuery query, Result result) {
            BatteryUsageStatsQuery query, Result result, BatteryConsumer.Key[] keys) {
        final long consumptionUC = u.getCpuMeasuredBatteryConsumptionUC();
        final long consumptionUC = u.getCpuMeasuredBatteryConsumptionUC();
        final int powerModel = getPowerModel(consumptionUC, query);
        final int powerModel = getPowerModel(consumptionUC, query);
        calculatePowerAndDuration(u, powerModel, consumptionUC, BatteryStats.STATS_SINCE_CHARGED,
        calculatePowerAndDuration(u, powerModel, consumptionUC, BatteryStats.STATS_SINCE_CHARGED,
@@ -114,6 +136,75 @@ public class CpuPowerCalculator extends PowerCalculator {
        app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, result.powerMah, powerModel)
        app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, result.powerMah, powerModel)
                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CPU, result.durationMs)
                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CPU, result.durationMs)
                .setPackageWithHighestDrain(result.packageWithHighestDrain);
                .setPackageWithHighestDrain(result.packageWithHighestDrain);

        if (query.isProcessStateDataNeeded() && keys != null) {
            switch (powerModel) {
                case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY:
                    calculateMeasuredPowerPerProcessState(app, u, keys);
                    break;
                case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
                    calculateModeledPowerPerProcessState(app, u, keys, result);
                    break;
            }
        }
    }

    private void calculateMeasuredPowerPerProcessState(UidBatteryConsumer.Builder app,
            BatteryStats.Uid u, BatteryConsumer.Key[] keys) {
        for (BatteryConsumer.Key key : keys) {
            // The key for "PROCESS_STATE_ANY" has already been populated with the
            // full energy across all states.  We don't want to override it with
            // the energy for "other" states, which excludes the tracked states like
            // foreground, background etc.
            if (key.processState == BatteryConsumer.PROCESS_STATE_ANY) {
                continue;
            }

            final long consumptionUC = u.getCpuMeasuredBatteryConsumptionUC(key.processState);
            if (consumptionUC != 0) {
                app.setConsumedPower(key, uCtoMah(consumptionUC),
                        BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
            }
        }
    }

    private void calculateModeledPowerPerProcessState(UidBatteryConsumer.Builder app,
            BatteryStats.Uid u, BatteryConsumer.Key[] keys, Result result) {
        if (result.perProcStatePowerMah == null) {
            result.perProcStatePowerMah = new double[BatteryConsumer.PROCESS_STATE_COUNT];
        } else {
            Arrays.fill(result.perProcStatePowerMah, 0);
        }

        for (int uidProcState = 0; uidProcState < BatteryStats.Uid.NUM_PROCESS_STATE;
                uidProcState++) {
            @BatteryConsumer.ProcessState int procState =
                    BatteryStats.mapUidProcessStateToBatteryConsumerProcessState(uidProcState);
            if (procState == BatteryConsumer.PROCESS_STATE_ANY) {
                continue;
            }

            // TODO(b/191921016): use per-state CPU active time
            final long cpuActiveTime = 0;
            // TODO(b/191921016): use per-state CPU cluster times
            final long[] cpuClusterTimes = null;

            final long[] cpuFreqTimes = u.getCpuFreqTimes(BatteryStats.STATS_SINCE_CHARGED,
                    uidProcState);
            if (cpuActiveTime != 0 || cpuClusterTimes != null || cpuFreqTimes != null) {
                result.perProcStatePowerMah[procState] += calculateUidModeledPowerMah(u,
                        cpuActiveTime, cpuClusterTimes, cpuFreqTimes);
            }
        }

        for (BatteryConsumer.Key key : keys) {
            if (key.processState == BatteryConsumer.PROCESS_STATE_ANY) {
                continue;
            }

            app.setConsumedPower(key, result.perProcStatePowerMah[key.processState],
                    BatteryConsumer.POWER_MODEL_POWER_PROFILE);
        }
    }
    }


    @Override
    @Override
@@ -205,16 +296,21 @@ public class CpuPowerCalculator extends PowerCalculator {
     * Calculates CPU power consumed by the specified app, using the PowerProfile model.
     * Calculates CPU power consumed by the specified app, using the PowerProfile model.
     */
     */
    public double calculateUidModeledPowerMah(BatteryStats.Uid u, int statsType) {
    public double calculateUidModeledPowerMah(BatteryStats.Uid u, int statsType) {
        return calculateUidModeledPowerMah(u, u.getCpuActiveTime(), u.getCpuClusterTimes(),
                u.getCpuFreqTimes(statsType));
    }

    private double calculateUidModeledPowerMah(BatteryStats.Uid u, long cpuActiveTime,
            long[] cpuClusterTimes, long[] cpuFreqTimes) {
        // Constant battery drain when CPU is active
        // Constant battery drain when CPU is active
        double powerMah = calculateActiveCpuPowerMah(u.getCpuActiveTime());
        double powerMah = calculateActiveCpuPowerMah(cpuActiveTime);


        // Additional per-cluster battery drain
        // Additional per-cluster battery drain
        long[] cpuClusterTimes = u.getCpuClusterTimes();
        if (cpuClusterTimes != null) {
        if (cpuClusterTimes != null) {
            if (cpuClusterTimes.length == mNumCpuClusters) {
            if (cpuClusterTimes.length == mNumCpuClusters) {
                for (int cluster = 0; cluster < mNumCpuClusters; cluster++) {
                for (int cluster = 0; cluster < mNumCpuClusters; cluster++) {
                    double power = calculatePerCpuClusterPowerMah(cluster,
                    final double power = mPerClusterPowerEstimators[cluster]
                            cpuClusterTimes[cluster]);
                            .calculatePower(cpuClusterTimes[cluster]);
                    powerMah += power;
                    powerMah += power;
                    if (DEBUG) {
                    if (DEBUG) {
                        Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster
                        Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster
@@ -228,21 +324,17 @@ public class CpuPowerCalculator extends PowerCalculator {
            }
            }
        }
        }


        // Additional per-frequency battery drain
        if (cpuFreqTimes != null) {
        for (int cluster = 0; cluster < mNumCpuClusters; cluster++) {
            if (cpuFreqTimes.length == mPerCpuFreqPowerEstimators.length) {
            final int speedsForCluster = mPerCpuFreqPowerEstimators[cluster].length;
                for (int i = 0; i < cpuFreqTimes.length; i++) {
            for (int speed = 0; speed < speedsForCluster; speed++) {
                    powerMah += mPerCpuFreqPowerEstimators[i].calculatePower(cpuFreqTimes[i]);
                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;
            } else {
                Log.w(TAG, "UID " + u.getUid() + " CPU freq # mismatch: Power Profile # "
                        + mPerCpuFreqPowerEstimators.length + " actual # " + cpuFreqTimes.length);
            }
            }
        }
        }

        return powerMah;
        return powerMah;
    }
    }


@@ -277,7 +369,7 @@ public class CpuPowerCalculator extends PowerCalculator {
     */
     */
    public double calculatePerCpuFreqPowerMah(int cluster, int speedStep,
    public double calculatePerCpuFreqPowerMah(int cluster, int speedStep,
            long clusterSpeedDurationsMs) {
            long clusterSpeedDurationsMs) {
        return mPerCpuFreqPowerEstimators[cluster][speedStep].calculatePower(
        return mPerCpuFreqPowerEstimatorsByCluster[cluster][speedStep].calculatePower(
                clusterSpeedDurationsMs);
                clusterSpeedDurationsMs);
    }
    }
}
}
Loading