Loading core/java/android/os/BatteryStats.java +8 −0 Original line number Diff line number Diff line Loading @@ -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. Loading core/java/com/android/internal/os/BatteryStatsHelper.java +4 −4 Original line number Diff line number Diff line Loading @@ -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) Loading core/java/com/android/internal/os/BatteryStatsImpl.java +104 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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) { Loading Loading @@ -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; Loading Loading @@ -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() { Loading Loading @@ -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) { Loading Loading @@ -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) { Loading Loading @@ -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) { Loading Loading @@ -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) { Loading Loading @@ -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]; Loading Loading @@ -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(); } Loading @@ -11453,6 +11490,8 @@ public class BatteryStatsImpl extends BatteryStats { updateClusterSpeedTimes(updatedUids); } readKernelUidCpuFreqTimesLocked(partialTimersToConsider); readKernelUidCpuActiveTimesLocked(); readKernelUidCpuClusterTimesLocked(); } /** Loading Loading @@ -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; Loading Loading @@ -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]; Loading Loading @@ -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) { core/java/com/android/internal/os/CpuPowerCalculator.java +21 −3 Original line number Diff line number Diff line Loading @@ -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(); Loading @@ -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=" Loading @@ -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)) { Loading core/java/com/android/internal/os/KernelUidCpuActiveTimeReader.java 0 → 100644 +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
core/java/android/os/BatteryStats.java +8 −0 Original line number Diff line number Diff line Loading @@ -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. Loading
core/java/com/android/internal/os/BatteryStatsHelper.java +4 −4 Original line number Diff line number Diff line Loading @@ -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) Loading
core/java/com/android/internal/os/BatteryStatsImpl.java +104 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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) { Loading Loading @@ -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; Loading Loading @@ -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() { Loading Loading @@ -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) { Loading Loading @@ -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) { Loading Loading @@ -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) { Loading Loading @@ -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) { Loading Loading @@ -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]; Loading Loading @@ -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(); } Loading @@ -11453,6 +11490,8 @@ public class BatteryStatsImpl extends BatteryStats { updateClusterSpeedTimes(updatedUids); } readKernelUidCpuFreqTimesLocked(partialTimersToConsider); readKernelUidCpuActiveTimesLocked(); readKernelUidCpuClusterTimesLocked(); } /** Loading Loading @@ -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; Loading Loading @@ -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]; Loading Loading @@ -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) {
core/java/com/android/internal/os/CpuPowerCalculator.java +21 −3 Original line number Diff line number Diff line Loading @@ -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(); Loading @@ -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=" Loading @@ -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)) { Loading
core/java/com/android/internal/os/KernelUidCpuActiveTimeReader.java 0 → 100644 +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); } } } }