Loading core/java/android/os/BatteryStats.java +91 −0 Original line number Diff line number Diff line Loading @@ -203,6 +203,8 @@ public abstract class BatteryStats implements Parcelable { private static final String APK_DATA = "apk"; private static final String PROCESS_DATA = "pr"; private static final String CPU_DATA = "cpu"; private static final String GLOBAL_CPU_FREQ_DATA = "gcf"; private static final String CPU_TIMES_AT_FREQ_DATA = "ctf"; private static final String SENSOR_DATA = "sr"; private static final String VIBRATOR_DATA = "vib"; private static final String FOREGROUND_DATA = "fg"; Loading Loading @@ -264,6 +266,13 @@ public abstract class BatteryStats implements Parcelable { private final StringBuilder mFormatBuilder = new StringBuilder(32); private final Formatter mFormatter = new Formatter(mFormatBuilder); /** * Indicates times spent by the uid at each cpu frequency in all process states. * * Other types might include times spent in foreground, background etc. */ private final String UID_TIMES_TYPE_ALL = "A"; /** * State for keeping track of counting information. */ Loading Loading @@ -302,6 +311,24 @@ public abstract class BatteryStats implements Parcelable { public abstract void logState(Printer pw, String prefix); } /** * State for keeping track of array of long counting information. */ public static abstract class LongCounterArray { /** * Returns the counts associated with this Counter for the * selected type of statistics. * * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT */ public abstract long[] getCountsLocked(int which); /** * Temporary for debugging. */ public abstract void logState(Printer pw, String prefix); } /** * Container class that aggregates counters for transmit, receive, and idle state of a * radio controller. Loading Loading @@ -523,6 +550,9 @@ public abstract class BatteryStats implements Parcelable { public abstract Timer getBluetoothScanBackgroundTimer(); public abstract Counter getBluetoothScanResultCounter(); public abstract long[] getCpuFreqTimes(int which); public abstract long[] getScreenOffCpuFreqTimes(int which); // Note: the following times are disjoint. They can be added together to find the // total time a uid has had any processes running at all. Loading Loading @@ -1077,6 +1107,8 @@ public abstract class BatteryStats implements Parcelable { public abstract long getNextMaxDailyDeadline(); public abstract long[] getCpuFreqs(); public final static class HistoryTag { public String string; public int uid; Loading Loading @@ -3274,6 +3306,15 @@ public abstract class BatteryStats implements Parcelable { } } final long[] cpuFreqs = getCpuFreqs(); if (cpuFreqs != null) { sb.setLength(0); for (int i = 0; i < cpuFreqs.length; ++i) { sb.append((i == 0 ? "" : ",") + cpuFreqs[i]); } dumpLine(pw, 0 /* uid */, category, GLOBAL_CPU_FREQ_DATA, sb.toString()); } for (int iu = 0; iu < NU; iu++) { final int uid = uidStats.keyAt(iu); if (reqUid >= 0 && uid != reqUid) { Loading Loading @@ -3506,6 +3547,27 @@ public abstract class BatteryStats implements Parcelable { 0 /* old cpu power, keep for compatibility */); } final long[] cpuFreqTimeMs = u.getCpuFreqTimes(which); // If total cpuFreqTimes is null, then we don't need to check for screenOffCpuFreqTimes. if (cpuFreqTimeMs != null) { sb.setLength(0); for (int i = 0; i < cpuFreqTimeMs.length; ++i) { sb.append((i == 0 ? "" : ",") + cpuFreqTimeMs[i]); } final long[] screenOffCpuFreqTimeMs = u.getScreenOffCpuFreqTimes(which); if (screenOffCpuFreqTimeMs != null) { for (int i = 0; i < screenOffCpuFreqTimeMs.length; ++i) { sb.append("," + screenOffCpuFreqTimeMs[i]); } } else { for (int i = 0; i < cpuFreqTimeMs.length; ++i) { sb.append(",0"); } } dumpLine(pw, uid, category, CPU_TIMES_AT_FREQ_DATA, UID_TIMES_TYPE_ALL, cpuFreqTimeMs.length, sb.toString()); } final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats(); for (int ipr=processStats.size()-1; ipr>=0; ipr--) { Loading Loading @@ -4373,6 +4435,16 @@ public abstract class BatteryStats implements Parcelable { pw.println(sb.toString()); } final long[] cpuFreqs = getCpuFreqs(); if (cpuFreqs != null) { sb.setLength(0); sb.append("CPU freqs:"); for (int i = 0; i < cpuFreqs.length; ++i) { sb.append(" " + cpuFreqs[i]); } pw.println(sb.toString()); } for (int iu=0; iu<NU; iu++) { final int uid = uidStats.keyAt(iu); if (reqUid >= 0 && uid != reqUid && uid != Process.SYSTEM_UID) { Loading Loading @@ -4835,6 +4907,25 @@ public abstract class BatteryStats implements Parcelable { pw.println(sb.toString()); } final long[] cpuFreqTimes = u.getCpuFreqTimes(which); if (cpuFreqTimes != null) { sb.setLength(0); sb.append(" Total cpu time per freq:"); for (int i = 0; i < cpuFreqTimes.length; ++i) { sb.append(" " + cpuFreqTimes[i]); } pw.println(sb.toString()); } final long[] screenOffCpuFreqTimes = u.getScreenOffCpuFreqTimes(which); if (screenOffCpuFreqTimes != null) { sb.setLength(0); sb.append(" Total screen-off cpu time per freq:"); for (int i = 0; i < screenOffCpuFreqTimes.length; ++i) { sb.append(" " + screenOffCpuFreqTimes[i]); } pw.println(sb.toString()); } final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats(); for (int ipr=processStats.size()-1; ipr>=0; ipr--) { Loading core/java/com/android/internal/os/BatteryStatsImpl.java +275 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.internal.os; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.bluetooth.BluetoothActivityEnergyInfo; Loading Loading @@ -87,6 +88,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.HashMap; import java.util.Iterator; Loading Loading @@ -114,7 +116,7 @@ public class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version private static final int VERSION = 156 + (USE_OLD_HISTORY ? 1000 : 0); private static final int VERSION = 157 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; Loading Loading @@ -149,6 +151,8 @@ public class BatteryStatsImpl extends BatteryStats { private final KernelUidCpuTimeReader mKernelUidCpuTimeReader = new KernelUidCpuTimeReader(); private KernelCpuSpeedReader[] mKernelCpuSpeedReaders; private final KernelUidCpuFreqTimeReader mKernelUidCpuFreqTimeReader = new KernelUidCpuFreqTimeReader(); private final KernelMemoryBandwidthStats mKernelMemoryBandwidthStats = new KernelMemoryBandwidthStats(); Loading Loading @@ -570,6 +574,8 @@ public class BatteryStatsImpl extends BatteryStats { private final NetworkStats.Entry mTmpNetworkStatsEntry = new NetworkStats.Entry(); private long[] mCpuFreqs; private PowerProfile mPowerProfile; /* Loading Loading @@ -957,6 +963,131 @@ public class BatteryStatsImpl extends BatteryStats { } } public static class LongSamplingCounterArray extends LongCounterArray implements TimeBaseObs { final TimeBase mTimeBase; long[] mCounts; long[] mLoadedCounts; long[] mUnpluggedCounts; long[] mPluggedCounts; LongSamplingCounterArray(TimeBase timeBase, Parcel in) { mTimeBase = timeBase; mPluggedCounts = in.createLongArray(); mCounts = copyArray(mPluggedCounts, mCounts); mLoadedCounts = in.createLongArray(); mUnpluggedCounts = in.createLongArray(); timeBase.add(this); } LongSamplingCounterArray(TimeBase timeBase) { mTimeBase = timeBase; timeBase.add(this); } public void writeToParcel(Parcel out) { out.writeLongArray(mCounts); out.writeLongArray(mLoadedCounts); out.writeLongArray(mUnpluggedCounts); } @Override public void onTimeStarted(long elapsedRealTime, long baseUptime, long baseRealtime) { mUnpluggedCounts = copyArray(mPluggedCounts, mUnpluggedCounts); mCounts = copyArray(mPluggedCounts, mCounts); } @Override public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) { mPluggedCounts = copyArray(mCounts, mPluggedCounts); } @Override public long[] getCountsLocked(int which) { long[] val = copyArray(mTimeBase.isRunning() ? mCounts : mPluggedCounts, null); if (which == STATS_SINCE_UNPLUGGED) { subtract(val, mUnpluggedCounts); } else if (which != STATS_SINCE_CHARGED) { subtract(val, mLoadedCounts); } return val; } @Override public void logState(Printer pw, String prefix) { pw.println(prefix + "mCounts=" + Arrays.toString(mCounts) + " mLoadedCounts=" + Arrays.toString(mLoadedCounts) + " mUnpluggedCounts=" + Arrays.toString(mUnpluggedCounts) + " mPluggedCounts=" + Arrays.toString(mPluggedCounts)); } void addCountLocked(long[] counts) { if (counts == null) { return; } if (mCounts == null) { mCounts = new long[counts.length]; } for (int i = 0; i < counts.length; ++i) { mCounts[i] += counts[i]; } } /** * Clear state of this counter. */ void reset(boolean detachIfReset) { fillArray(mCounts, 0); fillArray(mLoadedCounts, 0); fillArray(mPluggedCounts, 0); fillArray(mUnpluggedCounts, 0); if (detachIfReset) { detach(); } } void detach() { mTimeBase.remove(this); } void writeSummaryFromParcelLocked(Parcel out) { out.writeLongArray(mCounts); } void readSummaryFromParcelLocked(Parcel in) { mCounts = in.createLongArray(); mLoadedCounts = copyArray(mCounts, mLoadedCounts); mUnpluggedCounts = copyArray(mCounts, mUnpluggedCounts); mPluggedCounts = copyArray(mCounts, mPluggedCounts); } private void fillArray(long[] a, long val) { if (a != null) { Arrays.fill(a, val); } } private void subtract(@NonNull long[] val, long[] toSubtract) { if (toSubtract == null) { return; } for (int i = 0; i < val.length; i++) { val[i] -= toSubtract[i]; } } private long[] copyArray(long[] src, long[] dest) { if (src == null) { return null; } else { if (dest == null) { dest = new long[src.length]; } System.arraycopy(src, 0, dest, 0, src.length); return dest; } } } public static class LongSamplingCounter extends LongCounter implements TimeBaseObs { final TimeBase mTimeBase; long mCount; Loading Loading @@ -5483,6 +5614,9 @@ public class BatteryStatsImpl extends BatteryStats { LongSamplingCounter mSystemCpuTime; LongSamplingCounter[][] mCpuClusterSpeed; LongSamplingCounterArray mCpuFreqTimeMs; LongSamplingCounterArray mScreenOffCpuFreqTimeMs; /** * The statistics we have collected for this uid's wake locks. */ Loading Loading @@ -5559,6 +5693,42 @@ public class BatteryStatsImpl extends BatteryStats { mProcessStateTimer = new StopwatchTimer[NUM_PROCESS_STATE]; } @Override public long[] getCpuFreqTimes(int which) { if (mCpuFreqTimeMs == null) { return null; } final long[] cpuFreqTimes = mCpuFreqTimeMs.getCountsLocked(which); if (cpuFreqTimes == null) { return null; } // Return cpuFreqTimes only if atleast one of the elements in non-zero. for (int i = 0; i < cpuFreqTimes.length; ++i) { if (cpuFreqTimes[i] != 0) { return cpuFreqTimes; } } return null; } @Override public long[] getScreenOffCpuFreqTimes(int which) { if (mScreenOffCpuFreqTimeMs == null) { return null; } final long[] cpuFreqTimes = mScreenOffCpuFreqTimeMs.getCountsLocked(which); if (cpuFreqTimes == null) { return null; } // Return cpuFreqTimes only if atleast one of the elements in non-zero. for (int i = 0; i < cpuFreqTimes.length; ++i) { if (cpuFreqTimes[i] != 0) { return cpuFreqTimes; } } return null; } @Override public ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() { return mWakelockStats.getMap(); Loading Loading @@ -6354,6 +6524,13 @@ public class BatteryStatsImpl extends BatteryStats { } } if (mCpuFreqTimeMs != null) { mCpuFreqTimeMs.reset(false); } if (mScreenOffCpuFreqTimeMs != null) { mScreenOffCpuFreqTimeMs.reset(false); } resetLongCounterIfNotNull(mMobileRadioApWakeupCount, false); resetLongCounterIfNotNull(mWifiRadioApWakeupCount, false); Loading Loading @@ -6523,6 +6700,13 @@ public class BatteryStatsImpl extends BatteryStats { } } if (mCpuFreqTimeMs != null) { mCpuFreqTimeMs.detach(); } if (mScreenOffCpuFreqTimeMs != null) { mScreenOffCpuFreqTimeMs.detach(); } detachLongCounterIfNotNull(mMobileRadioApWakeupCount); detachLongCounterIfNotNull(mWifiRadioApWakeupCount); } Loading Loading @@ -6739,6 +6923,19 @@ public class BatteryStatsImpl extends BatteryStats { out.writeInt(0); } if (mCpuFreqTimeMs != null) { out.writeInt(1); mCpuFreqTimeMs.writeToParcel(out); } else { out.writeInt(0); } if (mScreenOffCpuFreqTimeMs != null) { out.writeInt(1); mScreenOffCpuFreqTimeMs.writeToParcel(out); } else { out.writeInt(0); } if (mMobileRadioApWakeupCount != null) { out.writeInt(1); mMobileRadioApWakeupCount.writeToParcel(out); Loading Loading @@ -6986,6 +7183,18 @@ public class BatteryStatsImpl extends BatteryStats { mCpuClusterSpeed = null; } if (in.readInt() != 0) { mCpuFreqTimeMs = new LongSamplingCounterArray(mBsi.mOnBatteryTimeBase, in); } else { mCpuFreqTimeMs = null; } if (in.readInt() != 0) { mScreenOffCpuFreqTimeMs = new LongSamplingCounterArray( mBsi.mOnBatteryScreenOffTimeBase, in); } else { mScreenOffCpuFreqTimeMs = null; } if (in.readInt() != 0) { mMobileRadioApWakeupCount = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in); } else { Loading Loading @@ -8192,6 +8401,10 @@ public class BatteryStatsImpl extends BatteryStats { } } public long[] getCpuFreqs() { return mCpuFreqs; } public BatteryStatsImpl(File systemDir, Handler handler, ExternalStatsSync externalSync) { this(new SystemClocks(), systemDir, handler, externalSync, null); } Loading Loading @@ -9812,6 +10025,8 @@ public class BatteryStatsImpl extends BatteryStats { } }); readKernelUidCpuFreqTimesLocked(); final long elapse = (mClocks.elapsedRealtime() - startTimeMs); if (DEBUG_ENERGY_CPU || (elapse >= 100)) { Slog.d(TAG, "Reading cpu stats took " + elapse + " ms"); Loading Loading @@ -9900,6 +10115,30 @@ public class BatteryStatsImpl extends BatteryStats { } } void readKernelUidCpuFreqTimesLocked() { mKernelUidCpuFreqTimeReader.readDelta(!mOnBatteryInternal ? null : new KernelUidCpuFreqTimeReader.Callback() { @Override public void onCpuFreqs(long[] cpuFreqs) { mCpuFreqs = cpuFreqs; } @Override public void onUidCpuFreqTime(int uid, long[] cpuFreqTimeMs) { final Uid u = getUidStatsLocked(uid); if (u.mCpuFreqTimeMs == null) { u.mCpuFreqTimeMs = new LongSamplingCounterArray(mOnBatteryTimeBase); } u.mCpuFreqTimeMs.addCountLocked(cpuFreqTimeMs); if (u.mScreenOffCpuFreqTimeMs == null) { u.mScreenOffCpuFreqTimeMs = new LongSamplingCounterArray( mOnBatteryScreenOffTimeBase); } u.mScreenOffCpuFreqTimeMs.addCountLocked(cpuFreqTimeMs); } }); } boolean setChargingLocked(boolean charging) { if (mCharging != charging) { mCharging = charging; Loading Loading @@ -10988,6 +11227,8 @@ public class BatteryStatsImpl extends BatteryStats { } } mCpuFreqs = in.createLongArray(); final int NU = in.readInt(); if (NU > 10000) { throw new ParcelFormatException("File corrupt: too many uids " + NU); Loading Loading @@ -11110,6 +11351,20 @@ public class BatteryStatsImpl extends BatteryStats { u.mCpuClusterSpeed = null; } if (in.readInt() != 0) { u.mCpuFreqTimeMs = new LongSamplingCounterArray(mOnBatteryTimeBase); u.mCpuFreqTimeMs.readSummaryFromParcelLocked(in); } else { u.mCpuFreqTimeMs = null; } if (in.readInt() != 0) { u.mScreenOffCpuFreqTimeMs = new LongSamplingCounterArray( mOnBatteryScreenOffTimeBase); u.mScreenOffCpuFreqTimeMs.readSummaryFromParcelLocked(in); } else { u.mScreenOffCpuFreqTimeMs = null; } if (in.readInt() != 0) { u.mMobileRadioApWakeupCount = new LongSamplingCounter(mOnBatteryTimeBase); u.mMobileRadioApWakeupCount.readSummaryFromParcelLocked(in); Loading Loading @@ -11360,6 +11615,8 @@ public class BatteryStatsImpl extends BatteryStats { } } out.writeLongArray(mCpuFreqs); final int NU = mUidStats.size(); out.writeInt(NU); for (int iu = 0; iu < NU; iu++) { Loading Loading @@ -11504,6 +11761,19 @@ public class BatteryStatsImpl extends BatteryStats { out.writeInt(0); } if (u.mCpuFreqTimeMs != null) { out.writeInt(1); u.mCpuFreqTimeMs.writeSummaryFromParcelLocked(out); } else { out.writeInt(0); } if (u.mScreenOffCpuFreqTimeMs != null) { out.writeInt(1); u.mScreenOffCpuFreqTimeMs.writeSummaryFromParcelLocked(out); } else { out.writeInt(0); } if (u.mMobileRadioApWakeupCount != null) { out.writeInt(1); u.mMobileRadioApWakeupCount.writeSummaryFromParcelLocked(out); Loading Loading @@ -11794,6 +12064,8 @@ public class BatteryStatsImpl extends BatteryStats { mFlashlightTurnedOnTimers.clear(); mCameraTurnedOnTimers.clear(); mCpuFreqs = in.createLongArray(); int numUids = in.readInt(); mUidStats.clear(); for (int i = 0; i < numUids; i++) { Loading Loading @@ -11953,6 +12225,8 @@ public class BatteryStatsImpl extends BatteryStats { } } out.writeLongArray(mCpuFreqs); if (inclUids) { int size = mUidStats.size(); out.writeInt(size); Loading core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java 0 → 100644 +117 −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.util.Slog; import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; /** * Reads /proc/uid_time_in_state which has the format: * * uid: [freq1] [freq2] [freq3] ... * [uid1]: [time in freq1] [time in freq2] [time in freq3] ... * [uid2]: [time in freq1] [time in freq2] [time in freq3] ... * ... * * This provides the times a UID's processes spent executing at each different cpu frequency. * 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 KernelUidCpuFreqTimeReader { private static final String TAG = "KernelUidCpuFreqTimeReader"; private static final String UID_TIMES_PROC_FILE = "/proc/uid_time_in_state"; public interface Callback { void onCpuFreqs(long[] cpuFreqs); void onUidCpuFreqTime(int uid, long[] cpuFreqTimeMs); } private long[] mCpuFreqs; private int mCpuFreqsCount; private SparseArray<long[]> mLastUidCpuFreqTimeMs = new SparseArray<>(); public void readDelta(@Nullable Callback callback) { try (BufferedReader reader = new BufferedReader(new FileReader(UID_TIMES_PROC_FILE))) { readDelta(reader, callback); } catch (IOException e) { Slog.e(TAG, "Failed to read " + UID_TIMES_PROC_FILE + ": " + e); } } @VisibleForTesting public void readDelta(BufferedReader reader, @Nullable Callback callback) throws IOException { String line = reader.readLine(); if (line == null) { return; } readCpuFreqs(line, callback); 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, line.length()), callback); } } private void readTimesForUid(int uid, String line, Callback callback) { long[] uidTimeMs = mLastUidCpuFreqTimeMs.get(uid); if (uidTimeMs == null) { uidTimeMs = new long[mCpuFreqsCount]; mLastUidCpuFreqTimeMs.put(uid, uidTimeMs); } final String[] timesStr = line.split(" "); final int size = timesStr.length; if (size != uidTimeMs.length) { Slog.e(TAG, "No. of readings don't match cpu freqs, readings: " + size + " cpuFreqsCount: " + uidTimeMs.length); return; } final long[] deltaUidTimeMs = new long[size]; for (int i = 0; i < size; ++i) { // Times read will be in units of 10ms final long totalTimeMs = Long.parseLong(timesStr[i], 10) * 10; deltaUidTimeMs[i] = totalTimeMs - uidTimeMs[i]; uidTimeMs[i] = totalTimeMs; } if (callback != null) { callback.onUidCpuFreqTime(uid, deltaUidTimeMs); } } private void readCpuFreqs(String line, Callback callback) { if (mCpuFreqs == null) { final String[] freqStr = line.split(" "); // First item would be "uid:" which needs to be ignored mCpuFreqsCount = freqStr.length - 1; mCpuFreqs = new long[mCpuFreqsCount]; for (int i = 0; i < mCpuFreqsCount; ++i) { mCpuFreqs[i] = Long.parseLong(freqStr[i + 1], 10); } } if (callback != null) { callback.onCpuFreqs(mCpuFreqs); } } } core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java 0 → 100644 +109 −0 File added.Preview size limit exceeded, changes collapsed. Show changes Loading
core/java/android/os/BatteryStats.java +91 −0 Original line number Diff line number Diff line Loading @@ -203,6 +203,8 @@ public abstract class BatteryStats implements Parcelable { private static final String APK_DATA = "apk"; private static final String PROCESS_DATA = "pr"; private static final String CPU_DATA = "cpu"; private static final String GLOBAL_CPU_FREQ_DATA = "gcf"; private static final String CPU_TIMES_AT_FREQ_DATA = "ctf"; private static final String SENSOR_DATA = "sr"; private static final String VIBRATOR_DATA = "vib"; private static final String FOREGROUND_DATA = "fg"; Loading Loading @@ -264,6 +266,13 @@ public abstract class BatteryStats implements Parcelable { private final StringBuilder mFormatBuilder = new StringBuilder(32); private final Formatter mFormatter = new Formatter(mFormatBuilder); /** * Indicates times spent by the uid at each cpu frequency in all process states. * * Other types might include times spent in foreground, background etc. */ private final String UID_TIMES_TYPE_ALL = "A"; /** * State for keeping track of counting information. */ Loading Loading @@ -302,6 +311,24 @@ public abstract class BatteryStats implements Parcelable { public abstract void logState(Printer pw, String prefix); } /** * State for keeping track of array of long counting information. */ public static abstract class LongCounterArray { /** * Returns the counts associated with this Counter for the * selected type of statistics. * * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT */ public abstract long[] getCountsLocked(int which); /** * Temporary for debugging. */ public abstract void logState(Printer pw, String prefix); } /** * Container class that aggregates counters for transmit, receive, and idle state of a * radio controller. Loading Loading @@ -523,6 +550,9 @@ public abstract class BatteryStats implements Parcelable { public abstract Timer getBluetoothScanBackgroundTimer(); public abstract Counter getBluetoothScanResultCounter(); public abstract long[] getCpuFreqTimes(int which); public abstract long[] getScreenOffCpuFreqTimes(int which); // Note: the following times are disjoint. They can be added together to find the // total time a uid has had any processes running at all. Loading Loading @@ -1077,6 +1107,8 @@ public abstract class BatteryStats implements Parcelable { public abstract long getNextMaxDailyDeadline(); public abstract long[] getCpuFreqs(); public final static class HistoryTag { public String string; public int uid; Loading Loading @@ -3274,6 +3306,15 @@ public abstract class BatteryStats implements Parcelable { } } final long[] cpuFreqs = getCpuFreqs(); if (cpuFreqs != null) { sb.setLength(0); for (int i = 0; i < cpuFreqs.length; ++i) { sb.append((i == 0 ? "" : ",") + cpuFreqs[i]); } dumpLine(pw, 0 /* uid */, category, GLOBAL_CPU_FREQ_DATA, sb.toString()); } for (int iu = 0; iu < NU; iu++) { final int uid = uidStats.keyAt(iu); if (reqUid >= 0 && uid != reqUid) { Loading Loading @@ -3506,6 +3547,27 @@ public abstract class BatteryStats implements Parcelable { 0 /* old cpu power, keep for compatibility */); } final long[] cpuFreqTimeMs = u.getCpuFreqTimes(which); // If total cpuFreqTimes is null, then we don't need to check for screenOffCpuFreqTimes. if (cpuFreqTimeMs != null) { sb.setLength(0); for (int i = 0; i < cpuFreqTimeMs.length; ++i) { sb.append((i == 0 ? "" : ",") + cpuFreqTimeMs[i]); } final long[] screenOffCpuFreqTimeMs = u.getScreenOffCpuFreqTimes(which); if (screenOffCpuFreqTimeMs != null) { for (int i = 0; i < screenOffCpuFreqTimeMs.length; ++i) { sb.append("," + screenOffCpuFreqTimeMs[i]); } } else { for (int i = 0; i < cpuFreqTimeMs.length; ++i) { sb.append(",0"); } } dumpLine(pw, uid, category, CPU_TIMES_AT_FREQ_DATA, UID_TIMES_TYPE_ALL, cpuFreqTimeMs.length, sb.toString()); } final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats(); for (int ipr=processStats.size()-1; ipr>=0; ipr--) { Loading Loading @@ -4373,6 +4435,16 @@ public abstract class BatteryStats implements Parcelable { pw.println(sb.toString()); } final long[] cpuFreqs = getCpuFreqs(); if (cpuFreqs != null) { sb.setLength(0); sb.append("CPU freqs:"); for (int i = 0; i < cpuFreqs.length; ++i) { sb.append(" " + cpuFreqs[i]); } pw.println(sb.toString()); } for (int iu=0; iu<NU; iu++) { final int uid = uidStats.keyAt(iu); if (reqUid >= 0 && uid != reqUid && uid != Process.SYSTEM_UID) { Loading Loading @@ -4835,6 +4907,25 @@ public abstract class BatteryStats implements Parcelable { pw.println(sb.toString()); } final long[] cpuFreqTimes = u.getCpuFreqTimes(which); if (cpuFreqTimes != null) { sb.setLength(0); sb.append(" Total cpu time per freq:"); for (int i = 0; i < cpuFreqTimes.length; ++i) { sb.append(" " + cpuFreqTimes[i]); } pw.println(sb.toString()); } final long[] screenOffCpuFreqTimes = u.getScreenOffCpuFreqTimes(which); if (screenOffCpuFreqTimes != null) { sb.setLength(0); sb.append(" Total screen-off cpu time per freq:"); for (int i = 0; i < screenOffCpuFreqTimes.length; ++i) { sb.append(" " + screenOffCpuFreqTimes[i]); } pw.println(sb.toString()); } final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats(); for (int ipr=processStats.size()-1; ipr>=0; ipr--) { Loading
core/java/com/android/internal/os/BatteryStatsImpl.java +275 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.internal.os; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.bluetooth.BluetoothActivityEnergyInfo; Loading Loading @@ -87,6 +88,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.HashMap; import java.util.Iterator; Loading Loading @@ -114,7 +116,7 @@ public class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version private static final int VERSION = 156 + (USE_OLD_HISTORY ? 1000 : 0); private static final int VERSION = 157 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; Loading Loading @@ -149,6 +151,8 @@ public class BatteryStatsImpl extends BatteryStats { private final KernelUidCpuTimeReader mKernelUidCpuTimeReader = new KernelUidCpuTimeReader(); private KernelCpuSpeedReader[] mKernelCpuSpeedReaders; private final KernelUidCpuFreqTimeReader mKernelUidCpuFreqTimeReader = new KernelUidCpuFreqTimeReader(); private final KernelMemoryBandwidthStats mKernelMemoryBandwidthStats = new KernelMemoryBandwidthStats(); Loading Loading @@ -570,6 +574,8 @@ public class BatteryStatsImpl extends BatteryStats { private final NetworkStats.Entry mTmpNetworkStatsEntry = new NetworkStats.Entry(); private long[] mCpuFreqs; private PowerProfile mPowerProfile; /* Loading Loading @@ -957,6 +963,131 @@ public class BatteryStatsImpl extends BatteryStats { } } public static class LongSamplingCounterArray extends LongCounterArray implements TimeBaseObs { final TimeBase mTimeBase; long[] mCounts; long[] mLoadedCounts; long[] mUnpluggedCounts; long[] mPluggedCounts; LongSamplingCounterArray(TimeBase timeBase, Parcel in) { mTimeBase = timeBase; mPluggedCounts = in.createLongArray(); mCounts = copyArray(mPluggedCounts, mCounts); mLoadedCounts = in.createLongArray(); mUnpluggedCounts = in.createLongArray(); timeBase.add(this); } LongSamplingCounterArray(TimeBase timeBase) { mTimeBase = timeBase; timeBase.add(this); } public void writeToParcel(Parcel out) { out.writeLongArray(mCounts); out.writeLongArray(mLoadedCounts); out.writeLongArray(mUnpluggedCounts); } @Override public void onTimeStarted(long elapsedRealTime, long baseUptime, long baseRealtime) { mUnpluggedCounts = copyArray(mPluggedCounts, mUnpluggedCounts); mCounts = copyArray(mPluggedCounts, mCounts); } @Override public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) { mPluggedCounts = copyArray(mCounts, mPluggedCounts); } @Override public long[] getCountsLocked(int which) { long[] val = copyArray(mTimeBase.isRunning() ? mCounts : mPluggedCounts, null); if (which == STATS_SINCE_UNPLUGGED) { subtract(val, mUnpluggedCounts); } else if (which != STATS_SINCE_CHARGED) { subtract(val, mLoadedCounts); } return val; } @Override public void logState(Printer pw, String prefix) { pw.println(prefix + "mCounts=" + Arrays.toString(mCounts) + " mLoadedCounts=" + Arrays.toString(mLoadedCounts) + " mUnpluggedCounts=" + Arrays.toString(mUnpluggedCounts) + " mPluggedCounts=" + Arrays.toString(mPluggedCounts)); } void addCountLocked(long[] counts) { if (counts == null) { return; } if (mCounts == null) { mCounts = new long[counts.length]; } for (int i = 0; i < counts.length; ++i) { mCounts[i] += counts[i]; } } /** * Clear state of this counter. */ void reset(boolean detachIfReset) { fillArray(mCounts, 0); fillArray(mLoadedCounts, 0); fillArray(mPluggedCounts, 0); fillArray(mUnpluggedCounts, 0); if (detachIfReset) { detach(); } } void detach() { mTimeBase.remove(this); } void writeSummaryFromParcelLocked(Parcel out) { out.writeLongArray(mCounts); } void readSummaryFromParcelLocked(Parcel in) { mCounts = in.createLongArray(); mLoadedCounts = copyArray(mCounts, mLoadedCounts); mUnpluggedCounts = copyArray(mCounts, mUnpluggedCounts); mPluggedCounts = copyArray(mCounts, mPluggedCounts); } private void fillArray(long[] a, long val) { if (a != null) { Arrays.fill(a, val); } } private void subtract(@NonNull long[] val, long[] toSubtract) { if (toSubtract == null) { return; } for (int i = 0; i < val.length; i++) { val[i] -= toSubtract[i]; } } private long[] copyArray(long[] src, long[] dest) { if (src == null) { return null; } else { if (dest == null) { dest = new long[src.length]; } System.arraycopy(src, 0, dest, 0, src.length); return dest; } } } public static class LongSamplingCounter extends LongCounter implements TimeBaseObs { final TimeBase mTimeBase; long mCount; Loading Loading @@ -5483,6 +5614,9 @@ public class BatteryStatsImpl extends BatteryStats { LongSamplingCounter mSystemCpuTime; LongSamplingCounter[][] mCpuClusterSpeed; LongSamplingCounterArray mCpuFreqTimeMs; LongSamplingCounterArray mScreenOffCpuFreqTimeMs; /** * The statistics we have collected for this uid's wake locks. */ Loading Loading @@ -5559,6 +5693,42 @@ public class BatteryStatsImpl extends BatteryStats { mProcessStateTimer = new StopwatchTimer[NUM_PROCESS_STATE]; } @Override public long[] getCpuFreqTimes(int which) { if (mCpuFreqTimeMs == null) { return null; } final long[] cpuFreqTimes = mCpuFreqTimeMs.getCountsLocked(which); if (cpuFreqTimes == null) { return null; } // Return cpuFreqTimes only if atleast one of the elements in non-zero. for (int i = 0; i < cpuFreqTimes.length; ++i) { if (cpuFreqTimes[i] != 0) { return cpuFreqTimes; } } return null; } @Override public long[] getScreenOffCpuFreqTimes(int which) { if (mScreenOffCpuFreqTimeMs == null) { return null; } final long[] cpuFreqTimes = mScreenOffCpuFreqTimeMs.getCountsLocked(which); if (cpuFreqTimes == null) { return null; } // Return cpuFreqTimes only if atleast one of the elements in non-zero. for (int i = 0; i < cpuFreqTimes.length; ++i) { if (cpuFreqTimes[i] != 0) { return cpuFreqTimes; } } return null; } @Override public ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() { return mWakelockStats.getMap(); Loading Loading @@ -6354,6 +6524,13 @@ public class BatteryStatsImpl extends BatteryStats { } } if (mCpuFreqTimeMs != null) { mCpuFreqTimeMs.reset(false); } if (mScreenOffCpuFreqTimeMs != null) { mScreenOffCpuFreqTimeMs.reset(false); } resetLongCounterIfNotNull(mMobileRadioApWakeupCount, false); resetLongCounterIfNotNull(mWifiRadioApWakeupCount, false); Loading Loading @@ -6523,6 +6700,13 @@ public class BatteryStatsImpl extends BatteryStats { } } if (mCpuFreqTimeMs != null) { mCpuFreqTimeMs.detach(); } if (mScreenOffCpuFreqTimeMs != null) { mScreenOffCpuFreqTimeMs.detach(); } detachLongCounterIfNotNull(mMobileRadioApWakeupCount); detachLongCounterIfNotNull(mWifiRadioApWakeupCount); } Loading Loading @@ -6739,6 +6923,19 @@ public class BatteryStatsImpl extends BatteryStats { out.writeInt(0); } if (mCpuFreqTimeMs != null) { out.writeInt(1); mCpuFreqTimeMs.writeToParcel(out); } else { out.writeInt(0); } if (mScreenOffCpuFreqTimeMs != null) { out.writeInt(1); mScreenOffCpuFreqTimeMs.writeToParcel(out); } else { out.writeInt(0); } if (mMobileRadioApWakeupCount != null) { out.writeInt(1); mMobileRadioApWakeupCount.writeToParcel(out); Loading Loading @@ -6986,6 +7183,18 @@ public class BatteryStatsImpl extends BatteryStats { mCpuClusterSpeed = null; } if (in.readInt() != 0) { mCpuFreqTimeMs = new LongSamplingCounterArray(mBsi.mOnBatteryTimeBase, in); } else { mCpuFreqTimeMs = null; } if (in.readInt() != 0) { mScreenOffCpuFreqTimeMs = new LongSamplingCounterArray( mBsi.mOnBatteryScreenOffTimeBase, in); } else { mScreenOffCpuFreqTimeMs = null; } if (in.readInt() != 0) { mMobileRadioApWakeupCount = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in); } else { Loading Loading @@ -8192,6 +8401,10 @@ public class BatteryStatsImpl extends BatteryStats { } } public long[] getCpuFreqs() { return mCpuFreqs; } public BatteryStatsImpl(File systemDir, Handler handler, ExternalStatsSync externalSync) { this(new SystemClocks(), systemDir, handler, externalSync, null); } Loading Loading @@ -9812,6 +10025,8 @@ public class BatteryStatsImpl extends BatteryStats { } }); readKernelUidCpuFreqTimesLocked(); final long elapse = (mClocks.elapsedRealtime() - startTimeMs); if (DEBUG_ENERGY_CPU || (elapse >= 100)) { Slog.d(TAG, "Reading cpu stats took " + elapse + " ms"); Loading Loading @@ -9900,6 +10115,30 @@ public class BatteryStatsImpl extends BatteryStats { } } void readKernelUidCpuFreqTimesLocked() { mKernelUidCpuFreqTimeReader.readDelta(!mOnBatteryInternal ? null : new KernelUidCpuFreqTimeReader.Callback() { @Override public void onCpuFreqs(long[] cpuFreqs) { mCpuFreqs = cpuFreqs; } @Override public void onUidCpuFreqTime(int uid, long[] cpuFreqTimeMs) { final Uid u = getUidStatsLocked(uid); if (u.mCpuFreqTimeMs == null) { u.mCpuFreqTimeMs = new LongSamplingCounterArray(mOnBatteryTimeBase); } u.mCpuFreqTimeMs.addCountLocked(cpuFreqTimeMs); if (u.mScreenOffCpuFreqTimeMs == null) { u.mScreenOffCpuFreqTimeMs = new LongSamplingCounterArray( mOnBatteryScreenOffTimeBase); } u.mScreenOffCpuFreqTimeMs.addCountLocked(cpuFreqTimeMs); } }); } boolean setChargingLocked(boolean charging) { if (mCharging != charging) { mCharging = charging; Loading Loading @@ -10988,6 +11227,8 @@ public class BatteryStatsImpl extends BatteryStats { } } mCpuFreqs = in.createLongArray(); final int NU = in.readInt(); if (NU > 10000) { throw new ParcelFormatException("File corrupt: too many uids " + NU); Loading Loading @@ -11110,6 +11351,20 @@ public class BatteryStatsImpl extends BatteryStats { u.mCpuClusterSpeed = null; } if (in.readInt() != 0) { u.mCpuFreqTimeMs = new LongSamplingCounterArray(mOnBatteryTimeBase); u.mCpuFreqTimeMs.readSummaryFromParcelLocked(in); } else { u.mCpuFreqTimeMs = null; } if (in.readInt() != 0) { u.mScreenOffCpuFreqTimeMs = new LongSamplingCounterArray( mOnBatteryScreenOffTimeBase); u.mScreenOffCpuFreqTimeMs.readSummaryFromParcelLocked(in); } else { u.mScreenOffCpuFreqTimeMs = null; } if (in.readInt() != 0) { u.mMobileRadioApWakeupCount = new LongSamplingCounter(mOnBatteryTimeBase); u.mMobileRadioApWakeupCount.readSummaryFromParcelLocked(in); Loading Loading @@ -11360,6 +11615,8 @@ public class BatteryStatsImpl extends BatteryStats { } } out.writeLongArray(mCpuFreqs); final int NU = mUidStats.size(); out.writeInt(NU); for (int iu = 0; iu < NU; iu++) { Loading Loading @@ -11504,6 +11761,19 @@ public class BatteryStatsImpl extends BatteryStats { out.writeInt(0); } if (u.mCpuFreqTimeMs != null) { out.writeInt(1); u.mCpuFreqTimeMs.writeSummaryFromParcelLocked(out); } else { out.writeInt(0); } if (u.mScreenOffCpuFreqTimeMs != null) { out.writeInt(1); u.mScreenOffCpuFreqTimeMs.writeSummaryFromParcelLocked(out); } else { out.writeInt(0); } if (u.mMobileRadioApWakeupCount != null) { out.writeInt(1); u.mMobileRadioApWakeupCount.writeSummaryFromParcelLocked(out); Loading Loading @@ -11794,6 +12064,8 @@ public class BatteryStatsImpl extends BatteryStats { mFlashlightTurnedOnTimers.clear(); mCameraTurnedOnTimers.clear(); mCpuFreqs = in.createLongArray(); int numUids = in.readInt(); mUidStats.clear(); for (int i = 0; i < numUids; i++) { Loading Loading @@ -11953,6 +12225,8 @@ public class BatteryStatsImpl extends BatteryStats { } } out.writeLongArray(mCpuFreqs); if (inclUids) { int size = mUidStats.size(); out.writeInt(size); Loading
core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java 0 → 100644 +117 −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.util.Slog; import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; /** * Reads /proc/uid_time_in_state which has the format: * * uid: [freq1] [freq2] [freq3] ... * [uid1]: [time in freq1] [time in freq2] [time in freq3] ... * [uid2]: [time in freq1] [time in freq2] [time in freq3] ... * ... * * This provides the times a UID's processes spent executing at each different cpu frequency. * 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 KernelUidCpuFreqTimeReader { private static final String TAG = "KernelUidCpuFreqTimeReader"; private static final String UID_TIMES_PROC_FILE = "/proc/uid_time_in_state"; public interface Callback { void onCpuFreqs(long[] cpuFreqs); void onUidCpuFreqTime(int uid, long[] cpuFreqTimeMs); } private long[] mCpuFreqs; private int mCpuFreqsCount; private SparseArray<long[]> mLastUidCpuFreqTimeMs = new SparseArray<>(); public void readDelta(@Nullable Callback callback) { try (BufferedReader reader = new BufferedReader(new FileReader(UID_TIMES_PROC_FILE))) { readDelta(reader, callback); } catch (IOException e) { Slog.e(TAG, "Failed to read " + UID_TIMES_PROC_FILE + ": " + e); } } @VisibleForTesting public void readDelta(BufferedReader reader, @Nullable Callback callback) throws IOException { String line = reader.readLine(); if (line == null) { return; } readCpuFreqs(line, callback); 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, line.length()), callback); } } private void readTimesForUid(int uid, String line, Callback callback) { long[] uidTimeMs = mLastUidCpuFreqTimeMs.get(uid); if (uidTimeMs == null) { uidTimeMs = new long[mCpuFreqsCount]; mLastUidCpuFreqTimeMs.put(uid, uidTimeMs); } final String[] timesStr = line.split(" "); final int size = timesStr.length; if (size != uidTimeMs.length) { Slog.e(TAG, "No. of readings don't match cpu freqs, readings: " + size + " cpuFreqsCount: " + uidTimeMs.length); return; } final long[] deltaUidTimeMs = new long[size]; for (int i = 0; i < size; ++i) { // Times read will be in units of 10ms final long totalTimeMs = Long.parseLong(timesStr[i], 10) * 10; deltaUidTimeMs[i] = totalTimeMs - uidTimeMs[i]; uidTimeMs[i] = totalTimeMs; } if (callback != null) { callback.onUidCpuFreqTime(uid, deltaUidTimeMs); } } private void readCpuFreqs(String line, Callback callback) { if (mCpuFreqs == null) { final String[] freqStr = line.split(" "); // First item would be "uid:" which needs to be ignored mCpuFreqsCount = freqStr.length - 1; mCpuFreqs = new long[mCpuFreqsCount]; for (int i = 0; i < mCpuFreqsCount; ++i) { mCpuFreqs[i] = Long.parseLong(freqStr[i + 1], 10); } } if (callback != null) { callback.onCpuFreqs(mCpuFreqs); } } }
core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java 0 → 100644 +109 −0 File added.Preview size limit exceeded, changes collapsed. Show changes