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

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

Merge "Update CpuInfoReader to compute normalized available CPU frequency."

parents 8835c0a7 67bc8812
Loading
Loading
Loading
Loading
+146 −13
Original line number Diff line number Diff line
@@ -21,8 +21,10 @@ import static com.android.server.cpu.CpuMonitorService.TAG;

import android.annotation.IntDef;
import android.annotation.Nullable;
import android.os.SystemClock;
import android.system.Os;
import android.system.OsConstants;
import android.util.IndentingPrintWriter;
import android.util.IntArray;
import android.util.LongSparseLongArray;
import android.util.SparseArray;
@@ -50,6 +52,9 @@ public final class CpuInfoReader {
    private static final String POLICY_DIR_PREFIX = "policy";
    private static final String RELATED_CPUS_FILE = "related_cpus";
    private static final String AFFECTED_CPUS_FILE = "affected_cpus";
    // TODO(b/263154344): Avoid reading from cpuinfo_cur_freq because non-root users don't have
    //  read permission for this file. The file permissions are set by the Kernel. Instead, read
    //  the current frequency only from scaling_cur_freq.
    private static final String CUR_CPUFREQ_FILE = "cpuinfo_cur_freq";
    private static final String MAX_CPUFREQ_FILE = "cpuinfo_max_freq";
    private static final String CUR_SCALING_FREQ_FILE = "scaling_cur_freq";
@@ -70,16 +75,18 @@ public final class CpuInfoReader {
    private static final Pattern TIME_IN_STATE_PATTERN =
            Pattern.compile("(?<freqKHz>[0-9]+)\\s(?<time>[0-9]+)");
    private static final long MILLIS_PER_CLOCK_TICK = 1000L / Os.sysconf(OsConstants._SC_CLK_TCK);
    private static final long MIN_READ_INTERVAL_MILLISECONDS = 500;

    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = {"FLAG_CPUSET_CATEGORY_"}, flag = true, value = {
            FLAG_CPUSET_CATEGORY_TOP_APP,
            FLAG_CPUSET_CATEGORY_BACKGROUND
    })
    private @interface CpusetCategory{}
    /** package **/ @interface CpusetCategory{}

    // TODO(b/242722241): Protect updatable variables with a local lock.
    private final File mCpusetDir;
    private final long mMinReadIntervalMillis;
    private final SparseIntArray mCpusetCategoriesByCpus = new SparseIntArray();
    private final SparseArray<File> mCpuFreqPolicyDirsById = new SparseArray<>();
    private final SparseArray<StaticPolicyInfo> mStaticPolicyInfoById = new SparseArray<>();
@@ -90,16 +97,20 @@ public final class CpuInfoReader {
    private SparseArray<CpuUsageStats> mCumulativeCpuUsageStats = new SparseArray<>();
    private boolean mIsEnabled;
    private boolean mHasTimeInStateFile;
    private long mLastReadUptimeMillis;
    private SparseArray<CpuInfo> mLastReadCpuInfos;

    public CpuInfoReader() {
        this(new File(CPUSET_DIR_PATH), new File(CPUFREQ_DIR_PATH), new File(PROC_STAT_FILE_PATH));
        this(new File(CPUSET_DIR_PATH), new File(CPUFREQ_DIR_PATH), new File(PROC_STAT_FILE_PATH),
                MIN_READ_INTERVAL_MILLISECONDS);
    }

    @VisibleForTesting
    CpuInfoReader(File cpusetDir, File cpuFreqDir, File procStatFile) {
    CpuInfoReader(File cpusetDir, File cpuFreqDir, File procStatFile, long minReadIntervalMillis) {
        mCpusetDir = cpusetDir;
        mCpuFreqDir = cpuFreqDir;
        mProcStatFile = procStatFile;
        mMinReadIntervalMillis = minReadIntervalMillis;
    }

    /**
@@ -167,6 +178,16 @@ public final class CpuInfoReader {
        if (!mIsEnabled) {
            return null;
        }
        long uptimeMillis = SystemClock.uptimeMillis();
        if (mLastReadUptimeMillis > 0
                && uptimeMillis - mLastReadUptimeMillis < mMinReadIntervalMillis) {
            Slogf.w(TAG, "Skipping reading from device and returning the last read CpuInfos. "
                    + "Last read was %d ms ago, min read interval is %d ms",
                    uptimeMillis - mLastReadUptimeMillis, mMinReadIntervalMillis);
            return mLastReadCpuInfos;
        }
        mLastReadUptimeMillis = uptimeMillis;
        mLastReadCpuInfos = null;
        SparseArray<CpuUsageStats> cpuUsageStatsByCpus = readLatestCpuUsageStats();
        if (cpuUsageStatsByCpus == null || cpuUsageStatsByCpus.size() == 0) {
            Slogf.e(TAG, "Failed to read latest CPU usage stats");
@@ -202,6 +223,12 @@ public final class CpuInfoReader {
                        + " policy ID %d", policyId);
                continue;
            }
            if (curFreqKHz > maxFreqKHz) {
                Slogf.w(TAG, "Current CPU frequency (%d) is greater than maximum CPU frequency"
                        + " (%d) for policy ID (%d). Skipping CPU frequency policy", curFreqKHz,
                        maxFreqKHz, policyId);
                continue;
            }
            for (int coreIdx = 0; coreIdx < staticPolicyInfo.relatedCpuCores.size(); coreIdx++) {
                int relatedCpuCore = staticPolicyInfo.relatedCpuCores.get(coreIdx);
                CpuInfo prevCpuInfo = cpuInfoByCpus.get(relatedCpuCore);
@@ -241,9 +268,73 @@ public final class CpuInfoReader {
                }
            }
        }
        mLastReadCpuInfos = cpuInfoByCpus;
        return cpuInfoByCpus;
    }

    /** Dumps the current state. */
    public void dump(IndentingPrintWriter writer) {
        writer.printf("*%s*\n", getClass().getSimpleName());
        writer.increaseIndent();    // Add intend for the outermost block.

        writer.printf("mCpusetDir = %s\n", mCpusetDir.getAbsolutePath());
        writer.printf("mCpuFreqDir = %s\n", mCpuFreqDir.getAbsolutePath());
        writer.printf("mProcStatFile = %s\n", mProcStatFile.getAbsolutePath());
        writer.printf("mIsEnabled = %s\n", mIsEnabled);
        writer.printf("mHasTimeInStateFile = %s\n", mHasTimeInStateFile);
        writer.printf("mLastReadUptimeMillis = %d\n", mLastReadUptimeMillis);
        writer.printf("mMinReadIntervalMillis = %d\n", mMinReadIntervalMillis);

        writer.printf("Cpuset categories by CPU core:\n");
        writer.increaseIndent();
        for (int i = 0; i < mCpusetCategoriesByCpus.size(); i++) {
            writer.printf("CPU core id = %d, %s\n", mCpusetCategoriesByCpus.keyAt(i),
                    toCpusetCategoriesStr(mCpusetCategoriesByCpus.valueAt(i)));
        }
        writer.decreaseIndent();

        writer.println("Cpu frequency policy directories by policy id:");
        writer.increaseIndent();
        for (int i = 0; i < mCpuFreqPolicyDirsById.size(); i++) {
            writer.printf("Policy id = %d, Dir = %s\n", mCpuFreqPolicyDirsById.keyAt(i),
                    mCpuFreqPolicyDirsById.valueAt(i));
        }
        writer.decreaseIndent();

        writer.println("Static cpu frequency policy infos by policy id:");
        writer.increaseIndent();
        for (int i = 0; i < mStaticPolicyInfoById.size(); i++) {
            writer.printf("Policy id = %d, %s\n", mStaticPolicyInfoById.keyAt(i),
                    mStaticPolicyInfoById.valueAt(i));
        }
        writer.decreaseIndent();

        writer.println("Cpu time in frequency state by policy id:");
        writer.increaseIndent();
        for (int i = 0; i < mTimeInStateByPolicyId.size(); i++) {
            writer.printf("Policy id = %d, Time(millis) in state by CPU frequency(KHz) = %s\n",
                    mTimeInStateByPolicyId.keyAt(i), mTimeInStateByPolicyId.valueAt(i));
        }
        writer.decreaseIndent();

        writer.println("Last read CPU infos:");
        writer.increaseIndent();
        for (int i = 0; i < mLastReadCpuInfos.size(); i++) {
            writer.printf("%s\n", mLastReadCpuInfos.valueAt(i));
        }
        writer.decreaseIndent();

        writer.println("Latest cumulative CPU usage stats by CPU core:");
        writer.increaseIndent();
        for (int i = 0; i < mCumulativeCpuUsageStats.size(); i++) {
            writer.printf("CPU core id = %d, %s\n", mCumulativeCpuUsageStats.keyAt(i),
                    mCumulativeCpuUsageStats.valueAt(i));
        }
        writer.decreaseIndent();

        writer.decreaseIndent();    // Remove intend for the outermost block.
    }

    /**
     * Sets the CPU frequency for testing.
     *
@@ -496,6 +587,9 @@ public final class CpuInfoReader {
        for (int i = 0; i < timeInState.size(); i++) {
            totalTimeInState += timeInState.valueAt(i);
        }
        if (totalTimeInState == 0) {
            return CpuInfo.MISSING_FREQUENCY;
        }
        double avgFreqKHz = 0;
        for (int i = 0; i < timeInState.size(); i++) {
            avgFreqKHz += (timeInState.keyAt(i) * timeInState.valueAt(i)) / totalTimeInState;
@@ -624,16 +718,29 @@ public final class CpuInfoReader {
        @CpusetCategory
        public final int cpusetCategories;
        public final boolean isOnline;
        public final long maxCpuFreqKHz;
        // Values in the below fields may be missing when a CPU core is offline.
        public final long curCpuFreqKHz;
        public final long maxCpuFreqKHz;
        public final long avgTimeInStateCpuFreqKHz;
        @Nullable
        public final CpuUsageStats latestCpuUsageStats;

        private long mNormalizedAvailableCpuFreqKHz;

        CpuInfo(int cpuCore, @CpusetCategory int cpusetCategories, boolean isOnline,
                long curCpuFreqKHz, long maxCpuFreqKHz, long avgTimeInStateCpuFreqKHz,
                CpuUsageStats latestCpuUsageStats) {
            this(cpuCore, cpusetCategories, isOnline, curCpuFreqKHz, maxCpuFreqKHz,
                    avgTimeInStateCpuFreqKHz, /* normalizedAvailableCpuFreqKHz= */ 0,
                    latestCpuUsageStats);
            this.mNormalizedAvailableCpuFreqKHz = computeNormalizedAvailableCpuFreqKHz();
        }

        // Should be used only for testing.
        @VisibleForTesting
        CpuInfo(int cpuCore, @CpusetCategory int cpusetCategories, boolean isOnline,
                long curCpuFreqKHz, long maxCpuFreqKHz, long avgTimeInStateCpuFreqKHz,
                long normalizedAvailableCpuFreqKHz, CpuUsageStats latestCpuUsageStats) {
            this.cpuCore = cpuCore;
            this.cpusetCategories = cpusetCategories;
            this.isOnline = isOnline;
@@ -641,6 +748,11 @@ public final class CpuInfoReader {
            this.maxCpuFreqKHz = maxCpuFreqKHz;
            this.avgTimeInStateCpuFreqKHz = avgTimeInStateCpuFreqKHz;
            this.latestCpuUsageStats = latestCpuUsageStats;
            this.mNormalizedAvailableCpuFreqKHz = normalizedAvailableCpuFreqKHz;
        }

        public long getNormalizedAvailableCpuFreqKHz() {
            return mNormalizedAvailableCpuFreqKHz;
        }

        @Override
@@ -657,6 +769,8 @@ public final class CpuInfoReader {
                    .append(avgTimeInStateCpuFreqKHz == MISSING_FREQUENCY ? "missing"
                            : avgTimeInStateCpuFreqKHz)
                    .append(", latestCpuUsageStats = ").append(latestCpuUsageStats)
                    .append(", mNormalizedAvailableCpuFreqKHz = ")
                    .append(mNormalizedAvailableCpuFreqKHz)
                    .append(" }").toString();
        }

@@ -673,13 +787,32 @@ public final class CpuInfoReader {
                    && isOnline == other.isOnline  && curCpuFreqKHz == other.curCpuFreqKHz
                    && maxCpuFreqKHz == other.maxCpuFreqKHz
                    && avgTimeInStateCpuFreqKHz == other.avgTimeInStateCpuFreqKHz
                    && latestCpuUsageStats.equals(other.latestCpuUsageStats);
                    && latestCpuUsageStats.equals(other.latestCpuUsageStats)
                    && mNormalizedAvailableCpuFreqKHz == other.mNormalizedAvailableCpuFreqKHz;
        }

        @Override
        public int hashCode() {
            return Objects.hash(cpuCore, cpusetCategories, isOnline, curCpuFreqKHz, maxCpuFreqKHz,
                    avgTimeInStateCpuFreqKHz, latestCpuUsageStats);
                    avgTimeInStateCpuFreqKHz, latestCpuUsageStats, mNormalizedAvailableCpuFreqKHz);
        }

        private long computeNormalizedAvailableCpuFreqKHz() {
            if (!isOnline) {
                return MISSING_FREQUENCY;
            }
            long totalTimeMillis = latestCpuUsageStats.getTotalTimeMillis();
            if (totalTimeMillis == 0) {
                Slogf.wtf(TAG, "Total CPU time millis is 0. This shouldn't happen unless stats are"
                        + " polled too frequently");
                return MISSING_FREQUENCY;
            }
            double nonIdlePercent = 100.0 * (totalTimeMillis
                    - (double) latestCpuUsageStats.idleTimeMillis) / totalTimeMillis;
            long curFreqKHz = avgTimeInStateCpuFreqKHz == MISSING_FREQUENCY
                    ? curCpuFreqKHz : avgTimeInStateCpuFreqKHz;
            double availablePercent = 100.0 - (nonIdlePercent * curFreqKHz / maxCpuFreqKHz);
            return (long) ((availablePercent * maxCpuFreqKHz) / 100.0);
        }
    }

@@ -712,7 +845,7 @@ public final class CpuInfoReader {
            this.guestNiceTimeMillis = guestNiceTimeMillis;
        }

        public long getTotalTime() {
        public long getTotalTimeMillis() {
            return userTimeMillis + niceTimeMillis + systemTimeMillis + idleTimeMillis
                    + iowaitTimeMillis + irqTimeMillis + softirqTimeMillis + stealTimeMillis
                    + guestTimeMillis + guestNiceTimeMillis;
@@ -796,8 +929,8 @@ public final class CpuInfoReader {

        @Override
        public String toString() {
            return "FrequencyPair{cpuFreqKHz=" + cpuFreqKHz + ", scalingFreqKHz=" + scalingFreqKHz
                    + '}';
            return "FrequencyPair{cpuFreqKHz = " + cpuFreqKHz + ", scalingFreqKHz = "
                    + scalingFreqKHz + '}';
        }
    }

+44 −35

File changed.

Preview size limit exceeded, changes collapsed.