Use LongArrayMultiStateCounter for proc-in-state time counting
The acquisition of eBPF's per-UID time-in-state data is now done in the native code, directly integrating with the native layer of LongArrayMultiStateCounter. Bug: 197162116 Test: atest FrameworksCoreTests:BatteryStatsImplTest atest FrameworksCoreTests:BstatsCpuTimesValidationTest atest FrameworksCoreTests:LongArrayMultiStateCounterTest atest FrameworksCoreTests:KernelSingleUidTimeReaderTest Change-Id: I1fdc747f272ecc0c35c51db39e442aac67d1b24c
This commit is contained in:
parent
ee014a0699
commit
2464cfb9d0
@ -77,7 +77,6 @@ import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.AtomicFile;
|
||||
import android.util.IndentingPrintWriter;
|
||||
import android.util.IntArray;
|
||||
import android.util.KeyValueListParser;
|
||||
import android.util.Log;
|
||||
import android.util.LongSparseArray;
|
||||
@ -161,7 +160,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
|
||||
|
||||
// Current on-disk Parcel version
|
||||
static final int VERSION = 200;
|
||||
static final int VERSION = 201;
|
||||
|
||||
// The maximum number of names wakelocks we will keep track of
|
||||
// per uid; once the limit is reached, we batch the remaining wakelocks
|
||||
@ -464,10 +463,12 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
uidStates = mPendingUids.clone();
|
||||
mPendingUids.clear();
|
||||
}
|
||||
final long timestampMs = mClock.elapsedRealtime();
|
||||
for (int i = uidStates.size() - 1; i >= 0; --i) {
|
||||
final int uid = uidStates.keyAt(i);
|
||||
final int procState = uidStates.valueAt(i);
|
||||
final int[] isolatedUids;
|
||||
final LongArrayMultiStateCounter[] isolatedUidTimeInFreqCounters;
|
||||
final Uid u;
|
||||
synchronized (BatteryStatsImpl.this) {
|
||||
// It's possible that uid no longer exists and any internal references have
|
||||
@ -479,26 +480,44 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
}
|
||||
if (u.mChildUids == null) {
|
||||
isolatedUids = null;
|
||||
isolatedUidTimeInFreqCounters = null;
|
||||
} else {
|
||||
isolatedUids = u.mChildUids.toArray();
|
||||
for (int j = isolatedUids.length - 1; j >= 0; --j) {
|
||||
isolatedUids[j] = u.mChildUids.get(j);
|
||||
int childUidCount = u.mChildUids.size();
|
||||
isolatedUids = new int[childUidCount];
|
||||
isolatedUidTimeInFreqCounters = new LongArrayMultiStateCounter[childUidCount];
|
||||
for (int j = childUidCount - 1; j >= 0; --j) {
|
||||
isolatedUids[j] = u.mChildUids.keyAt(j);
|
||||
isolatedUidTimeInFreqCounters[j] = u.mChildUids.valueAt(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
long[] cpuTimesMs = mKernelSingleUidTimeReader.readDeltaMs(uid);
|
||||
|
||||
LongArrayMultiStateCounter onBatteryCounter =
|
||||
u.getProcStateTimeCounter().getCounter();
|
||||
LongArrayMultiStateCounter onBatteryScreenOffCounter =
|
||||
u.getProcStateScreenOffTimeCounter().getCounter();
|
||||
|
||||
onBatteryCounter.setState(procState, timestampMs);
|
||||
mKernelSingleUidTimeReader.addDelta(uid, onBatteryCounter, timestampMs);
|
||||
|
||||
onBatteryScreenOffCounter.setState(procState, timestampMs);
|
||||
mKernelSingleUidTimeReader.addDelta(uid, onBatteryScreenOffCounter, timestampMs);
|
||||
|
||||
if (isolatedUids != null) {
|
||||
LongArrayMultiStateCounter.LongArrayContainer deltaContainer =
|
||||
new LongArrayMultiStateCounter.LongArrayContainer(getCpuFreqCount());
|
||||
for (int j = isolatedUids.length - 1; j >= 0; --j) {
|
||||
cpuTimesMs = addCpuTimes(cpuTimesMs,
|
||||
mKernelSingleUidTimeReader.readDeltaMs(isolatedUids[j]));
|
||||
}
|
||||
}
|
||||
if (onBattery && cpuTimesMs != null) {
|
||||
synchronized (BatteryStatsImpl.this) {
|
||||
u.addProcStateTimesMs(procState, cpuTimesMs, onBattery);
|
||||
u.addProcStateScreenOffTimesMs(procState, cpuTimesMs, onBatteryScreenOff);
|
||||
if (isolatedUidTimeInFreqCounters[j] != null) {
|
||||
mKernelSingleUidTimeReader.addDelta(isolatedUids[j],
|
||||
isolatedUidTimeInFreqCounters[j], timestampMs, deltaContainer);
|
||||
onBatteryCounter.addCounts(deltaContainer);
|
||||
onBatteryScreenOffCounter.addCounts(deltaContainer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onBatteryCounter.setState(u.mProcessState, timestampMs);
|
||||
onBatteryScreenOffCounter.setState(u.mProcessState, timestampMs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -537,6 +556,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(b/197162116): just get a list of UIDs
|
||||
final SparseArray<long[]> allUidCpuFreqTimesMs =
|
||||
mCpuUidFreqTimeReader.getAllUidCpuFreqTimeMs();
|
||||
// If the KernelSingleUidTimeReader has stale cpu times, then we shouldn't try to
|
||||
@ -553,24 +573,40 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
if (u == null) {
|
||||
continue;
|
||||
}
|
||||
final long[] cpuTimesMs = allUidCpuFreqTimesMs.valueAt(i);
|
||||
if (cpuTimesMs == null) {
|
||||
continue;
|
||||
|
||||
final int procState;
|
||||
final int idx = mPendingUids.indexOfKey(uid);
|
||||
if (idx >= 0) {
|
||||
procState = mPendingUids.valueAt(idx);
|
||||
mPendingUids.removeAt(idx);
|
||||
} else {
|
||||
procState = u.mProcessState;
|
||||
}
|
||||
final long[] deltaTimesMs = mKernelSingleUidTimeReader.computeDelta(
|
||||
uid, cpuTimesMs.clone());
|
||||
if (onBattery && deltaTimesMs != null) {
|
||||
final int procState;
|
||||
final int idx = mPendingUids.indexOfKey(uid);
|
||||
if (idx >= 0) {
|
||||
procState = mPendingUids.valueAt(idx);
|
||||
mPendingUids.removeAt(idx);
|
||||
} else {
|
||||
procState = u.mProcessState;
|
||||
}
|
||||
if (procState >= 0 && procState < Uid.NUM_PROCESS_STATE) {
|
||||
u.addProcStateTimesMs(procState, deltaTimesMs, onBattery);
|
||||
u.addProcStateScreenOffTimesMs(procState, deltaTimesMs, onBatteryScreenOff);
|
||||
|
||||
final long timestampMs = mClock.elapsedRealtime();
|
||||
final LongArrayMultiStateCounter onBatteryCounter =
|
||||
u.getProcStateTimeCounter().getCounter();
|
||||
final LongArrayMultiStateCounter onBatteryScreenOffCounter =
|
||||
u.getProcStateScreenOffTimeCounter().getCounter();
|
||||
|
||||
onBatteryCounter.setState(procState, timestampMs);
|
||||
mKernelSingleUidTimeReader.addDelta(uid, onBatteryCounter, timestampMs);
|
||||
|
||||
onBatteryScreenOffCounter.setState(procState, timestampMs);
|
||||
mKernelSingleUidTimeReader.addDelta(uid, onBatteryScreenOffCounter, timestampMs);
|
||||
|
||||
if (u.mChildUids != null) {
|
||||
final LongArrayMultiStateCounter.LongArrayContainer deltaContainer =
|
||||
new LongArrayMultiStateCounter.LongArrayContainer(getCpuFreqCount());
|
||||
for (int j = u.mChildUids.size() - 1; j >= 0; --j) {
|
||||
final LongArrayMultiStateCounter counter = u.mChildUids.valueAt(j);
|
||||
if (counter != null) {
|
||||
final int isolatedUid = u.mChildUids.keyAt(j);
|
||||
mKernelSingleUidTimeReader.addDelta(isolatedUid,
|
||||
counter, timestampMs, deltaContainer);
|
||||
onBatteryCounter.addCounts(deltaContainer);
|
||||
onBatteryScreenOffCounter.addCounts(deltaContainer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1653,6 +1689,97 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
}
|
||||
}
|
||||
|
||||
private static class TimeInFreqMultiStateCounter implements TimeBaseObs {
|
||||
private final TimeBase mTimeBase;
|
||||
private final LongArrayMultiStateCounter mCounter;
|
||||
|
||||
private TimeInFreqMultiStateCounter(TimeBase timeBase, Parcel in, long timestampMs) {
|
||||
mTimeBase = timeBase;
|
||||
mCounter = LongArrayMultiStateCounter.CREATOR.createFromParcel(in);
|
||||
mCounter.setEnabled(mTimeBase.isRunning(), timestampMs);
|
||||
timeBase.add(this);
|
||||
}
|
||||
|
||||
private TimeInFreqMultiStateCounter(TimeBase timeBase, int stateCount, int cpuFreqCount,
|
||||
long timestampMs) {
|
||||
mTimeBase = timeBase;
|
||||
mCounter = new LongArrayMultiStateCounter(stateCount, cpuFreqCount);
|
||||
mCounter.setEnabled(mTimeBase.isRunning(), timestampMs);
|
||||
timeBase.add(this);
|
||||
}
|
||||
|
||||
private void writeToParcel(Parcel out) {
|
||||
mCounter.writeToParcel(out, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeStarted(long elapsedRealtimeUs, long baseUptimeUs, long baseRealtimeUs) {
|
||||
mCounter.setEnabled(true, elapsedRealtimeUs / 1000);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeStopped(long elapsedRealtimeUs, long baseUptimeUs, long baseRealtimeUs) {
|
||||
mCounter.setEnabled(false, elapsedRealtimeUs / 1000);
|
||||
}
|
||||
|
||||
public LongArrayMultiStateCounter getCounter() {
|
||||
return mCounter;
|
||||
}
|
||||
|
||||
public int getStateCount() {
|
||||
return mCounter.getStateCount();
|
||||
}
|
||||
|
||||
public void setTrackingEnabled(boolean enabled, long timestampMs) {
|
||||
mCounter.setEnabled(enabled && mTimeBase.isRunning(), timestampMs);
|
||||
}
|
||||
|
||||
private void setState(int uidRunningState, long elapsedRealtimeMs) {
|
||||
mCounter.setState(uidRunningState, elapsedRealtimeMs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns accumulated counts for the specified state, or null if all counts are zero.
|
||||
*/
|
||||
@Nullable
|
||||
public long[] getCountsLocked(int which, int procState) {
|
||||
LongArrayMultiStateCounter.LongArrayContainer longArrayContainer =
|
||||
new LongArrayMultiStateCounter.LongArrayContainer(mCounter.getArrayLength());
|
||||
mCounter.getCounts(longArrayContainer, procState);
|
||||
final long[] counts = new long[mCounter.getArrayLength()];
|
||||
longArrayContainer.getValues(counts);
|
||||
|
||||
// Return counts only if at least one of the elements is non-zero.
|
||||
for (int i = counts.length - 1; i >= 0; --i) {
|
||||
if (counts[i] != 0) {
|
||||
return counts;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void logState(Printer pw, String prefix) {
|
||||
pw.println(prefix + "mCounter=" + mCounter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears state of this counter.
|
||||
*/
|
||||
@Override
|
||||
public boolean reset(boolean detachIfReset, long elapsedRealtimeUs /* unused */) {
|
||||
mCounter.reset();
|
||||
if (detachIfReset) {
|
||||
detach();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detach() {
|
||||
mTimeBase.remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static class LongSamplingCounter extends LongCounter implements TimeBaseObs {
|
||||
final TimeBase mTimeBase;
|
||||
@ -7300,10 +7427,10 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
LongSamplingCounterArray mScreenOffCpuFreqTimeMs;
|
||||
LongSamplingCounterArray mCpuClusterTimesMs;
|
||||
|
||||
LongSamplingCounterArray[] mProcStateTimeMs;
|
||||
LongSamplingCounterArray[] mProcStateScreenOffTimeMs;
|
||||
TimeInFreqMultiStateCounter mProcStateTimeMs;
|
||||
TimeInFreqMultiStateCounter mProcStateScreenOffTimeMs;
|
||||
|
||||
IntArray mChildUids;
|
||||
SparseArray<LongArrayMultiStateCounter> mChildUids;
|
||||
|
||||
/**
|
||||
* The statistics we have collected for this uid's wake locks.
|
||||
@ -7455,8 +7582,10 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void setProcessStateForTest(int procState) {
|
||||
public void setProcessStateForTest(int procState, long elapsedTimeMs) {
|
||||
mProcessState = procState;
|
||||
getProcStateTimeCounter().setState(procState, elapsedTimeMs);
|
||||
getProcStateScreenOffTimeCounter().setState(procState, elapsedTimeMs);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -7481,7 +7610,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
|
||||
@Override
|
||||
public long[] getCpuFreqTimes(int which, int procState) {
|
||||
if (which < 0 || which >= NUM_PROCESS_STATE) {
|
||||
if (procState < 0 || procState >= NUM_PROCESS_STATE) {
|
||||
return null;
|
||||
}
|
||||
if (mProcStateTimeMs == null) {
|
||||
@ -7491,12 +7620,13 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
mProcStateTimeMs = null;
|
||||
return null;
|
||||
}
|
||||
return nullIfAllZeros(mProcStateTimeMs[procState], which);
|
||||
|
||||
return mProcStateTimeMs.getCountsLocked(which, procState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long[] getScreenOffCpuFreqTimes(int which, int procState) {
|
||||
if (which < 0 || which >= NUM_PROCESS_STATE) {
|
||||
if (procState < 0 || procState >= NUM_PROCESS_STATE) {
|
||||
return null;
|
||||
}
|
||||
if (mProcStateScreenOffTimeMs == null) {
|
||||
@ -7506,7 +7636,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
mProcStateScreenOffTimeMs = null;
|
||||
return null;
|
||||
}
|
||||
return nullIfAllZeros(mProcStateScreenOffTimeMs[procState], which);
|
||||
return mProcStateScreenOffTimeMs.getCountsLocked(which, procState);
|
||||
}
|
||||
|
||||
public long getBinderCallCount() {
|
||||
@ -7525,15 +7655,26 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
|
||||
public void addIsolatedUid(int isolatedUid) {
|
||||
if (mChildUids == null) {
|
||||
mChildUids = new IntArray();
|
||||
} else if (mChildUids.indexOf(isolatedUid) >= 0) {
|
||||
mChildUids = new SparseArray<>();
|
||||
} else if (mChildUids.indexOfKey(isolatedUid) >= 0) {
|
||||
return;
|
||||
}
|
||||
mChildUids.add(isolatedUid);
|
||||
if (mBsi.trackPerProcStateCpuTimes()) {
|
||||
LongArrayMultiStateCounter counter =
|
||||
new LongArrayMultiStateCounter(1, mBsi.getCpuFreqCount());
|
||||
// Set initial values to all 0. This is a child UID and we want to include
|
||||
// the entirety of its CPU time-in-freq stats into the parent's stats.
|
||||
counter.updateValues(
|
||||
new LongArrayMultiStateCounter.LongArrayContainer(mBsi.getCpuFreqCount()),
|
||||
mBsi.mClock.elapsedRealtime());
|
||||
mChildUids.put(isolatedUid, counter);
|
||||
} else {
|
||||
mChildUids.put(isolatedUid, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeIsolatedUid(int isolatedUid) {
|
||||
final int idx = mChildUids == null ? -1 : mChildUids.indexOf(isolatedUid);
|
||||
final int idx = mChildUids == null ? -1 : mChildUids.indexOfKey(isolatedUid);
|
||||
if (idx < 0) {
|
||||
return;
|
||||
}
|
||||
@ -7557,31 +7698,37 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void addProcStateTimesMs(int procState, long[] cpuTimesMs, boolean onBattery) {
|
||||
if (mProcStateTimeMs == null) {
|
||||
mProcStateTimeMs = new LongSamplingCounterArray[NUM_PROCESS_STATE];
|
||||
private void ensureMultiStateCounters() {
|
||||
if (mProcStateTimeMs != null) {
|
||||
return;
|
||||
}
|
||||
if (mProcStateTimeMs[procState] == null
|
||||
|| mProcStateTimeMs[procState].getSize() != cpuTimesMs.length) {
|
||||
detachIfNotNull(mProcStateTimeMs[procState]);
|
||||
mProcStateTimeMs[procState] = new LongSamplingCounterArray(
|
||||
mBsi.mOnBatteryTimeBase);
|
||||
}
|
||||
mProcStateTimeMs[procState].addCountLocked(cpuTimesMs, onBattery);
|
||||
|
||||
final long timestampMs = mBsi.mClock.elapsedRealtime();
|
||||
mProcStateTimeMs =
|
||||
new TimeInFreqMultiStateCounter(mBsi.mOnBatteryTimeBase,
|
||||
NUM_PROCESS_STATE, mBsi.getCpuFreqCount(), timestampMs);
|
||||
mProcStateScreenOffTimeMs =
|
||||
new TimeInFreqMultiStateCounter(mBsi.mOnBatteryScreenOffTimeBase,
|
||||
NUM_PROCESS_STATE, mBsi.getCpuFreqCount(), timestampMs);
|
||||
}
|
||||
|
||||
private void addProcStateScreenOffTimesMs(int procState, long[] cpuTimesMs,
|
||||
boolean onBatteryScreenOff) {
|
||||
if (mProcStateScreenOffTimeMs == null) {
|
||||
mProcStateScreenOffTimeMs = new LongSamplingCounterArray[NUM_PROCESS_STATE];
|
||||
private TimeInFreqMultiStateCounter getProcStateTimeCounter() {
|
||||
ensureMultiStateCounters();
|
||||
return mProcStateTimeMs;
|
||||
}
|
||||
|
||||
private TimeInFreqMultiStateCounter getProcStateScreenOffTimeCounter() {
|
||||
ensureMultiStateCounters();
|
||||
return mProcStateScreenOffTimeMs;
|
||||
}
|
||||
|
||||
private void setProcStateTimesTrackingEnabled(boolean enabled, long timestampMs) {
|
||||
if (mProcStateTimeMs != null) {
|
||||
mProcStateTimeMs.setTrackingEnabled(enabled, timestampMs);
|
||||
}
|
||||
if (mProcStateScreenOffTimeMs[procState] == null
|
||||
|| mProcStateScreenOffTimeMs[procState].getSize() != cpuTimesMs.length) {
|
||||
detachIfNotNull(mProcStateScreenOffTimeMs[procState]);
|
||||
mProcStateScreenOffTimeMs[procState] = new LongSamplingCounterArray(
|
||||
mBsi.mOnBatteryScreenOffTimeBase);
|
||||
if (mProcStateScreenOffTimeMs != null) {
|
||||
mProcStateScreenOffTimeMs.setTrackingEnabled(enabled, timestampMs);
|
||||
}
|
||||
mProcStateScreenOffTimeMs[procState].addCountLocked(cpuTimesMs, onBatteryScreenOff);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -9108,18 +9255,14 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
mCpuClusterTimesMs.writeToParcel(out);
|
||||
|
||||
if (mProcStateTimeMs != null) {
|
||||
out.writeInt(mProcStateTimeMs.length);
|
||||
for (LongSamplingCounterArray counters : mProcStateTimeMs) {
|
||||
LongSamplingCounterArray.writeToParcel(out, counters);
|
||||
}
|
||||
out.writeInt(mProcStateTimeMs.getStateCount());
|
||||
mProcStateTimeMs.writeToParcel(out);
|
||||
} else {
|
||||
out.writeInt(0);
|
||||
}
|
||||
if (mProcStateScreenOffTimeMs != null) {
|
||||
out.writeInt(mProcStateScreenOffTimeMs.length);
|
||||
for (LongSamplingCounterArray counters : mProcStateScreenOffTimeMs) {
|
||||
LongSamplingCounterArray.writeToParcel(out, counters);
|
||||
}
|
||||
out.writeInt(mProcStateScreenOffTimeMs.getStateCount());
|
||||
mProcStateScreenOffTimeMs.writeToParcel(out);
|
||||
} else {
|
||||
out.writeInt(0);
|
||||
}
|
||||
@ -9412,22 +9555,27 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
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];
|
||||
for (int procState = 0; procState < length; ++procState) {
|
||||
mProcStateTimeMs[procState] = LongSamplingCounterArray.readFromParcel(
|
||||
in, mBsi.mOnBatteryTimeBase);
|
||||
final long timestampMs = mBsi.mClock.elapsedRealtime();
|
||||
int stateCount = in.readInt();
|
||||
if (stateCount != 0) {
|
||||
// Read the object from the Parcel, whether it's usable or not
|
||||
TimeInFreqMultiStateCounter counter = new TimeInFreqMultiStateCounter(
|
||||
mBsi.mOnBatteryTimeBase, in, timestampMs);
|
||||
if (stateCount == NUM_PROCESS_STATE) {
|
||||
mProcStateTimeMs = counter;
|
||||
}
|
||||
} else {
|
||||
mProcStateTimeMs = null;
|
||||
}
|
||||
length = in.readInt();
|
||||
if (length == NUM_PROCESS_STATE) {
|
||||
mProcStateScreenOffTimeMs = new LongSamplingCounterArray[length];
|
||||
for (int procState = 0; procState < length; ++procState) {
|
||||
mProcStateScreenOffTimeMs[procState] = LongSamplingCounterArray.readFromParcel(
|
||||
in, mBsi.mOnBatteryScreenOffTimeBase);
|
||||
|
||||
stateCount = in.readInt();
|
||||
if (stateCount != 0) {
|
||||
// Read the object from the Parcel, whether it's usable or not
|
||||
TimeInFreqMultiStateCounter counter =
|
||||
new TimeInFreqMultiStateCounter(
|
||||
mBsi.mOnBatteryScreenOffTimeBase, in, timestampMs);
|
||||
if (stateCount == NUM_PROCESS_STATE) {
|
||||
mProcStateScreenOffTimeMs = counter;
|
||||
}
|
||||
} else {
|
||||
mProcStateScreenOffTimeMs = null;
|
||||
@ -10603,6 +10751,16 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
return mCpuFreqs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of frequencies across all CPU clusters.
|
||||
*/
|
||||
private int getCpuFreqCount() {
|
||||
if (mCpuFreqs == null) {
|
||||
mCpuFreqs = mCpuUidFreqTimeReader.readFreqs(mPowerProfile);
|
||||
}
|
||||
return mCpuFreqs != null ? mCpuFreqs.length : 0;
|
||||
}
|
||||
|
||||
public BatteryStatsImpl(File systemDir, Handler handler, PlatformIdleStateCallback cb,
|
||||
MeasuredEnergyRetriever energyStatsCb, UserInfoProvider userInfoProvider) {
|
||||
this(Clock.SYSTEM_CLOCK, systemDir, handler, cb, energyStatsCb, userInfoProvider);
|
||||
@ -14747,6 +14905,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
DEFAULT_BATTERY_CHARGED_DELAY_MS);
|
||||
}
|
||||
|
||||
@GuardedBy("BatteryStatsImpl.this")
|
||||
private void updateTrackCpuTimesByProcStateLocked(boolean wasEnabled, boolean isEnabled) {
|
||||
TRACK_CPU_TIMES_BY_PROC_STATE = isEnabled;
|
||||
if (isEnabled && !wasEnabled) {
|
||||
@ -14757,6 +14916,10 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
mNumBatchedSingleUidCpuTimeReads = 0;
|
||||
mCpuTimeReadsTrackingStartTimeMs = mClock.uptimeMillis();
|
||||
}
|
||||
final long timestampMs = mClock.elapsedRealtime();
|
||||
for (int i = mUidStats.size() - 1; i >= 0; i--) {
|
||||
mUidStats.valueAt(i).setProcStateTimesTrackingEnabled(isEnabled, timestampMs);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateProcStateCpuTimesReadDelayMs(long oldDelayMillis, long newDelayMillis) {
|
||||
@ -15531,31 +15694,32 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
u.mCpuActiveTimeMs.readSummaryFromParcelLocked(in);
|
||||
u.mCpuClusterTimesMs.readSummaryFromParcelLocked(in);
|
||||
|
||||
int length = in.readInt();
|
||||
if (length == Uid.NUM_PROCESS_STATE) {
|
||||
detachIfNotNull(u.mProcStateTimeMs);
|
||||
u.mProcStateTimeMs = new LongSamplingCounterArray[length];
|
||||
for (int procState = 0; procState < length; ++procState) {
|
||||
u.mProcStateTimeMs[procState]
|
||||
= LongSamplingCounterArray.readSummaryFromParcelLocked(
|
||||
in, mOnBatteryTimeBase);
|
||||
detachIfNotNull(u.mProcStateTimeMs);
|
||||
u.mProcStateTimeMs = null;
|
||||
|
||||
int stateCount = in.readInt();
|
||||
if (stateCount != 0) {
|
||||
// Read the object from the Parcel, whether it's usable or not
|
||||
TimeInFreqMultiStateCounter counter = new TimeInFreqMultiStateCounter(
|
||||
mOnBatteryTimeBase, in, mClock.elapsedRealtime());
|
||||
if (stateCount == Uid.NUM_PROCESS_STATE) {
|
||||
u.mProcStateTimeMs = counter;
|
||||
}
|
||||
} else {
|
||||
detachIfNotNull(u.mProcStateTimeMs);
|
||||
u.mProcStateTimeMs = null;
|
||||
}
|
||||
length = in.readInt();
|
||||
if (length == Uid.NUM_PROCESS_STATE) {
|
||||
|
||||
detachIfNotNull(u.mProcStateScreenOffTimeMs);
|
||||
u.mProcStateScreenOffTimeMs = null;
|
||||
|
||||
stateCount = in.readInt();
|
||||
if (stateCount != 0) {
|
||||
detachIfNotNull(u.mProcStateScreenOffTimeMs);
|
||||
u.mProcStateScreenOffTimeMs = new LongSamplingCounterArray[length];
|
||||
for (int procState = 0; procState < length; ++procState) {
|
||||
u.mProcStateScreenOffTimeMs[procState]
|
||||
= LongSamplingCounterArray.readSummaryFromParcelLocked(
|
||||
in, mOnBatteryScreenOffTimeBase);
|
||||
// Read the object from the Parcel, whether it's usable or not
|
||||
TimeInFreqMultiStateCounter counter =
|
||||
new TimeInFreqMultiStateCounter(
|
||||
mOnBatteryScreenOffTimeBase, in, mClock.elapsedRealtime());
|
||||
if (stateCount == Uid.NUM_PROCESS_STATE) {
|
||||
u.mProcStateScreenOffTimeMs = counter;
|
||||
}
|
||||
} else {
|
||||
detachIfNotNull(u.mProcStateScreenOffTimeMs);
|
||||
u.mProcStateScreenOffTimeMs = null;
|
||||
}
|
||||
|
||||
if (in.readInt() != 0) {
|
||||
@ -16058,18 +16222,15 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
u.mCpuClusterTimesMs.writeSummaryToParcelLocked(out);
|
||||
|
||||
if (u.mProcStateTimeMs != null) {
|
||||
out.writeInt(u.mProcStateTimeMs.length);
|
||||
for (LongSamplingCounterArray counters : u.mProcStateTimeMs) {
|
||||
LongSamplingCounterArray.writeSummaryToParcelLocked(out, counters);
|
||||
}
|
||||
out.writeInt(u.mProcStateTimeMs.getStateCount());
|
||||
u.mProcStateTimeMs.writeToParcel(out);
|
||||
} else {
|
||||
out.writeInt(0);
|
||||
}
|
||||
|
||||
if (u.mProcStateScreenOffTimeMs != null) {
|
||||
out.writeInt(u.mProcStateScreenOffTimeMs.length);
|
||||
for (LongSamplingCounterArray counters : u.mProcStateScreenOffTimeMs) {
|
||||
LongSamplingCounterArray.writeSummaryToParcelLocked(out, counters);
|
||||
}
|
||||
out.writeInt(u.mProcStateScreenOffTimeMs.getStateCount());
|
||||
u.mProcStateScreenOffTimeMs.writeToParcel(out);
|
||||
} else {
|
||||
out.writeInt(0);
|
||||
}
|
||||
|
@ -243,6 +243,23 @@ public class KernelSingleUidTimeReader {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves CPU time-in-state data for the specified UID and adds the accumulated
|
||||
* delta to the supplied counter.
|
||||
*/
|
||||
public void addDelta(int uid, LongArrayMultiStateCounter counter, long timestampMs) {
|
||||
mInjector.addDelta(uid, counter, timestampMs, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #addDelta(int, LongArrayMultiStateCounter, long)}, also returning
|
||||
* the delta in the supplied array container.
|
||||
*/
|
||||
public void addDelta(int uid, LongArrayMultiStateCounter counter, long timestampMs,
|
||||
LongArrayMultiStateCounter.LongArrayContainer deltaContainer) {
|
||||
mInjector.addDelta(uid, counter, timestampMs, deltaContainer);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static class Injector {
|
||||
public byte[] readData(String procFile) throws IOException {
|
||||
@ -254,14 +271,19 @@ public class KernelSingleUidTimeReader {
|
||||
/**
|
||||
* Reads CPU time-in-state data for the specified UID and adds the delta since the
|
||||
* previous call to the current state stats in the LongArrayMultiStateCounter.
|
||||
*
|
||||
* The delta is also returned via the optional deltaOut parameter.
|
||||
*/
|
||||
public boolean addDelta(int uid, LongArrayMultiStateCounter counter, long timestampMs) {
|
||||
return addDeltaFromBpf(uid, counter.mNativeObject, timestampMs);
|
||||
public boolean addDelta(int uid, LongArrayMultiStateCounter counter, long timestampMs,
|
||||
LongArrayMultiStateCounter.LongArrayContainer deltaOut) {
|
||||
return addDeltaFromBpf(uid, counter.mNativeObject, timestampMs,
|
||||
deltaOut != null ? deltaOut.mNativeObject : 0);
|
||||
}
|
||||
|
||||
@CriticalNative
|
||||
private static native boolean addDeltaFromBpf(int uid,
|
||||
long longArrayMultiStateCounterNativePointer, long timestampMs);
|
||||
long longArrayMultiStateCounterNativePointer, long timestampMs,
|
||||
long longArrayContainerNativePointer);
|
||||
|
||||
/**
|
||||
* Used for testing.
|
||||
@ -269,13 +291,15 @@ public class KernelSingleUidTimeReader {
|
||||
* Takes mock cpu-time-in-frequency data and uses it the same way eBPF data would be used.
|
||||
*/
|
||||
public boolean addDeltaForTest(int uid, LongArrayMultiStateCounter counter,
|
||||
long timestampMs, long[][] timeInFreqDataNanos) {
|
||||
return addDeltaForTest(uid, counter.mNativeObject, timestampMs, timeInFreqDataNanos);
|
||||
long timestampMs, long[][] timeInFreqDataNanos,
|
||||
LongArrayMultiStateCounter.LongArrayContainer deltaOut) {
|
||||
return addDeltaForTest(uid, counter.mNativeObject, timestampMs, timeInFreqDataNanos,
|
||||
deltaOut != null ? deltaOut.mNativeObject : 0);
|
||||
}
|
||||
|
||||
private static native boolean addDeltaForTest(int uid,
|
||||
long longArrayMultiStateCounterNativePointer, long timestampMs,
|
||||
long[][] timeInFreqDataNanos);
|
||||
long[][] timeInFreqDataNanos, long longArrayContainerNativePointer);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
@ -26,6 +26,8 @@ import dalvik.annotation.optimization.FastNative;
|
||||
|
||||
import libcore.util.NativeAllocationRegistry;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Performs per-state counting of multi-element values over time. The class' behavior is illustrated
|
||||
* by this example:
|
||||
@ -62,7 +64,9 @@ public final class LongArrayMultiStateCounter implements Parcelable {
|
||||
NativeAllocationRegistry.createMalloced(
|
||||
LongArrayContainer.class.getClassLoader(), native_getReleaseFunc());
|
||||
|
||||
private final long mNativeObject;
|
||||
// Visible to other objects in this package so that it can be passed to @CriticalNative
|
||||
// methods.
|
||||
final long mNativeObject;
|
||||
private final int mLength;
|
||||
|
||||
public LongArrayContainer(int length) {
|
||||
@ -93,6 +97,13 @@ public final class LongArrayMultiStateCounter implements Parcelable {
|
||||
native_getValues(mNativeObject, array);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final long[] array = new long[mLength];
|
||||
getValues(array);
|
||||
return Arrays.toString(array);
|
||||
}
|
||||
|
||||
@CriticalNative
|
||||
private static native long native_init(int length);
|
||||
|
||||
@ -133,6 +144,14 @@ public final class LongArrayMultiStateCounter implements Parcelable {
|
||||
mLength = native_getArrayLength(mNativeObject);
|
||||
}
|
||||
|
||||
public int getStateCount() {
|
||||
return mStateCount;
|
||||
}
|
||||
|
||||
public int getArrayLength() {
|
||||
return mLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables the counter. When the counter is disabled, it does not
|
||||
* accumulate counts supplied by the {@link #updateValues} method.
|
||||
@ -147,7 +166,7 @@ public final class LongArrayMultiStateCounter implements Parcelable {
|
||||
public void setState(int state, long timestampMs) {
|
||||
if (state < 0 || state >= mStateCount) {
|
||||
throw new IllegalArgumentException(
|
||||
"State: " + state + ", outside the range: [0-" + mStateCount + "]");
|
||||
"State: " + state + ", outside the range: [0-" + (mStateCount - 1) + "]");
|
||||
}
|
||||
native_setState(mNativeObject, state, timestampMs);
|
||||
}
|
||||
@ -166,6 +185,17 @@ public final class LongArrayMultiStateCounter implements Parcelable {
|
||||
native_updateValues(mNativeObject, longArrayContainer.mNativeObject, timestampMs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the supplied values to the current accumulated values in the counter.
|
||||
*/
|
||||
public void addCounts(LongArrayContainer counts) {
|
||||
if (counts.mLength != mLength) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid array length: " + counts.mLength + ", expected: " + mLength);
|
||||
}
|
||||
native_addCounts(mNativeObject, counts.mNativeObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the accumulated counts to 0.
|
||||
*/
|
||||
@ -230,6 +260,10 @@ public final class LongArrayMultiStateCounter implements Parcelable {
|
||||
private static native void native_updateValues(long nativeObject,
|
||||
long longArrayContainerNativeObject, long timestampMs);
|
||||
|
||||
@CriticalNative
|
||||
private static native void native_addCounts(long nativeObject,
|
||||
long longArrayContainerNativeObject);
|
||||
|
||||
@CriticalNative
|
||||
private static native void native_reset(long nativeObject);
|
||||
|
||||
|
@ -50,7 +50,8 @@ static jlongArray getUidCpuFreqTimeMs(JNIEnv *env, jclass, jint uid) {
|
||||
*/
|
||||
static jboolean addCpuTimeInFreqDelta(
|
||||
jint uid, jlong counterNativePtr, jlong timestampMs,
|
||||
std::optional<std::vector<std::vector<uint64_t>>> timeInFreqDataNanos) {
|
||||
std::optional<std::vector<std::vector<uint64_t>>> timeInFreqDataNanos,
|
||||
jlong deltaOutContainerNativePtr) {
|
||||
if (!timeInFreqDataNanos) {
|
||||
return false;
|
||||
}
|
||||
@ -70,20 +71,35 @@ static jboolean addCpuTimeInFreqDelta(
|
||||
for (size_t i = 0; i < s; ++i) {
|
||||
flattened[i] /= NSEC_PER_MSEC;
|
||||
}
|
||||
counter->updateValue(flattened, timestampMs);
|
||||
if (s != counter->getCount(0).size()) { // Counter has at least one state
|
||||
ALOGE("Mismatch between eBPF data size (%d) and the counter size (%d)", (int)s,
|
||||
(int)counter->getCount(0).size());
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::vector<uint64_t> &delta = counter->updateValue(flattened, timestampMs);
|
||||
if (deltaOutContainerNativePtr) {
|
||||
std::vector<uint64_t> *vector =
|
||||
reinterpret_cast<std::vector<uint64_t> *>(deltaOutContainerNativePtr);
|
||||
*vector = delta;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static jboolean addDeltaFromBpf(jint uid, jlong counterNativePtr, jlong timestampMs) {
|
||||
static jboolean addDeltaFromBpf(jint uid, jlong counterNativePtr, jlong timestampMs,
|
||||
jlong deltaOutContainerNativePtr) {
|
||||
return addCpuTimeInFreqDelta(uid, counterNativePtr, timestampMs,
|
||||
android::bpf::getUidCpuFreqTimes(uid));
|
||||
android::bpf::getUidCpuFreqTimes(uid), deltaOutContainerNativePtr);
|
||||
}
|
||||
|
||||
static jboolean addDeltaForTest(JNIEnv *env, jclass, jint uid, jlong counterNativePtr,
|
||||
jlong timestampMs, jobjectArray timeInFreqDataNanos) {
|
||||
jlong timestampMs, jobjectArray timeInFreqDataNanos,
|
||||
jlong deltaOutContainerNativePtr) {
|
||||
if (!timeInFreqDataNanos) {
|
||||
return addCpuTimeInFreqDelta(uid, counterNativePtr, timestampMs,
|
||||
std::optional<std::vector<std::vector<uint64_t>>>());
|
||||
std::optional<std::vector<std::vector<uint64_t>>>(),
|
||||
deltaOutContainerNativePtr);
|
||||
}
|
||||
|
||||
std::vector<std::vector<uint64_t>> timeInFreqData;
|
||||
@ -97,17 +113,18 @@ static jboolean addDeltaForTest(JNIEnv *env, jclass, jint uid, jlong counterNati
|
||||
}
|
||||
timeInFreqData.push_back(cluster);
|
||||
}
|
||||
return addCpuTimeInFreqDelta(uid, counterNativePtr, timestampMs, std::optional(timeInFreqData));
|
||||
return addCpuTimeInFreqDelta(uid, counterNativePtr, timestampMs, std::optional(timeInFreqData),
|
||||
deltaOutContainerNativePtr);
|
||||
}
|
||||
|
||||
static const JNINativeMethod g_single_methods[] = {
|
||||
{"readBpfData", "(I)[J", (void *)getUidCpuFreqTimeMs},
|
||||
|
||||
// @CriticalNative
|
||||
{"addDeltaFromBpf", "(IJJ)Z", (void *)addDeltaFromBpf},
|
||||
{"addDeltaFromBpf", "(IJJJ)Z", (void *)addDeltaFromBpf},
|
||||
|
||||
// Used for testing
|
||||
{"addDeltaForTest", "(IJJ[[J)Z", (void *)addDeltaForTest},
|
||||
{"addDeltaForTest", "(IJJ[[JJ)Z", (void *)addDeltaForTest},
|
||||
};
|
||||
|
||||
int register_com_android_internal_os_KernelSingleUidTimeReader(JNIEnv *env) {
|
||||
|
@ -65,6 +65,14 @@ static void native_updateValues(jlong nativePtr, jlong longArrayContainerNativeP
|
||||
counter->updateValue(*vector, timestamp);
|
||||
}
|
||||
|
||||
static void native_addCounts(jlong nativePtr, jlong longArrayContainerNativePtr) {
|
||||
battery::LongArrayMultiStateCounter *counter =
|
||||
reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
|
||||
std::vector<uint64_t> *vector =
|
||||
reinterpret_cast<std::vector<uint64_t> *>(longArrayContainerNativePtr);
|
||||
counter->addValue(*vector);
|
||||
}
|
||||
|
||||
static void native_reset(jlong nativePtr) {
|
||||
battery::LongArrayMultiStateCounter *counter =
|
||||
reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
|
||||
@ -184,6 +192,8 @@ static const JNINativeMethod g_LongArrayMultiStateCounter_methods[] = {
|
||||
// @CriticalNative
|
||||
{"native_updateValues", "(JJJ)V", (void *)native_updateValues},
|
||||
// @CriticalNative
|
||||
{"native_addCounts", "(JJ)V", (void *)native_addCounts},
|
||||
// @CriticalNative
|
||||
{"native_reset", "(J)V", (void *)native_reset},
|
||||
// @CriticalNative
|
||||
{"native_getCounts", "(JJI)V", (void *)native_getCounts},
|
||||
|
@ -27,10 +27,13 @@ import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.os.BatteryStats;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseIntArray;
|
||||
@ -40,20 +43,19 @@ import androidx.test.filters.LargeTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentMatcher;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@LargeTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class BatteryStatsImplTest {
|
||||
private static final long[] CPU_FREQS = {1, 2, 3, 4, 5};
|
||||
private static final int NUM_CPU_FREQS = CPU_FREQS.length;
|
||||
|
||||
@Mock
|
||||
private KernelCpuUidFreqTimeReader mKernelUidCpuFreqTimeReader;
|
||||
@Mock
|
||||
@ -61,13 +63,16 @@ public class BatteryStatsImplTest {
|
||||
|
||||
private MockBatteryStatsImpl mBatteryStatsImpl;
|
||||
|
||||
private MockClock mMockClock = new MockClock();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
when(mKernelUidCpuFreqTimeReader.readFreqs(any())).thenReturn(CPU_FREQS);
|
||||
when(mKernelUidCpuFreqTimeReader.allUidTimesAvailable()).thenReturn(true);
|
||||
when(mKernelSingleUidTimeReader.singleUidCpuTimesAvailable()).thenReturn(true);
|
||||
mBatteryStatsImpl = new MockBatteryStatsImpl()
|
||||
mBatteryStatsImpl = new MockBatteryStatsImpl(mMockClock)
|
||||
.setKernelCpuUidFreqTimeReader(mKernelUidCpuFreqTimeReader)
|
||||
.setKernelSingleUidTimeReader(mKernelSingleUidTimeReader)
|
||||
.setTrackingCpuByProcStateEnabled(true);
|
||||
@ -76,9 +81,17 @@ public class BatteryStatsImplTest {
|
||||
@Test
|
||||
public void testUpdateProcStateCpuTimes() {
|
||||
mBatteryStatsImpl.setOnBatteryInternal(true);
|
||||
mBatteryStatsImpl.updateTimeBasesLocked(false, Display.STATE_ON, 0, 0);
|
||||
synchronized (mBatteryStatsImpl) {
|
||||
mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
|
||||
}
|
||||
|
||||
final int[] testUids = {10032, 10048, 10145, 10139};
|
||||
final int[] activityManagerProcStates = {
|
||||
ActivityManager.PROCESS_STATE_RECEIVER,
|
||||
ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
|
||||
ActivityManager.PROCESS_STATE_TOP,
|
||||
ActivityManager.PROCESS_STATE_CACHED_EMPTY
|
||||
};
|
||||
final int[] testProcStates = {
|
||||
PROCESS_STATE_BACKGROUND,
|
||||
PROCESS_STATE_FOREGROUND_SERVICE,
|
||||
@ -86,14 +99,24 @@ public class BatteryStatsImplTest {
|
||||
PROCESS_STATE_CACHED
|
||||
};
|
||||
addPendingUids(testUids, testProcStates);
|
||||
|
||||
// Initialize time-in-freq counters
|
||||
mMockClock.realtime = 1000;
|
||||
for (int i = 0; i < testUids.length; ++i) {
|
||||
mBatteryStatsImpl.noteUidProcessStateLocked(testUids[i], activityManagerProcStates[i]);
|
||||
mockKernelSingleUidTimeReader(testUids[i], new long[5]);
|
||||
}
|
||||
mBatteryStatsImpl.updateProcStateCpuTimes(true, false);
|
||||
|
||||
// Obtain initial CPU time-in-freq counts
|
||||
final long[][] cpuTimes = {
|
||||
{349734983, 394982394832l, 909834, 348934, 9838},
|
||||
{349734983, 394982394832L, 909834, 348934, 9838},
|
||||
{7498, 1239890, 988, 13298, 98980},
|
||||
{989834, 384098, 98483, 23809, 4984},
|
||||
{4859048, 348903, 4578967, 5973894, 298549}
|
||||
};
|
||||
for (int i = 0; i < testUids.length; ++i) {
|
||||
when(mKernelSingleUidTimeReader.readDeltaMs(testUids[i])).thenReturn(cpuTimes[i]);
|
||||
mockKernelSingleUidTimeReader(testUids[i], cpuTimes[i]);
|
||||
|
||||
// Verify there are no cpu times initially.
|
||||
final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUids[i]);
|
||||
@ -102,7 +125,9 @@ public class BatteryStatsImplTest {
|
||||
assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState));
|
||||
}
|
||||
}
|
||||
addPendingUids(testUids, testProcStates);
|
||||
|
||||
mMockClock.realtime += 1000;
|
||||
mBatteryStatsImpl.updateProcStateCpuTimes(true, false);
|
||||
|
||||
verifyNoPendingUids();
|
||||
@ -119,6 +144,7 @@ public class BatteryStatsImplTest {
|
||||
}
|
||||
}
|
||||
|
||||
// Accumulate CPU time-in-freq deltas
|
||||
final long[][] delta1 = {
|
||||
{9589, 148934, 309894, 3098493, 98754},
|
||||
{21983, 94983, 4983, 9878493, 84854},
|
||||
@ -126,10 +152,15 @@ public class BatteryStatsImplTest {
|
||||
{843895, 43948, 949582, 99, 384}
|
||||
};
|
||||
for (int i = 0; i < testUids.length; ++i) {
|
||||
when(mKernelSingleUidTimeReader.readDeltaMs(testUids[i])).thenReturn(delta1[i]);
|
||||
long[] newCpuTimes = new long[cpuTimes[i].length];
|
||||
for (int j = 0; j < cpuTimes[i].length; j++) {
|
||||
newCpuTimes[j] = cpuTimes[i][j] + delta1[i][j];
|
||||
}
|
||||
mockKernelSingleUidTimeReader(testUids[i], newCpuTimes);
|
||||
}
|
||||
addPendingUids(testUids, testProcStates);
|
||||
|
||||
mMockClock.realtime += 1000;
|
||||
mBatteryStatsImpl.updateProcStateCpuTimes(true, false);
|
||||
|
||||
verifyNoPendingUids();
|
||||
@ -150,7 +181,12 @@ public class BatteryStatsImplTest {
|
||||
}
|
||||
}
|
||||
|
||||
mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
|
||||
// Validate the on-battery-screen-off counter
|
||||
synchronized (mBatteryStatsImpl) {
|
||||
mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0,
|
||||
mMockClock.realtime * 1000);
|
||||
}
|
||||
|
||||
final long[][] delta2 = {
|
||||
{95932, 2943, 49834, 89034, 139},
|
||||
{349, 89605, 5896, 845, 98444},
|
||||
@ -158,10 +194,15 @@ public class BatteryStatsImplTest {
|
||||
{488, 998, 8498, 394, 574}
|
||||
};
|
||||
for (int i = 0; i < testUids.length; ++i) {
|
||||
when(mKernelSingleUidTimeReader.readDeltaMs(testUids[i])).thenReturn(delta2[i]);
|
||||
long[] newCpuTimes = new long[cpuTimes[i].length];
|
||||
for (int j = 0; j < cpuTimes[i].length; j++) {
|
||||
newCpuTimes[j] = cpuTimes[i][j] + delta1[i][j] + delta2[i][j];
|
||||
}
|
||||
mockKernelSingleUidTimeReader(testUids[i], newCpuTimes);
|
||||
}
|
||||
addPendingUids(testUids, testProcStates);
|
||||
|
||||
mMockClock.realtime += 1000;
|
||||
mBatteryStatsImpl.updateProcStateCpuTimes(true, true);
|
||||
|
||||
verifyNoPendingUids();
|
||||
@ -184,6 +225,10 @@ public class BatteryStatsImplTest {
|
||||
}
|
||||
}
|
||||
|
||||
// Verify handling of isolated UIDs - their time-in-freq must be directly
|
||||
// added to that of the parent UID's. The proc state of the isolated UID is
|
||||
// assumed to be the same as that of the parent UID, so there is no per-state
|
||||
// data for isolated UIDs.
|
||||
final long[][] delta3 = {
|
||||
{98545, 95768795, 76586, 548945, 57846},
|
||||
{788876, 586, 578459, 8776984, 9578923},
|
||||
@ -191,16 +236,20 @@ public class BatteryStatsImplTest {
|
||||
{9493, 784, 99895, 8974893, 9879843}
|
||||
};
|
||||
for (int i = 0; i < testUids.length; ++i) {
|
||||
when(mKernelSingleUidTimeReader.readDeltaMs(testUids[i])).thenReturn(
|
||||
delta3[i].clone());
|
||||
long[] newCpuTimes = new long[cpuTimes[i].length];
|
||||
for (int j = 0; j < cpuTimes[i].length; j++) {
|
||||
newCpuTimes[j] = cpuTimes[i][j] + delta1[i][j] + delta2[i][j] + delta3[i][j];
|
||||
}
|
||||
mockKernelSingleUidTimeReader(testUids[i], newCpuTimes);
|
||||
}
|
||||
addPendingUids(testUids, testProcStates);
|
||||
final int parentUid = testUids[1];
|
||||
final int childUid = 99099;
|
||||
addIsolatedUid(parentUid, childUid);
|
||||
final long[] isolatedUidCpuTimes = {495784, 398473, 4895, 4905, 30984093};
|
||||
when(mKernelSingleUidTimeReader.readDeltaMs(childUid)).thenReturn(isolatedUidCpuTimes);
|
||||
mockKernelSingleUidTimeReader(childUid, isolatedUidCpuTimes, isolatedUidCpuTimes);
|
||||
|
||||
mMockClock.realtime += 1000;
|
||||
mBatteryStatsImpl.updateProcStateCpuTimes(true, true);
|
||||
|
||||
verifyNoPendingUids();
|
||||
@ -233,7 +282,11 @@ public class BatteryStatsImplTest {
|
||||
@Test
|
||||
public void testCopyFromAllUidsCpuTimes() {
|
||||
mBatteryStatsImpl.setOnBatteryInternal(false);
|
||||
mBatteryStatsImpl.updateTimeBasesLocked(false, Display.STATE_ON, 0, 0);
|
||||
synchronized (mBatteryStatsImpl) {
|
||||
mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
|
||||
}
|
||||
|
||||
mMockClock.realtime = 1000;
|
||||
|
||||
final int[] testUids = {10032, 10048, 10145, 10139};
|
||||
final int[] testProcStates = {
|
||||
@ -242,8 +295,14 @@ public class BatteryStatsImplTest {
|
||||
PROCESS_STATE_TOP,
|
||||
PROCESS_STATE_CACHED
|
||||
};
|
||||
final int[] pendingUidIdx = {1, 2};
|
||||
updateProcessStates(testUids, testProcStates, pendingUidIdx);
|
||||
addPendingUids(testUids, testProcStates);
|
||||
|
||||
for (int i = 0; i < testUids.length; ++i) {
|
||||
BatteryStatsImpl.Uid uid = mBatteryStatsImpl.getUidStatsLocked(testUids[i]);
|
||||
uid.setProcessStateForTest(testProcStates[i], mMockClock.elapsedRealtime());
|
||||
mockKernelSingleUidTimeReader(testUids[i], new long[NUM_CPU_FREQS]);
|
||||
}
|
||||
mBatteryStatsImpl.updateProcStateCpuTimes(true, false);
|
||||
|
||||
final SparseArray<long[]> allUidCpuTimes = new SparseArray<>();
|
||||
long[][] allCpuTimes = {
|
||||
@ -257,18 +316,16 @@ public class BatteryStatsImplTest {
|
||||
}
|
||||
when(mKernelUidCpuFreqTimeReader.getAllUidCpuFreqTimeMs()).thenReturn(allUidCpuTimes);
|
||||
long[][] expectedCpuTimes = {
|
||||
{843598745, 397843, 32749, 99854},
|
||||
{9834, 5885, 487589, 394},
|
||||
{203984, 439, 9859, 30948},
|
||||
{9389, 858, 239, 349}
|
||||
{843598745, 397843, 32749, 99854, 23454},
|
||||
{9834, 5885, 487589, 394, 93933},
|
||||
{203984, 439, 9859, 30948, 49494},
|
||||
{9389, 858, 239, 349, 50505}
|
||||
};
|
||||
for (int i = 0; i < testUids.length; ++i) {
|
||||
final int idx = i;
|
||||
final ArgumentMatcher<long[]> matcher = times -> Arrays.equals(times, allCpuTimes[idx]);
|
||||
when(mKernelSingleUidTimeReader.computeDelta(eq(testUids[i]), argThat(matcher)))
|
||||
.thenReturn(expectedCpuTimes[i]);
|
||||
mockKernelSingleUidTimeReader(testUids[i], expectedCpuTimes[i]);
|
||||
}
|
||||
|
||||
mMockClock.realtime += 1000;
|
||||
mBatteryStatsImpl.copyFromAllUidsCpuTimes(true, false);
|
||||
|
||||
verifyNoPendingUids();
|
||||
@ -286,6 +343,39 @@ public class BatteryStatsImplTest {
|
||||
}
|
||||
}
|
||||
|
||||
private void mockKernelSingleUidTimeReader(int testUid, long[] cpuTimes) {
|
||||
doAnswer(invocation -> {
|
||||
LongArrayMultiStateCounter counter = invocation.getArgument(1);
|
||||
long timestampMs = invocation.getArgument(2);
|
||||
LongArrayMultiStateCounter.LongArrayContainer container =
|
||||
new LongArrayMultiStateCounter.LongArrayContainer(NUM_CPU_FREQS);
|
||||
container.setValues(cpuTimes);
|
||||
counter.updateValues(container, timestampMs);
|
||||
return null;
|
||||
}).when(mKernelSingleUidTimeReader).addDelta(eq(testUid),
|
||||
any(LongArrayMultiStateCounter.class), anyLong());
|
||||
}
|
||||
|
||||
private void mockKernelSingleUidTimeReader(int testUid, long[] cpuTimes, long[] delta) {
|
||||
doAnswer(invocation -> {
|
||||
LongArrayMultiStateCounter counter = invocation.getArgument(1);
|
||||
long timestampMs = invocation.getArgument(2);
|
||||
LongArrayMultiStateCounter.LongArrayContainer deltaContainer =
|
||||
invocation.getArgument(3);
|
||||
|
||||
LongArrayMultiStateCounter.LongArrayContainer container =
|
||||
new LongArrayMultiStateCounter.LongArrayContainer(NUM_CPU_FREQS);
|
||||
container.setValues(cpuTimes);
|
||||
counter.updateValues(container, timestampMs);
|
||||
if (deltaContainer != null) {
|
||||
deltaContainer.setValues(delta);
|
||||
}
|
||||
return null;
|
||||
}).when(mKernelSingleUidTimeReader).addDelta(eq(testUid),
|
||||
any(LongArrayMultiStateCounter.class), anyLong(),
|
||||
any(LongArrayMultiStateCounter.LongArrayContainer.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddCpuTimes() {
|
||||
long[] timesA = null;
|
||||
@ -314,7 +404,9 @@ public class BatteryStatsImplTest {
|
||||
final int releaseTimeMs = 1005;
|
||||
final int currentTimeMs = 1011;
|
||||
|
||||
mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
|
||||
synchronized (mBatteryStatsImpl) {
|
||||
mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
|
||||
}
|
||||
|
||||
// Create a Uid Object
|
||||
final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUid);
|
||||
@ -325,7 +417,7 @@ public class BatteryStatsImplTest {
|
||||
u.noteWifiMulticastDisabledLocked(releaseTimeMs);
|
||||
|
||||
// Get the total acquisition time
|
||||
long totalTime = u.getWifiMulticastTime(currentTimeMs*1000,
|
||||
long totalTime = u.getWifiMulticastTime(currentTimeMs * 1000,
|
||||
BatteryStats.STATS_SINCE_CHARGED);
|
||||
assertEquals("Miscalculations of Multicast wakelock acquisition time",
|
||||
(releaseTimeMs - acquireTimeMs) * 1000, totalTime);
|
||||
@ -337,7 +429,9 @@ public class BatteryStatsImplTest {
|
||||
final int acquireTimeMs = 1000;
|
||||
final int currentTimeMs = 1011;
|
||||
|
||||
mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
|
||||
synchronized (mBatteryStatsImpl) {
|
||||
mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
|
||||
}
|
||||
|
||||
// Create a Uid Object
|
||||
final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUid);
|
||||
@ -347,7 +441,7 @@ public class BatteryStatsImplTest {
|
||||
u.noteWifiMulticastEnabledLocked(acquireTimeMs);
|
||||
|
||||
// Get the total acquisition time
|
||||
long totalTime = u.getWifiMulticastTime(currentTimeMs*1000,
|
||||
long totalTime = u.getWifiMulticastTime(currentTimeMs * 1000,
|
||||
BatteryStats.STATS_SINCE_CHARGED);
|
||||
assertEquals("Miscalculations of Multicast wakelock acquisition time",
|
||||
(currentTimeMs - acquireTimeMs) * 1000, totalTime);
|
||||
@ -363,7 +457,9 @@ public class BatteryStatsImplTest {
|
||||
final int releaseTimeMs_2 = 1009;
|
||||
final int currentTimeMs = 1011;
|
||||
|
||||
mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
|
||||
synchronized (mBatteryStatsImpl) {
|
||||
mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
|
||||
}
|
||||
|
||||
// Create a Uid Object
|
||||
final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUid);
|
||||
@ -377,7 +473,7 @@ public class BatteryStatsImplTest {
|
||||
u.noteWifiMulticastDisabledLocked(releaseTimeMs_2);
|
||||
|
||||
// Get the total acquisition time
|
||||
long totalTime = u.getWifiMulticastTime(currentTimeMs*1000,
|
||||
long totalTime = u.getWifiMulticastTime(currentTimeMs * 1000,
|
||||
BatteryStats.STATS_SINCE_CHARGED);
|
||||
assertEquals("Miscalculations of Multicast wakelock acquisition time",
|
||||
(releaseTimeMs_2 - acquireTimeMs_1) * 1000, totalTime);
|
||||
@ -393,7 +489,9 @@ public class BatteryStatsImplTest {
|
||||
final int releaseTimeMs_2 = 1009;
|
||||
final int currentTimeMs = 1011;
|
||||
|
||||
mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
|
||||
synchronized (mBatteryStatsImpl) {
|
||||
mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
|
||||
}
|
||||
|
||||
// Create a Uid Object
|
||||
final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUid);
|
||||
@ -407,11 +505,11 @@ public class BatteryStatsImplTest {
|
||||
u.noteWifiMulticastDisabledLocked(releaseTimeMs_2);
|
||||
|
||||
// Get the total acquisition time
|
||||
long totalTime = u.getWifiMulticastTime(currentTimeMs*1000,
|
||||
long totalTime = u.getWifiMulticastTime(currentTimeMs * 1000,
|
||||
BatteryStats.STATS_SINCE_CHARGED);
|
||||
assertEquals("Miscalculations of Multicast wakelock acquisition time",
|
||||
((releaseTimeMs_1 - acquireTimeMs_1) + (releaseTimeMs_2 - acquireTimeMs_2))
|
||||
* 1000, totalTime);
|
||||
* 1000, totalTime);
|
||||
}
|
||||
|
||||
private void addIsolatedUid(int parentUid, int childUid) {
|
||||
@ -426,20 +524,6 @@ public class BatteryStatsImplTest {
|
||||
}
|
||||
}
|
||||
|
||||
private void updateProcessStates(int[] uids, int[] procStates,
|
||||
int[] pendingUidsIdx) {
|
||||
final SparseIntArray pendingUids = mBatteryStatsImpl.getPendingUids();
|
||||
for (int i = 0; i < uids.length; ++i) {
|
||||
final BatteryStatsImpl.Uid u = mBatteryStatsImpl.getUidStatsLocked(uids[i]);
|
||||
if (ArrayUtils.contains(pendingUidsIdx, i)) {
|
||||
u.setProcessStateForTest(PROCESS_STATE_TOP);
|
||||
pendingUids.put(uids[i], procStates[i]);
|
||||
} else {
|
||||
u.setProcessStateForTest(procStates[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyNoPendingUids() {
|
||||
final SparseIntArray pendingUids = mBatteryStatsImpl.getPendingUids();
|
||||
assertEquals("There shouldn't be any pending uids left: " + pendingUids,
|
||||
|
@ -183,7 +183,9 @@ public class BstatsCpuTimesValidationTest {
|
||||
sCpuFreqTimesAvailable = totalCpuTimes != null;
|
||||
final long[] fgCpuTimes = getAllCpuFreqTimes(Process.SYSTEM_UID,
|
||||
PROCESS_STATE_FOREGROUND);
|
||||
sPerProcStateTimesAvailable = fgCpuTimes != null;
|
||||
final long[] topCpuTimes = getAllCpuFreqTimes(Process.SYSTEM_UID,
|
||||
PROCESS_STATE_TOP);
|
||||
sPerProcStateTimesAvailable = fgCpuTimes != null || topCpuTimes != null;
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -563,7 +565,7 @@ public class BstatsCpuTimesValidationTest {
|
||||
|
||||
final long[] cpuTimesMs3 = getAllCpuFreqTimes(sTestPkgUid, PROCESS_STATE_TOP);
|
||||
assertCpuTimesValid(cpuTimesMs3);
|
||||
assertCpuTimesEqual(cpuTimesMs3, cpuTimesMs, 20,
|
||||
assertCpuTimesEqual(cpuTimesMs3, cpuTimesMs, 500,
|
||||
"Unexpected cpu times after turning on tracking");
|
||||
|
||||
doSomeWork(PROCESS_STATE_TOP);
|
||||
@ -588,7 +590,8 @@ public class BstatsCpuTimesValidationTest {
|
||||
private void assertCpuTimesEqual(long[] actual, long[] expected, long delta, String errMsg) {
|
||||
for (int i = actual.length - 1; i >= 0; --i) {
|
||||
if (actual[i] > expected[i] + delta || actual[i] < expected[i]) {
|
||||
fail(errMsg + ", actual=" + actual + ", expected=" + expected + ", delta=" + delta);
|
||||
fail(errMsg + ", actual=" + Arrays.toString(actual)
|
||||
+ ", expected=" + Arrays.toString(expected) + ", delta=" + delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -285,7 +285,7 @@ public class KernelSingleUidTimeReaderTest {
|
||||
LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 5);
|
||||
counter.setState(0, 0);
|
||||
mInjector.setCpuTimeInStatePerClusterNs(new long[][]{{0, 0, 0}, {0, 0}});
|
||||
boolean success = mInjector.addDelta(TEST_UID, counter, 0);
|
||||
boolean success = mInjector.addDelta(TEST_UID, counter, 0, null);
|
||||
assertThat(success).isTrue();
|
||||
|
||||
// Nanoseconds
|
||||
@ -294,13 +294,16 @@ public class KernelSingleUidTimeReaderTest {
|
||||
{1_000_000, 2_000_000, 3_000_000},
|
||||
{4_000_000, 5_000_000}});
|
||||
|
||||
success = mInjector.addDelta(TEST_UID, counter, 2000);
|
||||
assertThat(success).isTrue();
|
||||
|
||||
LongArrayMultiStateCounter.LongArrayContainer array =
|
||||
new LongArrayMultiStateCounter.LongArrayContainer(5);
|
||||
long[] out = new long[5];
|
||||
|
||||
success = mInjector.addDelta(TEST_UID, counter, 2000, array);
|
||||
assertThat(success).isTrue();
|
||||
|
||||
array.getValues(out);
|
||||
assertThat(out).isEqualTo(new long[]{1, 2, 3, 4, 5});
|
||||
|
||||
counter.getCounts(array, 0);
|
||||
array.getValues(out);
|
||||
assertThat(out).isEqualTo(new long[]{1, 2, 3, 4, 5});
|
||||
@ -312,9 +315,12 @@ public class KernelSingleUidTimeReaderTest {
|
||||
{11_000_000, 22_000_000, 33_000_000},
|
||||
{44_000_000, 55_000_000}});
|
||||
|
||||
success = mInjector.addDelta(TEST_UID, counter, 4000);
|
||||
success = mInjector.addDelta(TEST_UID, counter, 4000, array);
|
||||
assertThat(success).isTrue();
|
||||
|
||||
array.getValues(out);
|
||||
assertThat(out).isEqualTo(new long[]{10, 20, 30, 40, 50});
|
||||
|
||||
counter.getCounts(array, 0);
|
||||
array.getValues(out);
|
||||
assertThat(out).isEqualTo(new long[]{1 + 5, 2 + 10, 3 + 15, 4 + 20, 5 + 25});
|
||||
@ -371,8 +377,10 @@ public class KernelSingleUidTimeReaderTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addDelta(int uid, LongArrayMultiStateCounter counter, long timestampMs) {
|
||||
return addDeltaForTest(uid, counter, timestampMs, mCpuTimeInStatePerClusterNs);
|
||||
public boolean addDelta(int uid, LongArrayMultiStateCounter counter, long timestampMs,
|
||||
LongArrayMultiStateCounter.LongArrayContainer deltaOut) {
|
||||
return addDeltaForTest(uid, counter, timestampMs, mCpuTimeInStatePerClusterNs,
|
||||
deltaOut);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user