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

Commit ec82dbfd authored by Dmitri Plotnikov's avatar Dmitri Plotnikov
Browse files

Add CPU power brackets to PowerProfile

Bug: 244623253
Test: atest com.android.internal.os.PowerProfileTest

Change-Id: I9757577fa526c40fc09af073a2d6eb0aa1db9501
parent b0ac7831
Loading
Loading
Loading
Loading
+153 −6
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ 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.
@@ -315,6 +316,8 @@ public class PowerProfile {

    private static final Object sLock = new Object();

    private int mCpuPowerBracketCount;

    @VisibleForTesting
    @UnsupportedAppUsage
    public PowerProfile(Context context) {
@@ -346,7 +349,6 @@ public class PowerProfile {
            sModemPowerProfile.clear();
            initLocked(context, xmlId);
        }

    }

    @GuardedBy("sLock")
@@ -450,6 +452,9 @@ public class PowerProfile {
    private static final String CPU_CLUSTER_POWER_COUNT = "cpu.cluster_power.cluster";
    private static final String CPU_CORE_SPEED_PREFIX = "cpu.core_speeds.cluster";
    private static final String CPU_CORE_POWER_PREFIX = "cpu.core_power.cluster";
    private static final String CPU_POWER_BRACKETS_PREFIX = "cpu.power_brackets.cluster";

    private static final int DEFAULT_CPU_POWER_BRACKET_NUMBER = 3;

    private void initCpuClusters() {
        if (sPowerArrayMap.containsKey(CPU_PER_CLUSTER_CORE_COUNT)) {
@@ -471,13 +476,104 @@ public class PowerProfile {
            mCpuClusters[0] = new CpuClusterKey(CPU_CORE_SPEED_PREFIX + 0,
                    CPU_CLUSTER_POWER_COUNT + 0, CPU_CORE_POWER_PREFIX + 0, numCpus);
        }

        initCpuPowerBrackets(DEFAULT_CPU_POWER_BRACKET_NUMBER);
    }

    /**
     * Parses or computes CPU power brackets: groups of states with similar power requirements.
     */
    @VisibleForTesting
    public void initCpuPowerBrackets(int defaultCpuPowerBracketNumber) {
        boolean anyBracketsSpecified = false;
        boolean allBracketsSpecified = true;
        for (int cluster = 0; cluster < mCpuClusters.length; cluster++) {
            final int steps = getNumSpeedStepsInCpuCluster(cluster);
            mCpuClusters[cluster].powerBrackets = new int[steps];
            if (sPowerArrayMap.get(CPU_POWER_BRACKETS_PREFIX + cluster) != null) {
                anyBracketsSpecified = true;
            } else {
                allBracketsSpecified = false;
            }
        }

        if (anyBracketsSpecified && !allBracketsSpecified) {
            throw new RuntimeException(
                    "Power brackets should be specified for all clusters or no clusters");
        }

        mCpuPowerBracketCount = 0;
        if (allBracketsSpecified) {
            for (int cluster = 0; cluster < mCpuClusters.length; cluster++) {
                final Double[] data = sPowerArrayMap.get(CPU_POWER_BRACKETS_PREFIX + cluster);
                if (data.length != mCpuClusters[cluster].powerBrackets.length) {
                    throw new RuntimeException(
                            "Wrong number of items in " + CPU_POWER_BRACKETS_PREFIX + cluster);
                }

                for (int i = 0; i < data.length; i++) {
                    final int bracket = (int) Math.round(data[i]);
                    mCpuClusters[cluster].powerBrackets[i] = bracket;
                    if (bracket > mCpuPowerBracketCount) {
                        mCpuPowerBracketCount = bracket;
                    }
                }
            }
            mCpuPowerBracketCount++;
        } else {
            double minPower = Double.MAX_VALUE;
            double maxPower = Double.MIN_VALUE;
            int stateCount = 0;
            for (int cluster = 0; cluster < mCpuClusters.length; cluster++) {
                final int steps = getNumSpeedStepsInCpuCluster(cluster);
                for (int step = 0; step < steps; step++) {
                    final double power = getAveragePowerForCpuCore(cluster, step);
                    if (power < minPower) {
                        minPower = power;
                    }
                    if (power > maxPower) {
                        maxPower = power;
                    }
                }
                stateCount += steps;
            }

            if (stateCount <= defaultCpuPowerBracketNumber) {
                mCpuPowerBracketCount = stateCount;
                int bracket = 0;
                for (int cluster = 0; cluster < mCpuClusters.length; cluster++) {
                    final int steps = getNumSpeedStepsInCpuCluster(cluster);
                    for (int step = 0; step < steps; step++) {
                        mCpuClusters[cluster].powerBrackets[step] = bracket++;
                    }
                }
            } else {
                mCpuPowerBracketCount = defaultCpuPowerBracketNumber;
                final double minLogPower = Math.log(minPower);
                final double logBracket = (Math.log(maxPower) - minLogPower)
                        / defaultCpuPowerBracketNumber;

                for (int cluster = 0; cluster < mCpuClusters.length; cluster++) {
                    final int steps = getNumSpeedStepsInCpuCluster(cluster);
                    for (int step = 0; step < steps; step++) {
                        final double power = getAveragePowerForCpuCore(cluster, step);
                        int bracket = (int) ((Math.log(power) - minLogPower) / logBracket);
                        if (bracket >= defaultCpuPowerBracketNumber) {
                            bracket = defaultCpuPowerBracketNumber - 1;
                        }
                        mCpuClusters[cluster].powerBrackets[step] = bracket;
                    }
                }
            }
        }
    }

    public static class CpuClusterKey {
        private final String freqKey;
        private final String clusterPowerKey;
        private final String corePowerKey;
        private final int numCpus;
    private static class CpuClusterKey {
        public final String freqKey;
        public final String clusterPowerKey;
        public final String corePowerKey;
        public final int numCpus;
        public int[] powerBrackets;

        private CpuClusterKey(String freqKey, String clusterPowerKey,
                String corePowerKey, int numCpus) {
@@ -525,6 +621,57 @@ public class PowerProfile {
        return 0;
    }

    /**
     * Returns the number of CPU power brackets: groups of states with similar power requirements.
     */
    public int getCpuPowerBracketCount() {
        return mCpuPowerBracketCount;
    }

    /**
     * Description of a CPU power bracket: which cluster/frequency combinations are included.
     */
    public String getCpuPowerBracketDescription(int powerBracket) {
        StringBuilder sb = new StringBuilder();
        for (int cluster = 0; cluster < mCpuClusters.length; cluster++) {
            int[] brackets = mCpuClusters[cluster].powerBrackets;
            for (int step = 0; step < brackets.length; step++) {
                if (brackets[step] == powerBracket) {
                    if (sb.length() != 0) {
                        sb.append(", ");
                    }
                    if (mCpuClusters.length > 1) {
                        sb.append(cluster).append('/');
                    }
                    Double[] freqs = sPowerArrayMap.get(mCpuClusters[cluster].freqKey);
                    if (freqs != null && step < freqs.length) {
                        // Frequency in MHz
                        sb.append(freqs[step].intValue() / 1000);
                    }
                    sb.append('(');
                    sb.append(String.format(Locale.US, "%.1f",
                            getAveragePowerForCpuCore(cluster, step)));
                    sb.append(')');
                }
            }
        }
        return sb.toString();
    }

    /**
     * Returns the CPU power bracket corresponding to the specified cluster and frequency step
     */
    public int getPowerBracketForCpuCore(int cluster, int step) {
        if (cluster >= 0
                && cluster < mCpuClusters.length
                && step >= 0
                && step < mCpuClusters[cluster].powerBrackets.length) {
            return mCpuClusters[cluster].powerBrackets[step];
        }
        return 0;
    }


    private int mNumDisplays;

    private void initDisplays() {
+51 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ Copyright (C) 2022 The Android Open Source Project
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~      http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  -->

<device name="Android">

    <array name="cpu.clusters.cores">
        <value>1</value>
        <value>2</value>
    </array>

    <array name="cpu.core_speeds.cluster0">
        <value>300000</value>
    </array>

    <array name="cpu.core_speeds.cluster1">
        <value>300000</value>
        <value>1000000</value>
    </array>

    <array name="cpu.core_power.cluster0">
        <value>10</value>
    </array>

    <array name="cpu.core_power.cluster1">
        <value>25</value>
        <value>35</value>
    </array>

    <array name="cpu.power_brackets.cluster0">
        <value>1</value>
    </array>

    <array name="cpu.power_brackets.cluster1">
        <value>1</value>
        <value>0</value>
    </array>
</device>
+72 −3
Original line number Diff line number Diff line
@@ -21,6 +21,11 @@ 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;
@@ -28,15 +33,16 @@ import android.content.res.XmlResourceParser;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import com.android.frameworks.coretests.R;
import com.android.internal.power.ModemPowerProfile;
import com.android.internal.util.XmlUtils;

import junit.framework.TestCase;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

/*
 * Keep this file in sync with frameworks/base/core/res/res/xml/power_profile_test.xml and
@@ -46,7 +52,8 @@ import org.junit.Test;
 *     atest com.android.internal.os.PowerProfileTest
 */
@SmallTest
public class PowerProfileTest extends TestCase {
@RunWith(AndroidJUnit4.class)
public class PowerProfileTest {

    static final String TAG_TEST_MODEM = "test-modem";
    static final String ATTR_NAME = "name";
@@ -516,4 +523,66 @@ public class PowerProfileTest extends TestCase {
        fail("Unanable to find element " + element + " with name " + elementName);
        return null;
    }

    private void assertEquals(int expected, int actual) {
        Assert.assertEquals(expected, actual);
    }

    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.getPowerBracketForCpuCore(0, 0),
                mProfile.getPowerBracketForCpuCore(1, 0),
                mProfile.getPowerBracketForCpuCore(1, 1),
        }).isEqualTo(new int[]{1, 1, 0});
    }

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

        assertThat(mProfile.getCpuPowerBracketCount()).isEqualTo(3);
        assertThat(mProfile.getCpuPowerBracketDescription(0))
                .isEqualTo("0/300(10.0)");
        assertThat(mProfile.getCpuPowerBracketDescription(1))
                .isEqualTo("0/1000(20.0), 0/2000(30.0), 1/300(25.0)");
        assertThat(mProfile.getCpuPowerBracketDescription(2))
                .isEqualTo("1/1000(35.0), 1/2500(50.0), 1/3000(60.0)");
        assertThat(new int[]{
                mProfile.getPowerBracketForCpuCore(0, 0),
                mProfile.getPowerBracketForCpuCore(0, 1),
                mProfile.getPowerBracketForCpuCore(0, 2),
                mProfile.getPowerBracketForCpuCore(1, 0),
                mProfile.getPowerBracketForCpuCore(1, 1),
                mProfile.getPowerBracketForCpuCore(1, 2),
                mProfile.getPowerBracketForCpuCore(1, 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.getPowerBracketForCpuCore(0, 0),
                mProfile.getPowerBracketForCpuCore(0, 1),
                mProfile.getPowerBracketForCpuCore(0, 2),
                mProfile.getPowerBracketForCpuCore(1, 0),
                mProfile.getPowerBracketForCpuCore(1, 1),
                mProfile.getPowerBracketForCpuCore(1, 2),
                mProfile.getPowerBracketForCpuCore(1, 3),
        }).isEqualTo(new int[]{0, 1, 2, 3, 4, 5, 6});
    }
}
+15 −0
Original line number Diff line number Diff line
@@ -14965,6 +14965,18 @@ public class BatteryStatsImpl extends BatteryStats {
        }
    }
    @GuardedBy("this")
    private void dumpCpuPowerBracketsLocked(PrintWriter pw) {
        pw.println("CPU power brackets; cluster/freq in MHz(avg current in mA):");
        final int bracketCount = mPowerProfile.getCpuPowerBracketCount();
        for (int bracket = 0; bracket < bracketCount; bracket++) {
            pw.print("    ");
            pw.print(bracket);
            pw.print(": ");
            pw.println(mPowerProfile.getCpuPowerBracketDescription(bracket));
        }
    }
    /**
     * Dump measured charge stats
     */
@@ -16296,6 +16308,9 @@ public class BatteryStatsImpl extends BatteryStats {
        pw.println();
        dumpConstantsLocked(pw);
        pw.println();
        dumpCpuPowerBracketsLocked(pw);
        pw.println();
        dumpMeasuredEnergyStatsLocked(pw);
    }