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

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

Merge changes from topic "power_stats_aggregation" into main

* changes:
  Add power estimation (energy consumer based) to aggregated stats
  Add EnergyConsumer collection to CpuPowerStatsCollector
  Add power estimation (power-profile based) to aggregated stats
parents a01650e6 fcaf40e8
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -602,6 +602,17 @@ public class BatteryStatsHistory {
        initHistoryBuffer();
    }

    /**
     * Returns the monotonic clock time when the available battery history collection started.
     */
    public long getStartTime() {
        if (!mHistoryFiles.isEmpty()) {
            return mHistoryFiles.get(0).monotonicTimeMs;
        } else {
            return mHistoryBufferStartTime;
        }
    }

    /**
     * Start iterating history files and history buffer.
     *
+93 −54
Original line number Diff line number Diff line
@@ -29,6 +29,8 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.function.Consumer;
import java.util.function.Function;

/**
 * Maintains multidimensional multi-state stats.  States could be something like on-battery (0,1),
@@ -52,13 +54,55 @@ public class MultiStateStats {

        public States(String name, boolean tracked, String... labels) {
            mName = name;
            this.mTracked = tracked;
            this.mLabels = labels;
            mTracked = tracked;
            mLabels = labels;
        }

        public boolean isTracked() {
            return mTracked;
        }

        public String getName() {
            return mName;
        }

        public String[] getLabels() {
            return mLabels;
        }

        /**
         * Iterates over all combinations of tracked states and invokes <code>consumer</code>
         * for each of them.
         */
        public static void forEachTrackedStateCombination(States[] states,
                Consumer<int[]> consumer) {
            forEachTrackedStateCombination(consumer, states, new int[states.length], 0);
        }

        /**
         * Recursive function that does a depth-first traversal of the multi-dimensional
         * state space. Each time the traversal reaches the end of the <code>states</code> array,
         * <code>statesValues</code> contains a unique combination of values for all tracked states.
         * For untracked states, the corresponding values are left as 0.  The end result is
         * that the <code>consumer</code> is invoked for every unique combination of tracked state
         * values.  For example, it may be a sequence of calls like screen-on/power-on,
         * screen-on/power-off, screen-off/power-on, screen-off/power-off.
         */
        private static void forEachTrackedStateCombination(Consumer<int[]> consumer,
                States[] states, int[] statesValues, int stateIndex) {
            if (stateIndex < statesValues.length) {
                if (!states[stateIndex].mTracked) {
                    forEachTrackedStateCombination(consumer, states, statesValues, stateIndex + 1);
                    return;
                }
                for (int i = 0; i < states[stateIndex].mLabels.length; i++) {
                    statesValues[stateIndex] = i;
                    forEachTrackedStateCombination(consumer, states, statesValues, stateIndex + 1);
                }
                return;
            }
            consumer.accept(statesValues);
        }
    }

    /**
@@ -275,6 +319,13 @@ public class MultiStateStats {
        mCounter.getCounts(outValues, mFactory.getSerialState(states));
    }

    /**
     * Updates the stats values for the provided combination of states.
     */
    public void setStats(int[] states, long[] values) {
        mCounter.setValues(mFactory.getSerialState(states), values);
    }

    /**
     * Resets the counters.
     */
@@ -293,24 +344,27 @@ public class MultiStateStats {
     */
    public void writeXml(TypedXmlSerializer serializer) throws IOException {
        long[] tmpArray = new long[mCounter.getArrayLength()];
        writeXmlAllStates(serializer, new int[mFactory.mStates.length], 0, tmpArray);
    }

    private void writeXmlAllStates(TypedXmlSerializer serializer, int[] states, int stateIndex,
            long[] values) throws IOException {
        if (stateIndex < states.length) {
            if (!mFactory.mStates[stateIndex].mTracked) {
                writeXmlAllStates(serializer, states, stateIndex + 1, values);
                return;
        try {
            States.forEachTrackedStateCombination(mFactory.mStates,
                    states -> {
                        try {
                            writeXmlForStates(serializer, states, tmpArray);
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                    });
        } catch (RuntimeException e) {
            if (e.getCause() instanceof IOException) {
                throw (IOException) e.getCause();
            } else {
                throw e;
            }

            for (int i = 0; i < mFactory.mStates[stateIndex].mLabels.length; i++) {
                states[stateIndex] = i;
                writeXmlAllStates(serializer, states, stateIndex + 1, values);
        }
            return;
    }

    private void writeXmlForStates(TypedXmlSerializer serializer, int[] states, long[] values)
            throws IOException {
        mCounter.getCounts(values, mFactory.getSerialState(states));
        boolean nonZero = false;
        for (long value : values) {
@@ -391,25 +445,9 @@ public class MultiStateStats {
    /**
     * Prints the accumulated stats, one line of every combination of states that has data.
     */
    public void dump(PrintWriter pw) {
        long[] tmpArray = new long[mCounter.getArrayLength()];
        dumpAllStates(pw, new int[mFactory.mStates.length], 0, tmpArray);
    }

    private void dumpAllStates(PrintWriter pw, int[] states, int stateIndex, long[] values) {
        if (stateIndex < states.length) {
            if (!mFactory.mStates[stateIndex].mTracked) {
                dumpAllStates(pw, states, stateIndex + 1, values);
                return;
            }

            for (int i = 0; i < mFactory.mStates[stateIndex].mLabels.length; i++) {
                states[stateIndex] = i;
                dumpAllStates(pw, states, stateIndex + 1, values);
            }
            return;
        }

    public void dump(PrintWriter pw, Function<long[], String> statsFormatter) {
        long[] values = new long[mCounter.getArrayLength()];
        States.forEachTrackedStateCombination(mFactory.mStates, states -> {
            mCounter.getCounts(values, mFactory.getSerialState(states));
            boolean nonZero = false;
            for (long value : values) {
@@ -432,7 +470,8 @@ public class MultiStateStats {
                }
            }
            sb.append(" ");
        sb.append(Arrays.toString(values));
            sb.append(statsFormatter.apply(values));
            pw.println(sb);
        });
    }
}
+24 −104
Original line number Diff line number Diff line
@@ -44,7 +44,6 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Locale;

/**
 * Reports power consumption values for various device activities. Reads values from an XML file.
@@ -295,7 +294,7 @@ public class PowerProfile {

    private static final long SUBSYSTEM_FIELDS_MASK = 0xFFFF_FFFF;

    private static final int DEFAULT_CPU_POWER_BRACKET_NUMBER = 3;
    public static final int POWER_BRACKETS_UNSPECIFIED = -1;

    /**
     * A map from Power Use Item to its power consumption.
@@ -361,7 +360,7 @@ public class PowerProfile {
        }
        initCpuClusters();
        initCpuScalingPolicies();
        initCpuPowerBrackets(DEFAULT_CPU_POWER_BRACKET_NUMBER);
        initCpuPowerBrackets();
        initDisplays();
        initModem();
    }
@@ -560,8 +559,7 @@ public class PowerProfile {
    /**
     * Parses or computes CPU power brackets: groups of states with similar power requirements.
     */
    @VisibleForTesting
    public void initCpuPowerBrackets(int defaultCpuPowerBracketNumber) {
    private void initCpuPowerBrackets() {
        boolean anyBracketsSpecified = false;
        boolean allBracketsSpecified = true;
        for (int i = mCpuScalingPolicies.size() - 1; i >= 0; i--) {
@@ -580,8 +578,12 @@ public class PowerProfile {
                    "Power brackets should be specified for all scaling policies or none");
        }

        if (!allBracketsSpecified) {
            mCpuPowerBracketCount = POWER_BRACKETS_UNSPECIFIED;
            return;
        }

        mCpuPowerBracketCount = 0;
        if (allBracketsSpecified) {
        for (int i = mCpuScalingPolicies.size() - 1; i >= 0; i--) {
            int policy = mCpuScalingPolicies.keyAt(i);
            CpuScalingPolicyPower cpuScalingPolicyPower = mCpuScalingPolicies.valueAt(i);
@@ -602,57 +604,6 @@ public class PowerProfile {
            }
        }
        mCpuPowerBracketCount++;
        } else {
            double minPower = Double.MAX_VALUE;
            double maxPower = Double.MIN_VALUE;
            int stateCount = 0;
            for (int i = mCpuScalingPolicies.size() - 1; i >= 0; i--) {
                int policy = mCpuScalingPolicies.keyAt(i);
                CpuScalingPolicyPower cpuScalingPolicyPower = mCpuScalingPolicies.valueAt(i);
                final int steps = cpuScalingPolicyPower.stepPower.length;
                for (int step = 0; step < steps; step++) {
                    final double power = getAveragePowerForCpuScalingStep(policy, step);
                    if (power < minPower) {
                        minPower = power;
                    }
                    if (power > maxPower) {
                        maxPower = power;
                    }
                }
                stateCount += steps;
            }

            if (stateCount <= defaultCpuPowerBracketNumber) {
                mCpuPowerBracketCount = stateCount;
                int bracket = 0;
                for (int i = 0; i < mCpuScalingPolicies.size(); i++) {
                    CpuScalingPolicyPower cpuScalingPolicyPower = mCpuScalingPolicies.valueAt(i);
                    final int steps = cpuScalingPolicyPower.stepPower.length;
                    for (int step = 0; step < steps; step++) {
                        cpuScalingPolicyPower.powerBrackets[step] = bracket++;
                    }
                }
            } else {
                mCpuPowerBracketCount = defaultCpuPowerBracketNumber;
                final double minLogPower = Math.log(minPower);
                final double logBracket = (Math.log(maxPower) - minLogPower)
                        / defaultCpuPowerBracketNumber;

                for (int i = mCpuScalingPolicies.size() - 1; i >= 0; i--) {
                    int policy = mCpuScalingPolicies.keyAt(i);
                    CpuScalingPolicyPower cpuScalingPolicyPower = mCpuScalingPolicies.valueAt(i);
                    final int steps = cpuScalingPolicyPower.stepPower.length;
                    for (int step = 0; step < steps; step++) {
                        final double power = getAveragePowerForCpuScalingStep(policy, step);
                        int bracket = (int) ((Math.log(power) - minLogPower) / logBracket);
                        if (bracket >= defaultCpuPowerBracketNumber) {
                            bracket = defaultCpuPowerBracketNumber - 1;
                        }
                        cpuScalingPolicyPower.powerBrackets[step] = bracket;
                    }
                }
            }
        }
    }

    private static class CpuScalingPolicyPower {
@@ -771,43 +722,12 @@ public class PowerProfile {

    /**
     * Returns the number of CPU power brackets: groups of states with similar power requirements.
     * If power brackets are not specified, returns {@link #POWER_BRACKETS_UNSPECIFIED}
     */
    public int getCpuPowerBracketCount() {
        return mCpuPowerBracketCount;
    }

    /**
     * Description of a CPU power bracket: which cluster/frequency combinations are included.
     */
    public String getCpuPowerBracketDescription(CpuScalingPolicies cpuScalingPolicies,
            int powerBracket) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < mCpuScalingPolicies.size(); i++) {
            int policy = mCpuScalingPolicies.keyAt(i);
            CpuScalingPolicyPower cpuScalingPolicyPower = mCpuScalingPolicies.valueAt(i);
            int[] brackets = cpuScalingPolicyPower.powerBrackets;
            int[] freqs = cpuScalingPolicies.getFrequencies(policy);
            for (int step = 0; step < brackets.length; step++) {
                if (brackets[step] == powerBracket) {
                    if (sb.length() != 0) {
                        sb.append(", ");
                    }
                    if (mCpuScalingPolicies.size() > 1) {
                        sb.append(policy).append('/');
                    }
                    if (step < freqs.length) {
                        sb.append(freqs[step] / 1000);
                    }
                    sb.append('(');
                    sb.append(String.format(Locale.US, "%.1f",
                            getAveragePowerForCpuScalingStep(policy, step)));
                    sb.append(')');
                }
            }
        }
        return sb.toString();
    }

    /**
     * Returns the CPU power bracket corresponding to the specified scaling policy and frequency
     * step
+2 −2
Original line number Diff line number Diff line
@@ -55,12 +55,12 @@ public final class PowerStats {
    private static final int STATS_ARRAY_LENGTH_SHIFT =
            Integer.numberOfTrailingZeros(STATS_ARRAY_LENGTH_MASK);
    public static final int MAX_STATS_ARRAY_LENGTH =
            2 ^ Integer.bitCount(STATS_ARRAY_LENGTH_MASK) - 1;
            (1 << Integer.bitCount(STATS_ARRAY_LENGTH_MASK)) - 1;
    private static final int UID_STATS_ARRAY_LENGTH_MASK = 0x00FF0000;
    private static final int UID_STATS_ARRAY_LENGTH_SHIFT =
            Integer.numberOfTrailingZeros(UID_STATS_ARRAY_LENGTH_MASK);
    public static final int MAX_UID_STATS_ARRAY_LENGTH =
            (2 ^ Integer.bitCount(UID_STATS_ARRAY_LENGTH_MASK)) - 1;
            (1 << Integer.bitCount(UID_STATS_ARRAY_LENGTH_MASK)) - 1;

    /**
     * Descriptor of the stats collected for a given power component (e.g. CPU, WiFi etc).
+0 −66
Original line number Diff line number Diff line
@@ -21,16 +21,12 @@ import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_AMBIENT;
import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_SCREEN_FULL;
import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_SCREEN_ON;

import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

import android.annotation.XmlRes;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.util.SparseArray;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -540,66 +536,4 @@ public class PowerProfileTest {
    private void assertEquals(double expected, double actual) {
        Assert.assertEquals(expected, actual, 0.1);
    }

    @Test
    public void powerBrackets_specifiedInPowerProfile() {
        mProfile.forceInitForTesting(mContext, R.xml.power_profile_test_power_brackets);
        mProfile.initCpuPowerBrackets(8);

        int cpuPowerBracketCount = mProfile.getCpuPowerBracketCount();
        assertThat(cpuPowerBracketCount).isEqualTo(2);
        assertThat(new int[]{
                mProfile.getCpuPowerBracketForScalingStep(0, 0),
                mProfile.getCpuPowerBracketForScalingStep(4, 0),
                mProfile.getCpuPowerBracketForScalingStep(4, 1),
        }).isEqualTo(new int[]{1, 1, 0});
    }

    @Test
    public void powerBrackets_automatic() {
        mProfile.forceInitForTesting(mContext, R.xml.power_profile_test);
        CpuScalingPolicies scalingPolicies = new CpuScalingPolicies(
                new SparseArray<>() {{
                    put(0, new int[]{0, 1, 2});
                    put(3, new int[]{3, 4});
                }},
                new SparseArray<>() {{
                    put(0, new int[]{300000, 1000000, 2000000});
                    put(3, new int[]{300000, 1000000, 2500000, 3000000});
                }});

        assertThat(mProfile.getCpuPowerBracketCount()).isEqualTo(3);
        assertThat(mProfile.getCpuPowerBracketDescription(scalingPolicies, 0))
                .isEqualTo("0/300(10.0)");
        assertThat(mProfile.getCpuPowerBracketDescription(scalingPolicies, 1))
                .isEqualTo("0/1000(20.0), 0/2000(30.0), 3/300(25.0)");
        assertThat(mProfile.getCpuPowerBracketDescription(scalingPolicies, 2))
                .isEqualTo("3/1000(35.0), 3/2500(50.0), 3/3000(60.0)");
        assertThat(new int[]{
                mProfile.getCpuPowerBracketForScalingStep(0, 0),
                mProfile.getCpuPowerBracketForScalingStep(0, 1),
                mProfile.getCpuPowerBracketForScalingStep(0, 2),
                mProfile.getCpuPowerBracketForScalingStep(3, 0),
                mProfile.getCpuPowerBracketForScalingStep(3, 1),
                mProfile.getCpuPowerBracketForScalingStep(3, 2),
                mProfile.getCpuPowerBracketForScalingStep(3, 3),
        }).isEqualTo(new int[]{0, 1, 1, 1, 2, 2, 2});
    }

    @Test
    public void powerBrackets_moreBracketsThanStates() {
        mProfile.forceInitForTesting(mContext, R.xml.power_profile_test);
        mProfile.initCpuPowerBrackets(8);

        assertThat(mProfile.getCpuPowerBracketCount()).isEqualTo(7);
        assertThat(new int[]{
                mProfile.getCpuPowerBracketForScalingStep(0, 0),
                mProfile.getCpuPowerBracketForScalingStep(0, 1),
                mProfile.getCpuPowerBracketForScalingStep(0, 2),
                mProfile.getCpuPowerBracketForScalingStep(3, 0),
                mProfile.getCpuPowerBracketForScalingStep(3, 1),
                mProfile.getCpuPowerBracketForScalingStep(3, 2),
                mProfile.getCpuPowerBracketForScalingStep(3, 3),
        }).isEqualTo(new int[]{0, 1, 2, 3, 4, 5, 6});
    }
}
Loading