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

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

Merge "Add cluster&active cost to cpu power"

parents 7f013ecf 3d422c37
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -683,6 +683,14 @@ public abstract class BatteryStats implements Parcelable {

        public abstract long[] getCpuFreqTimes(int which);
        public abstract long[] getScreenOffCpuFreqTimes(int which);
        /**
         * Returns cpu active time of an uid.
         */
        public abstract long getCpuActiveTime();
        /**
         * Returns cpu times of an uid on each cluster
         */
        public abstract long[] getCpuClusterTimes();

        /**
         * Returns cpu times of an uid at a particular process state.
+4 −4
Original line number Diff line number Diff line
@@ -665,14 +665,14 @@ public class BatteryStatsHelper {

    /**
     * Calculate the baseline power usage for the device when it is in suspend and idle.
     * The device is drawing POWER_CPU_IDLE power at its lowest power state.
     * The device is drawing POWER_CPU_IDLE + POWER_CPU_AWAKE power when a wakelock is held.
     * The device is drawing POWER_CPU_SUSPEND power at its lowest power state.
     * The device is drawing POWER_CPU_SUSPEND + POWER_CPU_IDLE power when a wakelock is held.
     */
    private void addIdleUsage() {
        final double suspendPowerMaMs = (mTypeBatteryRealtimeUs / 1000) *
                mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE);
                mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_SUSPEND);
        final double idlePowerMaMs = (mTypeBatteryUptimeUs / 1000) *
                mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_AWAKE);
                mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE);
        final double totalPowerMah = (suspendPowerMaMs + idlePowerMaMs) / (60 * 60 * 1000);
        if (DEBUG && totalPowerMah != 0) {
            Log.d(TAG, "Suspend: time=" + (mTypeBatteryRealtimeUs / 1000)
+104 −0
Original line number Diff line number Diff line
@@ -198,6 +198,12 @@ public class BatteryStatsImpl extends BatteryStats {
    protected KernelUidCpuFreqTimeReader mKernelUidCpuFreqTimeReader =
            new KernelUidCpuFreqTimeReader();
    @VisibleForTesting
    protected KernelUidCpuActiveTimeReader mKernelUidCpuActiveTimeReader =
            new KernelUidCpuActiveTimeReader();
    @VisibleForTesting
    protected KernelUidCpuClusterTimeReader mKernelUidCpuClusterTimeReader =
            new KernelUidCpuClusterTimeReader();
    @VisibleForTesting
    protected KernelSingleUidTimeReader mKernelSingleUidTimeReader;
    private final KernelMemoryBandwidthStats mKernelMemoryBandwidthStats
@@ -3880,6 +3886,8 @@ public class BatteryStatsImpl extends BatteryStats {
        }
        mKernelUidCpuTimeReader.removeUid(isolatedUid);
        mKernelUidCpuFreqTimeReader.removeUid(isolatedUid);
        mKernelUidCpuActiveTimeReader.removeUid(isolatedUid);
        mKernelUidCpuClusterTimeReader.removeUid(isolatedUid);
    }
    public int mapUid(int uid) {
@@ -6479,9 +6487,11 @@ public class BatteryStatsImpl extends BatteryStats {
        LongSamplingCounter mUserCpuTime;
        LongSamplingCounter mSystemCpuTime;
        LongSamplingCounter[][] mCpuClusterSpeedTimesUs;
        LongSamplingCounter mCpuActiveTimeMs;
        LongSamplingCounterArray mCpuFreqTimeMs;
        LongSamplingCounterArray mScreenOffCpuFreqTimeMs;
        LongSamplingCounterArray mCpuClusterTimesMs;
        LongSamplingCounterArray[] mProcStateTimeMs;
        LongSamplingCounterArray[] mProcStateScreenOffTimeMs;
@@ -6551,6 +6561,8 @@ public class BatteryStatsImpl extends BatteryStats {
            mUserCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
            mSystemCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
            mCpuActiveTimeMs = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
            mCpuClusterTimesMs = new LongSamplingCounterArray(mBsi.mOnBatteryTimeBase);
            mWakelockStats = mBsi.new OverflowArrayMap<Wakelock>(uid) {
                @Override public Wakelock instantiateObject() {
@@ -6597,6 +6609,17 @@ public class BatteryStatsImpl extends BatteryStats {
            return nullIfAllZeros(mScreenOffCpuFreqTimeMs, which);
        }
        @Override
        public long getCpuActiveTime() {
            return mCpuActiveTimeMs.getCountLocked(STATS_SINCE_CHARGED);
        }
        @Override
        public long[] getCpuClusterTimes() {
            return nullIfAllZeros(mCpuClusterTimesMs, STATS_SINCE_CHARGED);
        }
        @Override
        public long[] getCpuFreqTimes(int which, int procState) {
            if (which < 0 || which >= NUM_PROCESS_STATE) {
@@ -7660,6 +7683,9 @@ public class BatteryStatsImpl extends BatteryStats {
                mScreenOffCpuFreqTimeMs.reset(false);
            }
            mCpuActiveTimeMs.reset(false);
            mCpuClusterTimesMs.reset(false);
            if (mProcStateTimeMs != null) {
                for (LongSamplingCounterArray counters : mProcStateTimeMs) {
                    if (counters != null) {
@@ -7864,6 +7890,8 @@ public class BatteryStatsImpl extends BatteryStats {
                if (mScreenOffCpuFreqTimeMs != null) {
                    mScreenOffCpuFreqTimeMs.detach();
                }
                mCpuActiveTimeMs.detach();
                mCpuClusterTimesMs.detach();
                if (mProcStateTimeMs != null) {
                    for (LongSamplingCounterArray counters : mProcStateTimeMs) {
@@ -8139,6 +8167,10 @@ public class BatteryStatsImpl extends BatteryStats {
            LongSamplingCounterArray.writeToParcel(out, mCpuFreqTimeMs);
            LongSamplingCounterArray.writeToParcel(out, mScreenOffCpuFreqTimeMs);
            mCpuActiveTimeMs.writeToParcel(out);
            mCpuClusterTimesMs.writeToParcel(out);
            if (mProcStateTimeMs != null) {
                out.writeInt(mProcStateTimeMs.length);
                for (LongSamplingCounterArray counters : mProcStateTimeMs) {
@@ -8456,6 +8488,9 @@ public class BatteryStatsImpl extends BatteryStats {
            mScreenOffCpuFreqTimeMs = LongSamplingCounterArray.readFromParcel(
                    in, mBsi.mOnBatteryScreenOffTimeBase);
            mCpuActiveTimeMs = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
            mCpuClusterTimesMs = new LongSamplingCounterArray(mBsi.mOnBatteryTimeBase, in);
            int length = in.readInt();
            if (length == NUM_PROCESS_STATE) {
                mProcStateTimeMs = new LongSamplingCounterArray[length];
@@ -11437,6 +11472,8 @@ public class BatteryStatsImpl extends BatteryStats {
        if (!mOnBatteryInternal) {
            mKernelUidCpuTimeReader.readDelta(null);
            mKernelUidCpuFreqTimeReader.readDelta(null);
            mKernelUidCpuActiveTimeReader.readDelta(null);
            mKernelUidCpuClusterTimeReader.readDelta(null);
            for (int cluster = mKernelCpuSpeedReaders.length - 1; cluster >= 0; --cluster) {
                mKernelCpuSpeedReaders[cluster].readDelta();
            }
@@ -11453,6 +11490,8 @@ public class BatteryStatsImpl extends BatteryStats {
            updateClusterSpeedTimes(updatedUids);
        }
        readKernelUidCpuFreqTimesLocked(partialTimersToConsider);
        readKernelUidCpuActiveTimesLocked();
        readKernelUidCpuClusterTimesLocked();
    }
    /**
@@ -11764,6 +11803,64 @@ public class BatteryStatsImpl extends BatteryStats {
        }
    }
    /**
     * Take a snapshot of the cpu active times spent by each uid and update the corresponding
     * counters.
     */
    @VisibleForTesting
    public void readKernelUidCpuActiveTimesLocked() {
        final long startTimeMs = mClocks.uptimeMillis();
        mKernelUidCpuActiveTimeReader.readDelta((uid, cpuActiveTimesUs) -> {
            uid = mapUid(uid);
            if (Process.isIsolated(uid)) {
                mKernelUidCpuActiveTimeReader.removeUid(uid);
                Slog.w(TAG, "Got active times for an isolated uid with no mapping: " + uid);
                return;
            }
            if (!mUserInfoProvider.exists(UserHandle.getUserId(uid))) {
                Slog.w(TAG, "Got active times for an invalid user's uid " + uid);
                mKernelUidCpuActiveTimeReader.removeUid(uid);
                return;
            }
            final Uid u = getUidStatsLocked(uid);
            u.mCpuActiveTimeMs.addCountLocked(cpuActiveTimesUs);
        });
        final long elapsedTimeMs = mClocks.uptimeMillis() - startTimeMs;
        if (DEBUG_ENERGY_CPU || elapsedTimeMs >= 100) {
            Slog.d(TAG, "Reading cpu active times took " + elapsedTimeMs + "ms");
        }
    }
    /**
     * Take a snapshot of the cpu cluster times spent by each uid and update the corresponding
     * counters.
     */
    @VisibleForTesting
    public void readKernelUidCpuClusterTimesLocked() {
        final long startTimeMs = mClocks.uptimeMillis();
        mKernelUidCpuClusterTimeReader.readDelta((uid, cpuClusterTimesUs) -> {
            uid = mapUid(uid);
            if (Process.isIsolated(uid)) {
                mKernelUidCpuClusterTimeReader.removeUid(uid);
                Slog.w(TAG, "Got cluster times for an isolated uid with no mapping: " + uid);
                return;
            }
            if (!mUserInfoProvider.exists(UserHandle.getUserId(uid))) {
                Slog.w(TAG, "Got cluster times for an invalid user's uid " + uid);
                mKernelUidCpuClusterTimeReader.removeUid(uid);
                return;
            }
            final Uid u = getUidStatsLocked(uid);
            u.mCpuClusterTimesMs.addCountLocked(cpuClusterTimesUs);
        });
        final long elapsedTimeMs = mClocks.uptimeMillis() - startTimeMs;
        if (DEBUG_ENERGY_CPU || elapsedTimeMs >= 100) {
            Slog.d(TAG, "Reading cpu cluster times took " + elapsedTimeMs + "ms");
        }
    }
    boolean setChargingLocked(boolean charging) {
        if (mCharging != charging) {
            mCharging = charging;
@@ -13249,6 +13346,10 @@ public class BatteryStatsImpl extends BatteryStats {
                    in, mOnBatteryTimeBase);
            u.mScreenOffCpuFreqTimeMs = LongSamplingCounterArray.readSummaryFromParcelLocked(
                    in, mOnBatteryScreenOffTimeBase);
            u.mCpuActiveTimeMs.readSummaryFromParcelLocked(in);
            u.mCpuClusterTimesMs.readSummaryFromParcelLocked(in);
            int length = in.readInt();
            if (length == Uid.NUM_PROCESS_STATE) {
                u.mProcStateTimeMs = new LongSamplingCounterArray[length];
@@ -13725,6 +13826,9 @@ public class BatteryStatsImpl extends BatteryStats {
            LongSamplingCounterArray.writeSummaryToParcelLocked(out, u.mCpuFreqTimeMs);
            LongSamplingCounterArray.writeSummaryToParcelLocked(out, u.mScreenOffCpuFreqTimeMs);
            u.mCpuActiveTimeMs.writeSummaryFromParcelLocked(out);
            u.mCpuClusterTimesMs.writeSummaryToParcelLocked(out);
            if (u.mProcStateTimeMs != null) {
                out.writeInt(u.mProcStateTimeMs.length);
                for (LongSamplingCounterArray counters : u.mProcStateTimeMs) {
+21 −3
Original line number Diff line number Diff line
@@ -32,7 +32,6 @@ public class CpuPowerCalculator extends PowerCalculator {
    @Override
    public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
            long rawUptimeUs, int statsType) {

        app.cpuTimeMs = (u.getUserCpuTimeUs(statsType) + u.getSystemCpuTimeUs(statsType)) / 1000;
        final int numClusters = mProfile.getNumCpuClusters();

@@ -42,7 +41,7 @@ public class CpuPowerCalculator extends PowerCalculator {
            for (int speed = 0; speed < speedsForCluster; speed++) {
                final long timeUs = u.getTimeAtCpuSpeed(cluster, speed, statsType);
                final double cpuSpeedStepPower = timeUs *
                        mProfile.getAveragePowerForCpu(cluster, speed);
                        mProfile.getAveragePowerForCpuCore(cluster, speed);
                if (DEBUG) {
                    Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster + " step #"
                            + speed + " timeUs=" + timeUs + " power="
@@ -51,6 +50,25 @@ public class CpuPowerCalculator extends PowerCalculator {
                cpuPowerMaUs += cpuSpeedStepPower;
            }
        }
        cpuPowerMaUs += u.getCpuActiveTime() * mProfile.getAveragePower(
                PowerProfile.POWER_CPU_ACTIVE);
        long[] cpuClusterTimes = u.getCpuClusterTimes();
        if (cpuClusterTimes != null) {
            if (cpuClusterTimes.length == numClusters) {
                for (int i = 0; i < numClusters; i++) {
                    double power = cpuClusterTimes[i] * mProfile.getAveragePowerForCpuCluster(i);
                    cpuPowerMaUs += power;
                    if (DEBUG) {
                        Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + i + " clusterTimeUs="
                                + cpuClusterTimes[i] + " power="
                                + BatteryStatsHelper.makemAh(power / MICROSEC_IN_HR));
                    }
                }
            } else {
                Log.w(TAG, "UID " + u.getUid() + " CPU cluster # mismatch: Power Profile # "
                        + numClusters + " actual # " + cpuClusterTimes.length);
            }
        }
        app.cpuPowerMah = cpuPowerMaUs / MICROSEC_IN_HR;

        if (DEBUG && (app.cpuTimeMs != 0 || app.cpuPowerMah != 0)) {
+146 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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.
 */

package com.android.internal.os;

import android.annotation.Nullable;
import android.os.StrictMode;
import android.os.SystemClock;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;

import com.android.internal.annotations.VisibleForTesting;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

/**
 * Reads /proc/uid_concurrent_active_time which has the format:
 * active: X (X is # cores)
 * [uid0]: [time-0] [time-1] [time-2] ... (# entries = # cores)
 * [uid1]: [time-0] [time-1] [time-2] ... ...
 * ...
 * Time-N means the CPU time a UID spent running concurrently with N other processes.
 * The file contains a monotonically increasing count of time for a single boot. This class
 * maintains the previous results of a call to {@link #readDelta} in order to provide a
 * proper delta.
 */
public class KernelUidCpuActiveTimeReader {
    private static final boolean DEBUG = false;
    private static final String TAG = "KernelUidCpuActiveTimeReader";
    private static final String UID_TIMES_PROC_FILE = "/proc/uid_concurrent_active_time";

    private int mCoreCount;
    private long mLastTimeReadMs;
    private long mNowTimeMs;
    private SparseArray<long[]> mLastUidCpuActiveTimeMs = new SparseArray<>();

    public interface Callback {
        void onUidCpuActiveTime(int uid, long cpuActiveTimeMs);
    }

    public void readDelta(@Nullable Callback cb) {
        final int oldMask = StrictMode.allowThreadDiskReadsMask();
        try (BufferedReader reader = new BufferedReader(new FileReader(UID_TIMES_PROC_FILE))) {
            mNowTimeMs = SystemClock.elapsedRealtime();
            readDeltaInternal(reader, cb);
            mLastTimeReadMs = mNowTimeMs;
        } catch (IOException e) {
            Slog.e(TAG, "Failed to read " + UID_TIMES_PROC_FILE + ": " + e);
        } finally {
            StrictMode.setThreadPolicyMask(oldMask);
        }
    }

    public void removeUid(int uid) {
        mLastUidCpuActiveTimeMs.delete(uid);
    }

    public void removeUidsInRange(int startUid, int endUid) {
        if (endUid < startUid) {
            Slog.w(TAG, "End UID " + endUid + " is smaller than start UID " + startUid);
            return;
        }
        mLastUidCpuActiveTimeMs.put(startUid, null);
        mLastUidCpuActiveTimeMs.put(endUid, null);
        final int firstIndex = mLastUidCpuActiveTimeMs.indexOfKey(startUid);
        final int lastIndex = mLastUidCpuActiveTimeMs.indexOfKey(endUid);
        mLastUidCpuActiveTimeMs.removeAtRange(firstIndex, lastIndex - firstIndex + 1);
    }

    @VisibleForTesting
    public void readDeltaInternal(BufferedReader reader, @Nullable Callback cb) throws IOException {
        String line = reader.readLine();
        if (line == null || !line.startsWith("active:")) {
            Slog.e(TAG, String.format("Malformed proc file: %s ", UID_TIMES_PROC_FILE));
            return;
        }
        if (mCoreCount == 0) {
            mCoreCount = Integer.parseInt(line.substring(line.indexOf(' ')+1));
        }
        while ((line = reader.readLine()) != null) {
            final int index = line.indexOf(' ');
            final int uid = Integer.parseInt(line.substring(0, index - 1), 10);
            readTimesForUid(uid, line.substring(index + 1), cb);
        }
    }

    private void readTimesForUid(int uid, String line, @Nullable Callback cb) {
        long[] lastActiveTime = mLastUidCpuActiveTimeMs.get(uid);
        if (lastActiveTime == null) {
            lastActiveTime = new long[mCoreCount];
            mLastUidCpuActiveTimeMs.put(uid, lastActiveTime);
        }
        final String[] timesStr = line.split(" ");
        if (timesStr.length != mCoreCount) {
            Slog.e(TAG, String.format("# readings don't match # cores, readings: %d, CPU cores: %d",
                    timesStr.length, mCoreCount));
            return;
        }
        long sumDeltas = 0;
        final long[] curActiveTime = new long[mCoreCount];
        boolean notify = false;
        for (int i = 0; i < mCoreCount; i++) {
            // Times read will be in units of 10ms
            curActiveTime[i] = Long.parseLong(timesStr[i], 10) * 10;
            long delta = curActiveTime[i] - lastActiveTime[i];
            if (delta < 0 || curActiveTime[i] < 0) {
                if (DEBUG) {
                    final StringBuilder sb = new StringBuilder();
                    sb.append(String.format("Malformed cpu active time for UID=%d\n", uid));
                    sb.append(String.format("data=(%d,%d)\n", lastActiveTime[i], curActiveTime[i]));
                    sb.append("times=(");
                    TimeUtils.formatDuration(mLastTimeReadMs, sb);
                    sb.append(",");
                    TimeUtils.formatDuration(mNowTimeMs, sb);
                    sb.append(")");
                    Slog.e(TAG, sb.toString());
                }
                return;
            }
            notify |= delta > 0;
            sumDeltas += delta / (i + 1);
        }
        if (notify) {
            System.arraycopy(curActiveTime, 0, lastActiveTime, 0, mCoreCount);
            if (cb != null) {
                cb.onUidCpuActiveTime(uid, sumDeltas);
            }
        }
    }
}
Loading