Merge "Add time spent by uid per cpu frequency to batterystats." into oc-dev
am: 5df9c5570e
Change-Id: Ia15bc54c61a692a37ad9b84a28643afc798b52c7
This commit is contained in:
@@ -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";
|
||||
@@ -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.
|
||||
*/
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
@@ -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) {
|
||||
@@ -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--) {
|
||||
@@ -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) {
|
||||
@@ -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--) {
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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();
|
||||
@@ -570,6 +574,8 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
|
||||
private final NetworkStats.Entry mTmpNetworkStatsEntry = new NetworkStats.Entry();
|
||||
|
||||
private long[] mCpuFreqs;
|
||||
|
||||
private PowerProfile mPowerProfile;
|
||||
|
||||
/*
|
||||
@@ -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;
|
||||
@@ -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.
|
||||
*/
|
||||
@@ -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();
|
||||
@@ -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);
|
||||
|
||||
@@ -6523,6 +6700,13 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
}
|
||||
}
|
||||
|
||||
if (mCpuFreqTimeMs != null) {
|
||||
mCpuFreqTimeMs.detach();
|
||||
}
|
||||
if (mScreenOffCpuFreqTimeMs != null) {
|
||||
mScreenOffCpuFreqTimeMs.detach();
|
||||
}
|
||||
|
||||
detachLongCounterIfNotNull(mMobileRadioApWakeupCount);
|
||||
detachLongCounterIfNotNull(mWifiRadioApWakeupCount);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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 {
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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");
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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++) {
|
||||
@@ -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);
|
||||
@@ -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++) {
|
||||
@@ -11953,6 +12225,8 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
}
|
||||
}
|
||||
|
||||
out.writeLongArray(mCpuFreqs);
|
||||
|
||||
if (inclUids) {
|
||||
int size = mUidStats.size();
|
||||
out.writeInt(size);
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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 static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
|
||||
/**
|
||||
* Test class for {@link KernelUidCpuFreqTimeReader}.
|
||||
*
|
||||
* To run the tests, use
|
||||
*
|
||||
* runtest -c com.android.internal.os.KernelUidCpuFreqTimeReaderTest frameworks-core
|
||||
*
|
||||
* or the following steps:
|
||||
*
|
||||
* Build: m FrameworksCoreTests
|
||||
* Install: adb install -r \
|
||||
* ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
|
||||
* Run: adb shell am instrument -e class com.android.internal.os.KernelUidCpuFreqTimeReaderTest -w \
|
||||
* com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
|
||||
*/
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class KernelUidCpuFreqTimeReaderTest {
|
||||
@Mock private BufferedReader mBufferedReader;
|
||||
@Mock private KernelUidCpuFreqTimeReader.Callback mCallback;
|
||||
|
||||
private KernelUidCpuFreqTimeReader mKernelUidCpuFreqTimeReader;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mKernelUidCpuFreqTimeReader = new KernelUidCpuFreqTimeReader();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadDelta() throws Exception {
|
||||
final long[] freqs = {1, 12, 123, 1234, 12345, 123456};
|
||||
final int[] uids = {1, 22, 333, 4444, 5555};
|
||||
final long[][] times = new long[uids.length][freqs.length];
|
||||
for (int i = 0; i < uids.length; ++i) {
|
||||
for (int j = 0; j < freqs.length; ++j) {
|
||||
times[i][j] = uids[i] * freqs[j] * 10;
|
||||
}
|
||||
}
|
||||
final String[] uidsTimesLines = getUidTimesLines(uids, times);
|
||||
final String[] lines = new String[uidsTimesLines.length + 1];
|
||||
System.arraycopy(uidsTimesLines, 0, lines, 0, uidsTimesLines.length);
|
||||
lines[uidsTimesLines.length] = null;
|
||||
when(mBufferedReader.readLine())
|
||||
.thenReturn(getFreqsLine(freqs), lines);
|
||||
mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback);
|
||||
verify(mCallback).onCpuFreqs(freqs);
|
||||
for (int i = 0; i < uids.length; ++i) {
|
||||
verify(mCallback).onUidCpuFreqTime(uids[i], times[i]);
|
||||
}
|
||||
verifyNoMoreInteractions(mCallback);
|
||||
}
|
||||
|
||||
private String getFreqsLine(long[] freqs) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("uid:");
|
||||
for (int i = 0; i < freqs.length; ++i) {
|
||||
sb.append(" " + freqs[i]);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String[] getUidTimesLines(int[] uids, long[][] times) {
|
||||
final String[] lines = new String[uids.length];
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < uids.length; ++i) {
|
||||
sb.setLength(0);
|
||||
sb.append(uids[i] + ":");
|
||||
for (int j = 0; j < times[i].length; ++j) {
|
||||
sb.append(" " + times[i][j] / 10);
|
||||
}
|
||||
lines[i] = sb.toString();
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user