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 Diff line number Diff line
@@ -756,6 +756,11 @@ public abstract class BatteryConsumer {
            mPowerComponentsBuilder = new PowerComponents.Builder(data);
        }

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

        @Nullable
        public Key getKey(@PowerComponent int componentId, @ProcessState int processState) {
            return mData.getKey(componentId, processState);
+11 −0
Original line number Diff line number Diff line
@@ -660,6 +660,7 @@ public abstract class BatteryStats implements Parcelable {
            mapUidProcessStateToBatteryConsumerProcessState(int processState) {
        switch (processState) {
            case BatteryStats.Uid.PROCESS_STATE_TOP:
            case BatteryStats.Uid.PROCESS_STATE_FOREGROUND:
                return BatteryConsumer.PROCESS_STATE_FOREGROUND;
            case BatteryStats.Uid.PROCESS_STATE_BACKGROUND:
            case BatteryStats.Uid.PROCESS_STATE_TOP_SLEEPING:
@@ -1027,6 +1028,16 @@ public abstract class BatteryStats implements Parcelable {
         */
        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
         * on device power measurement data.
+4 −0
Original line number 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;
    }

    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
     * this many milliseconds out-of-date.
+28 −0
Original line number Diff line number Diff line
@@ -588,6 +588,10 @@ public class BatteryStatsImpl extends BatteryStats {
                    procState = u.mProcessState;
                }
                if (procState == ActivityManager.PROCESS_STATE_NONEXISTENT) {
                    continue;
                }
                final long timestampMs = mClock.elapsedRealtime();
                final LongArrayMultiStateCounter onBatteryCounter =
                        u.getProcStateTimeCounter().getCounter();
@@ -8599,6 +8603,23 @@ public class BatteryStatsImpl extends BatteryStats {
            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")
        @Override
        public long[] getCustomConsumerMeasuredBatteryConsumptionUC() {
@@ -8625,6 +8646,13 @@ public class BatteryStatsImpl extends BatteryStats {
        }
        @GuardedBy("mBsi")
        @Override
        public long getCpuMeasuredBatteryConsumptionUC(
                @BatteryConsumer.ProcessState int processState) {
            return getMeasuredBatteryConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_CPU,
                    processState);
        }
        @Override
        public long getGnssMeasuredBatteryConsumptionUC() {
            return getMeasuredBatteryConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_GNSS);
+121 −29
Original line number Diff line number Diff line
@@ -25,11 +25,13 @@ import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseArray;

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

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

    // 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;
    // Multiple estimators per cluster: one per available scaling frequency. Note that different
    // 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 {
        public long durationMs;
        public double powerMah;
        public long durationFgMs;
        public String packageWithHighestDrain;
        public double[] perProcStatePowerMah;
    }

    public CpuPowerCalculator(PowerProfile profile) {
@@ -65,14 +70,23 @@ public class CpuPowerCalculator extends PowerCalculator {
                    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++) {
            final int speedsForCluster = profile.getNumSpeedStepsInCpuCluster(cluster);
            mPerCpuFreqPowerEstimators[cluster] = new UsageBasedPowerEstimator[speedsForCluster];
            mPerCpuFreqPowerEstimatorsByCluster[cluster] =
                    new UsageBasedPowerEstimator[speedsForCluster];
            for (int speed = 0; speed < speedsForCluster; speed++) {
                mPerCpuFreqPowerEstimators[cluster][speed] =
                        new UsageBasedPowerEstimator(
                final UsageBasedPowerEstimator estimator = new UsageBasedPowerEstimator(
                        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) {
        double totalPowerMah = 0;

        BatteryConsumer.Key[] keys = UNINITIALIZED_KEYS;
        Result result = new Result();
        final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =
                builder.getUidBatteryConsumerBuilders();
        for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; 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;
        }

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

    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 int powerModel = getPowerModel(consumptionUC, query);
        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)
                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CPU, result.durationMs)
                .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
@@ -205,16 +296,21 @@ public class CpuPowerCalculator extends PowerCalculator {
     * Calculates CPU power consumed by the specified app, using the PowerProfile model.
     */
    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
        double powerMah = calculateActiveCpuPowerMah(u.getCpuActiveTime());
        double powerMah = calculateActiveCpuPowerMah(cpuActiveTime);

        // 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]);
                    final double power = mPerClusterPowerEstimators[cluster]
                            .calculatePower(cpuClusterTimes[cluster]);
                    powerMah += power;
                    if (DEBUG) {
                        Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster
@@ -228,21 +324,17 @@ public class CpuPowerCalculator extends PowerCalculator {
            }
        }

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

        return powerMah;
    }

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