Loading core/java/android/os/BatteryStats.java +35 −29 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Formatter; Loading Loading @@ -859,11 +860,13 @@ public abstract class BatteryStats implements Parcelable { /** * Returns cpu times of an uid at a particular process state. */ public abstract long[] getCpuFreqTimes(int which, int procState); public abstract boolean getCpuFreqTimes(@NonNull long[] timesInFreqMs, int procState); /** * Returns cpu times of an uid while the screen if off at a particular process state. */ public abstract long[] getScreenOffCpuFreqTimes(int which, int procState); public abstract boolean getScreenOffCpuFreqTimes(@NonNull long[] timesInFreqMs, int procState); // 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 @@ -1575,6 +1578,11 @@ public abstract class BatteryStats implements Parcelable { public abstract long getNextMaxDailyDeadline(); /** * Returns the total number of frequencies across all CPU clusters. */ public abstract int getCpuFreqCount(); public abstract long[] getCpuFreqs(); public final static class HistoryTag { Loading Loading @@ -4626,27 +4634,26 @@ public abstract class BatteryStats implements Parcelable { cpuFreqTimeMs.length, sb.toString()); } final long[] timesInFreqMs = new long[getCpuFreqCount()]; for (int procState = 0; procState < Uid.NUM_PROCESS_STATE; ++procState) { final long[] timesMs = u.getCpuFreqTimes(which, procState); if (timesMs != null && timesMs.length == cpuFreqs.length) { if (u.getCpuFreqTimes(timesInFreqMs, procState)) { sb.setLength(0); for (int i = 0; i < timesMs.length; ++i) { for (int i = 0; i < timesInFreqMs.length; ++i) { if (i != 0) sb.append(','); sb.append(timesMs[i]); sb.append(timesInFreqMs[i]); } final long[] screenOffTimesMs = u.getScreenOffCpuFreqTimes( which, procState); if (screenOffTimesMs != null) { for (int i = 0; i < screenOffTimesMs.length; ++i) { sb.append(',').append(screenOffTimesMs[i]); if (u.getScreenOffCpuFreqTimes(timesInFreqMs, procState)) { for (int i = 0; i < timesInFreqMs.length; ++i) { sb.append(',').append(timesInFreqMs[i]); } } else { for (int i = 0; i < timesMs.length; ++i) { for (int i = 0; i < timesInFreqMs.length; ++i) { sb.append(",0"); } } dumpLine(pw, uid, category, CPU_TIMES_AT_FREQ_DATA, Uid.UID_PROCESS_TYPES[procState], timesMs.length, sb.toString()); Uid.UID_PROCESS_TYPES[procState], timesInFreqMs.length, sb.toString()); } } } Loading Loading @@ -6243,25 +6250,24 @@ public abstract class BatteryStats implements Parcelable { pw.println(sb.toString()); } final long[] timesInFreqMs = new long[getCpuFreqCount()]; for (int procState = 0; procState < Uid.NUM_PROCESS_STATE; ++procState) { final long[] cpuTimes = u.getCpuFreqTimes(which, procState); if (cpuTimes != null) { if (u.getCpuFreqTimes(timesInFreqMs, procState)) { sb.setLength(0); sb.append(" Cpu times per freq at state ") .append(Uid.PROCESS_STATE_NAMES[procState]).append(':'); for (int i = 0; i < cpuTimes.length; ++i) { sb.append(" " + cpuTimes[i]); for (int i = 0; i < timesInFreqMs.length; ++i) { sb.append(" ").append(timesInFreqMs[i]); } pw.println(sb.toString()); } final long[] screenOffCpuTimes = u.getScreenOffCpuFreqTimes(which, procState); if (screenOffCpuTimes != null) { if (u.getScreenOffCpuFreqTimes(timesInFreqMs, procState)) { sb.setLength(0); sb.append(" Screen-off cpu times per freq at state ") .append(Uid.PROCESS_STATE_NAMES[procState]).append(':'); for (int i = 0; i < screenOffCpuTimes.length; ++i) { sb.append(" " + screenOffCpuTimes[i]); for (int i = 0; i < timesInFreqMs.length; ++i) { sb.append(" ").append(timesInFreqMs[i]); } pw.println(sb.toString()); } Loading Loading @@ -7627,22 +7633,22 @@ public abstract class BatteryStats implements Parcelable { } } final long[] timesInFreqMs = new long[getCpuFreqCount()]; final long[] timesInFreqScreenOffMs = new long[getCpuFreqCount()]; for (int procState = 0; procState < Uid.NUM_PROCESS_STATE; ++procState) { final long[] timesMs = u.getCpuFreqTimes(which, procState); if (timesMs != null && timesMs.length == cpuFreqs.length) { long[] screenOffTimesMs = u.getScreenOffCpuFreqTimes(which, procState); if (screenOffTimesMs == null) { screenOffTimesMs = new long[timesMs.length]; if (u.getCpuFreqTimes(timesInFreqMs, procState)) { if (!u.getScreenOffCpuFreqTimes(timesInFreqScreenOffMs, procState)) { Arrays.fill(timesInFreqScreenOffMs, 0); } final long procToken = proto.start(UidProto.Cpu.BY_PROCESS_STATE); proto.write(UidProto.Cpu.ByProcessState.PROCESS_STATE, procState); for (int ic = 0; ic < timesMs.length; ++ic) { for (int ic = 0; ic < timesInFreqMs.length; ++ic) { long cToken = proto.start(UidProto.Cpu.ByProcessState.BY_FREQUENCY); proto.write(UidProto.Cpu.ByFrequency.FREQUENCY_INDEX, ic + 1); proto.write(UidProto.Cpu.ByFrequency.TOTAL_DURATION_MS, timesMs[ic]); timesInFreqMs[ic]); proto.write(UidProto.Cpu.ByFrequency.SCREEN_OFF_DURATION_MS, screenOffTimesMs[ic]); timesInFreqScreenOffMs[ic]); proto.end(cToken); } proto.end(procToken); Loading core/java/com/android/internal/os/BatteryStatsImpl.java +46 −32 Original line number Diff line number Diff line Loading @@ -468,6 +468,7 @@ public class BatteryStatsImpl extends BatteryStats { mPendingUids.clear(); } final long timestampMs = mClock.elapsedRealtime(); LongArrayMultiStateCounter.LongArrayContainer deltaContainer = null; for (int i = uidStates.size() - 1; i >= 0; --i) { final int uid = uidStates.keyAt(i); final int procState = uidStates.valueAt(i); Loading @@ -493,6 +494,9 @@ public class BatteryStatsImpl extends BatteryStats { isolatedUids[j] = u.mChildUids.keyAt(j); isolatedUidTimeInFreqCounters[j] = u.mChildUids.valueAt(j).cpuTimeInFreqCounter; if (deltaContainer == null && isolatedUidTimeInFreqCounters[j] != null) { deltaContainer = getCpuTimeInFreqContainer(); } } } } Loading @@ -509,8 +513,6 @@ public class BatteryStatsImpl extends BatteryStats { mKernelSingleUidTimeReader.addDelta(uid, onBatteryScreenOffCounter, timestampMs); if (isolatedUids != null) { LongArrayMultiStateCounter.LongArrayContainer deltaContainer = new LongArrayMultiStateCounter.LongArrayContainer(getCpuFreqCount()); for (int j = isolatedUids.length - 1; j >= 0; --j) { if (isolatedUidTimeInFreqCounters[j] != null) { mKernelSingleUidTimeReader.addDelta(isolatedUids[j], Loading Loading @@ -612,13 +614,13 @@ public class BatteryStatsImpl extends BatteryStats { } 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).cpuTimeInFreqCounter; if (counter != null) { final int isolatedUid = u.mChildUids.keyAt(j); final LongArrayMultiStateCounter.LongArrayContainer deltaContainer = getCpuTimeInFreqContainer(); mKernelSingleUidTimeReader.addDelta(isolatedUid, counter, timestampMs, deltaContainer); onBatteryCounter.addCounts(deltaContainer); Loading Loading @@ -1186,7 +1188,9 @@ public class BatteryStatsImpl extends BatteryStats { private long mBatteryTimeToFullSeconds = -1; private boolean mCpuFreqsInitialized; private long[] mCpuFreqs; private LongArrayMultiStateCounter.LongArrayContainer mTmpCpuTimeInFreq; /** * Times spent by the system server threads handling incoming binder requests. Loading Loading @@ -1931,23 +1935,22 @@ public class BatteryStatsImpl extends BatteryStats { } /** * Returns accumulated counts for the specified state, or null if all counts are zero. * Returns accumulated counts for the specified state, or false 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); public boolean getCountsLocked(long[] counts, int procState) { if (counts.length != mCounter.getArrayLength()) { return false; } mCounter.getCounts(counts, procState); // 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 true; } } return null; return false; } public void logState(Printer pw, String prefix) { Loading Loading @@ -8346,35 +8349,34 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("mBsi") @Override public long[] getCpuFreqTimes(int which, int procState) { public boolean getCpuFreqTimes(long[] timesInFreqMs, int procState) { if (procState < 0 || procState >= NUM_PROCESS_STATE) { return null; return false; } if (mProcStateTimeMs == null) { return null; return false; } if (!mBsi.mPerProcStateCpuTimesAvailable) { mProcStateTimeMs = null; return null; return false; } return mProcStateTimeMs.getCountsLocked(which, procState); return mProcStateTimeMs.getCountsLocked(timesInFreqMs, procState); } @GuardedBy("mBsi") @Override public long[] getScreenOffCpuFreqTimes(int which, int procState) { public boolean getScreenOffCpuFreqTimes(long[] timesInFreqMs, int procState) { if (procState < 0 || procState >= NUM_PROCESS_STATE) { return null; return false; } if (mProcStateScreenOffTimeMs == null) { return null; return false; } if (!mBsi.mPerProcStateCpuTimesAvailable) { mProcStateScreenOffTimeMs = null; return null; return false; } return mProcStateScreenOffTimeMs.getCountsLocked(which, procState); return mProcStateScreenOffTimeMs.getCountsLocked(timesInFreqMs, procState); } public long getBinderCallCount() { Loading Loading @@ -11577,18 +11579,30 @@ public class BatteryStatsImpl extends BatteryStats { } } @GuardedBy("this") @Override public long[] getCpuFreqs() { if (!mCpuFreqsInitialized) { mCpuFreqs = mCpuUidFreqTimeReader.readFreqs(mPowerProfile); mCpuFreqsInitialized = true; } return mCpuFreqs; } /** * Returns the total number of frequencies across all CPU clusters. */ private int getCpuFreqCount() { if (mCpuFreqs == null) { mCpuFreqs = mCpuUidFreqTimeReader.readFreqs(mPowerProfile); @GuardedBy("this") @Override public int getCpuFreqCount() { final long[] cpuFreqs = getCpuFreqs(); return cpuFreqs != null ? cpuFreqs.length : 0; } @GuardedBy("this") private LongArrayMultiStateCounter.LongArrayContainer getCpuTimeInFreqContainer() { if (mTmpCpuTimeInFreq == null) { mTmpCpuTimeInFreq = new LongArrayMultiStateCounter.LongArrayContainer(getCpuFreqCount()); } return mCpuFreqs != null ? mCpuFreqs.length : 0; return mTmpCpuTimeInFreq; } public BatteryStatsImpl(File systemDir, Handler handler, PlatformIdleStateCallback cb, Loading core/java/com/android/internal/os/CpuPowerCalculator.java +7 −4 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ public class CpuPowerCalculator extends PowerCalculator { public long durationFgMs; public String packageWithHighestDrain; public double[] perProcStatePowerMah; public long[] cpuFreqTimes; } public CpuPowerCalculator(PowerProfile profile) { Loading Loading @@ -98,6 +99,9 @@ public class CpuPowerCalculator extends PowerCalculator { BatteryConsumer.Key[] keys = UNINITIALIZED_KEYS; Result result = new Result(); if (query.isProcessStateDataNeeded()) { result.cpuFreqTimes = new long[batteryStats.getCpuFreqCount()]; } final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders = builder.getUidBatteryConsumerBuilders(); for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) { Loading Loading @@ -187,11 +191,10 @@ public class CpuPowerCalculator extends PowerCalculator { // TODO(b/191921016): use per-state CPU cluster times final long[] cpuClusterTimes = null; final long[] cpuFreqTimes = u.getCpuFreqTimes(BatteryStats.STATS_SINCE_CHARGED, uidProcState); if (cpuClusterTimes != null || cpuFreqTimes != null) { boolean hasCpuFreqTimes = u.getCpuFreqTimes(result.cpuFreqTimes, uidProcState); if (cpuClusterTimes != null || hasCpuFreqTimes) { result.perProcStatePowerMah[procState] += calculateUidModeledPowerMah(u, 0, cpuClusterTimes, cpuFreqTimes); 0, cpuClusterTimes, result.cpuFreqTimes); } } Loading core/java/com/android/internal/os/LongArrayMultiStateCounter.java +16 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import dalvik.annotation.optimization.FastNative; import libcore.util.NativeAllocationRegistry; import java.util.Arrays; import java.util.concurrent.atomic.AtomicReference; /** * Performs per-state counting of multi-element values over time. The class' behavior is illustrated Loading Loading @@ -120,6 +121,8 @@ public final class LongArrayMultiStateCounter implements Parcelable { private static final NativeAllocationRegistry sRegistry = NativeAllocationRegistry.createMalloced( LongArrayMultiStateCounter.class.getClassLoader(), native_getReleaseFunc()); private static final AtomicReference<LongArrayContainer> sTmpArrayContainer = new AtomicReference<>(); private final int mStateCount; private final int mLength; Loading Loading @@ -203,6 +206,19 @@ public final class LongArrayMultiStateCounter implements Parcelable { native_reset(mNativeObject); } /** * Populates the array with the accumulated counts for the specified state. */ public void getCounts(long[] counts, int state) { LongArrayContainer container = sTmpArrayContainer.getAndSet(null); if (container == null || container.mLength != counts.length) { container = new LongArrayContainer(counts.length); } getCounts(container, state); container.getValues(counts); sTmpArrayContainer.set(container); } /** * Populates longArrayContainer with the accumulated counts for the specified state. */ Loading core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java +34 −27 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package com.android.internal.os; import static android.os.BatteryStats.STATS_SINCE_CHARGED; import static android.os.BatteryStats.Uid.NUM_PROCESS_STATE; import static android.os.BatteryStats.Uid.PROCESS_STATE_BACKGROUND; import static android.os.BatteryStats.Uid.PROCESS_STATE_CACHED; Loading @@ -25,8 +24,10 @@ import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; Loading Loading @@ -115,14 +116,17 @@ public class BatteryStatsImplTest { {989834, 384098, 98483, 23809, 4984}, {4859048, 348903, 4578967, 5973894, 298549} }; final long[] timeInFreqs = new long[NUM_CPU_FREQS]; for (int i = 0; i < testUids.length; ++i) { mockKernelSingleUidTimeReader(testUids[i], cpuTimes[i]); // Verify there are no cpu times initially. final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUids[i]); for (int procState = 0; procState < NUM_PROCESS_STATE; ++procState) { assertNull(u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertFalse(u.getCpuFreqTimes(timeInFreqs, procState)); assertFalse(u.getScreenOffCpuFreqTimes(timeInFreqs, procState)); } } addPendingUids(testUids, testProcStates); Loading @@ -134,13 +138,13 @@ public class BatteryStatsImplTest { for (int i = 0; i < testUids.length; ++i) { final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]); for (int procState = 0; procState < NUM_PROCESS_STATE; ++procState) { final boolean hasTimeInFreq = u.getCpuFreqTimes(timeInFreqs, procState); if (procState == testProcStates[i]) { assertArrayEquals("Uid=" + testUids[i], cpuTimes[i], u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertArrayEquals("Uid=" + testUids[i], cpuTimes[i], timeInFreqs); } else { assertNull(u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertFalse(hasTimeInFreq); } assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertFalse(u.getScreenOffCpuFreqTimes(timeInFreqs, procState)); } } Loading Loading @@ -172,12 +176,12 @@ public class BatteryStatsImplTest { for (int j = 0; j < expectedCpuTimes.length; ++j) { expectedCpuTimes[j] += delta1[i][j]; } assertArrayEquals("Uid=" + testUids[i], expectedCpuTimes, u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertTrue(u.getCpuFreqTimes(timeInFreqs, procState)); assertArrayEquals("Uid=" + testUids[i], expectedCpuTimes, timeInFreqs); } else { assertNull(u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertFalse(u.getCpuFreqTimes(timeInFreqs, procState)); } assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertFalse(u.getScreenOffCpuFreqTimes(timeInFreqs, procState)); } } Loading Loading @@ -214,13 +218,13 @@ public class BatteryStatsImplTest { for (int j = 0; j < expectedCpuTimes.length; ++j) { expectedCpuTimes[j] += delta1[i][j] + delta2[i][j]; } assertArrayEquals("Uid=" + testUids[i], expectedCpuTimes, u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertArrayEquals("Uid=" + testUids[i], delta2[i], u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertTrue(u.getCpuFreqTimes(timeInFreqs, procState)); assertArrayEquals("Uid=" + testUids[i], expectedCpuTimes, timeInFreqs); assertTrue(u.getScreenOffCpuFreqTimes(timeInFreqs, procState)); assertArrayEquals("Uid=" + testUids[i], delta2[i], timeInFreqs); } else { assertNull(u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertFalse(u.getCpuFreqTimes(timeInFreqs, procState)); assertFalse(u.getScreenOffCpuFreqTimes(timeInFreqs, procState)); } } } Loading Loading @@ -262,18 +266,18 @@ public class BatteryStatsImplTest { expectedCpuTimes[j] += delta1[i][j] + delta2[i][j] + delta3[i][j] + (testUids[i] == parentUid ? isolatedUidCpuTimes[j] : 0); } assertArrayEquals("Uid=" + testUids[i], expectedCpuTimes, u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertTrue(u.getCpuFreqTimes(timeInFreqs, procState)); assertArrayEquals("Uid=" + testUids[i], expectedCpuTimes, timeInFreqs); long[] expectedScreenOffTimes = delta2[i].clone(); for (int j = 0; j < expectedScreenOffTimes.length; ++j) { expectedScreenOffTimes[j] += delta3[i][j] + (testUids[i] == parentUid ? isolatedUidCpuTimes[j] : 0); } assertArrayEquals("Uid=" + testUids[i], expectedScreenOffTimes, u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertTrue(u.getScreenOffCpuFreqTimes(timeInFreqs, procState)); assertArrayEquals("Uid=" + testUids[i], expectedScreenOffTimes, timeInFreqs); } else { assertNull(u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertFalse(u.getCpuFreqTimes(timeInFreqs, procState)); assertFalse(u.getScreenOffCpuFreqTimes(timeInFreqs, procState)); } } } Loading Loading @@ -329,16 +333,19 @@ public class BatteryStatsImplTest { mBatteryStatsImpl.copyFromAllUidsCpuTimes(true, false); verifyNoPendingUids(); final long[] timeInFreqs = new long[NUM_CPU_FREQS]; for (int i = 0; i < testUids.length; ++i) { final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]); for (int procState = 0; procState < NUM_PROCESS_STATE; ++procState) { if (procState == testProcStates[i]) { assertArrayEquals("Uid=" + testUids[i], expectedCpuTimes[i], u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertTrue(u.getCpuFreqTimes(timeInFreqs, procState)); assertArrayEquals("Uid=" + testUids[i], expectedCpuTimes[i], timeInFreqs); } else { assertNull(u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertFalse(u.getCpuFreqTimes(timeInFreqs, procState)); } assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertFalse(u.getScreenOffCpuFreqTimes(timeInFreqs, procState)); } } } Loading Loading
core/java/android/os/BatteryStats.java +35 −29 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Formatter; Loading Loading @@ -859,11 +860,13 @@ public abstract class BatteryStats implements Parcelable { /** * Returns cpu times of an uid at a particular process state. */ public abstract long[] getCpuFreqTimes(int which, int procState); public abstract boolean getCpuFreqTimes(@NonNull long[] timesInFreqMs, int procState); /** * Returns cpu times of an uid while the screen if off at a particular process state. */ public abstract long[] getScreenOffCpuFreqTimes(int which, int procState); public abstract boolean getScreenOffCpuFreqTimes(@NonNull long[] timesInFreqMs, int procState); // 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 @@ -1575,6 +1578,11 @@ public abstract class BatteryStats implements Parcelable { public abstract long getNextMaxDailyDeadline(); /** * Returns the total number of frequencies across all CPU clusters. */ public abstract int getCpuFreqCount(); public abstract long[] getCpuFreqs(); public final static class HistoryTag { Loading Loading @@ -4626,27 +4634,26 @@ public abstract class BatteryStats implements Parcelable { cpuFreqTimeMs.length, sb.toString()); } final long[] timesInFreqMs = new long[getCpuFreqCount()]; for (int procState = 0; procState < Uid.NUM_PROCESS_STATE; ++procState) { final long[] timesMs = u.getCpuFreqTimes(which, procState); if (timesMs != null && timesMs.length == cpuFreqs.length) { if (u.getCpuFreqTimes(timesInFreqMs, procState)) { sb.setLength(0); for (int i = 0; i < timesMs.length; ++i) { for (int i = 0; i < timesInFreqMs.length; ++i) { if (i != 0) sb.append(','); sb.append(timesMs[i]); sb.append(timesInFreqMs[i]); } final long[] screenOffTimesMs = u.getScreenOffCpuFreqTimes( which, procState); if (screenOffTimesMs != null) { for (int i = 0; i < screenOffTimesMs.length; ++i) { sb.append(',').append(screenOffTimesMs[i]); if (u.getScreenOffCpuFreqTimes(timesInFreqMs, procState)) { for (int i = 0; i < timesInFreqMs.length; ++i) { sb.append(',').append(timesInFreqMs[i]); } } else { for (int i = 0; i < timesMs.length; ++i) { for (int i = 0; i < timesInFreqMs.length; ++i) { sb.append(",0"); } } dumpLine(pw, uid, category, CPU_TIMES_AT_FREQ_DATA, Uid.UID_PROCESS_TYPES[procState], timesMs.length, sb.toString()); Uid.UID_PROCESS_TYPES[procState], timesInFreqMs.length, sb.toString()); } } } Loading Loading @@ -6243,25 +6250,24 @@ public abstract class BatteryStats implements Parcelable { pw.println(sb.toString()); } final long[] timesInFreqMs = new long[getCpuFreqCount()]; for (int procState = 0; procState < Uid.NUM_PROCESS_STATE; ++procState) { final long[] cpuTimes = u.getCpuFreqTimes(which, procState); if (cpuTimes != null) { if (u.getCpuFreqTimes(timesInFreqMs, procState)) { sb.setLength(0); sb.append(" Cpu times per freq at state ") .append(Uid.PROCESS_STATE_NAMES[procState]).append(':'); for (int i = 0; i < cpuTimes.length; ++i) { sb.append(" " + cpuTimes[i]); for (int i = 0; i < timesInFreqMs.length; ++i) { sb.append(" ").append(timesInFreqMs[i]); } pw.println(sb.toString()); } final long[] screenOffCpuTimes = u.getScreenOffCpuFreqTimes(which, procState); if (screenOffCpuTimes != null) { if (u.getScreenOffCpuFreqTimes(timesInFreqMs, procState)) { sb.setLength(0); sb.append(" Screen-off cpu times per freq at state ") .append(Uid.PROCESS_STATE_NAMES[procState]).append(':'); for (int i = 0; i < screenOffCpuTimes.length; ++i) { sb.append(" " + screenOffCpuTimes[i]); for (int i = 0; i < timesInFreqMs.length; ++i) { sb.append(" ").append(timesInFreqMs[i]); } pw.println(sb.toString()); } Loading Loading @@ -7627,22 +7633,22 @@ public abstract class BatteryStats implements Parcelable { } } final long[] timesInFreqMs = new long[getCpuFreqCount()]; final long[] timesInFreqScreenOffMs = new long[getCpuFreqCount()]; for (int procState = 0; procState < Uid.NUM_PROCESS_STATE; ++procState) { final long[] timesMs = u.getCpuFreqTimes(which, procState); if (timesMs != null && timesMs.length == cpuFreqs.length) { long[] screenOffTimesMs = u.getScreenOffCpuFreqTimes(which, procState); if (screenOffTimesMs == null) { screenOffTimesMs = new long[timesMs.length]; if (u.getCpuFreqTimes(timesInFreqMs, procState)) { if (!u.getScreenOffCpuFreqTimes(timesInFreqScreenOffMs, procState)) { Arrays.fill(timesInFreqScreenOffMs, 0); } final long procToken = proto.start(UidProto.Cpu.BY_PROCESS_STATE); proto.write(UidProto.Cpu.ByProcessState.PROCESS_STATE, procState); for (int ic = 0; ic < timesMs.length; ++ic) { for (int ic = 0; ic < timesInFreqMs.length; ++ic) { long cToken = proto.start(UidProto.Cpu.ByProcessState.BY_FREQUENCY); proto.write(UidProto.Cpu.ByFrequency.FREQUENCY_INDEX, ic + 1); proto.write(UidProto.Cpu.ByFrequency.TOTAL_DURATION_MS, timesMs[ic]); timesInFreqMs[ic]); proto.write(UidProto.Cpu.ByFrequency.SCREEN_OFF_DURATION_MS, screenOffTimesMs[ic]); timesInFreqScreenOffMs[ic]); proto.end(cToken); } proto.end(procToken); Loading
core/java/com/android/internal/os/BatteryStatsImpl.java +46 −32 Original line number Diff line number Diff line Loading @@ -468,6 +468,7 @@ public class BatteryStatsImpl extends BatteryStats { mPendingUids.clear(); } final long timestampMs = mClock.elapsedRealtime(); LongArrayMultiStateCounter.LongArrayContainer deltaContainer = null; for (int i = uidStates.size() - 1; i >= 0; --i) { final int uid = uidStates.keyAt(i); final int procState = uidStates.valueAt(i); Loading @@ -493,6 +494,9 @@ public class BatteryStatsImpl extends BatteryStats { isolatedUids[j] = u.mChildUids.keyAt(j); isolatedUidTimeInFreqCounters[j] = u.mChildUids.valueAt(j).cpuTimeInFreqCounter; if (deltaContainer == null && isolatedUidTimeInFreqCounters[j] != null) { deltaContainer = getCpuTimeInFreqContainer(); } } } } Loading @@ -509,8 +513,6 @@ public class BatteryStatsImpl extends BatteryStats { mKernelSingleUidTimeReader.addDelta(uid, onBatteryScreenOffCounter, timestampMs); if (isolatedUids != null) { LongArrayMultiStateCounter.LongArrayContainer deltaContainer = new LongArrayMultiStateCounter.LongArrayContainer(getCpuFreqCount()); for (int j = isolatedUids.length - 1; j >= 0; --j) { if (isolatedUidTimeInFreqCounters[j] != null) { mKernelSingleUidTimeReader.addDelta(isolatedUids[j], Loading Loading @@ -612,13 +614,13 @@ public class BatteryStatsImpl extends BatteryStats { } 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).cpuTimeInFreqCounter; if (counter != null) { final int isolatedUid = u.mChildUids.keyAt(j); final LongArrayMultiStateCounter.LongArrayContainer deltaContainer = getCpuTimeInFreqContainer(); mKernelSingleUidTimeReader.addDelta(isolatedUid, counter, timestampMs, deltaContainer); onBatteryCounter.addCounts(deltaContainer); Loading Loading @@ -1186,7 +1188,9 @@ public class BatteryStatsImpl extends BatteryStats { private long mBatteryTimeToFullSeconds = -1; private boolean mCpuFreqsInitialized; private long[] mCpuFreqs; private LongArrayMultiStateCounter.LongArrayContainer mTmpCpuTimeInFreq; /** * Times spent by the system server threads handling incoming binder requests. Loading Loading @@ -1931,23 +1935,22 @@ public class BatteryStatsImpl extends BatteryStats { } /** * Returns accumulated counts for the specified state, or null if all counts are zero. * Returns accumulated counts for the specified state, or false 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); public boolean getCountsLocked(long[] counts, int procState) { if (counts.length != mCounter.getArrayLength()) { return false; } mCounter.getCounts(counts, procState); // 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 true; } } return null; return false; } public void logState(Printer pw, String prefix) { Loading Loading @@ -8346,35 +8349,34 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("mBsi") @Override public long[] getCpuFreqTimes(int which, int procState) { public boolean getCpuFreqTimes(long[] timesInFreqMs, int procState) { if (procState < 0 || procState >= NUM_PROCESS_STATE) { return null; return false; } if (mProcStateTimeMs == null) { return null; return false; } if (!mBsi.mPerProcStateCpuTimesAvailable) { mProcStateTimeMs = null; return null; return false; } return mProcStateTimeMs.getCountsLocked(which, procState); return mProcStateTimeMs.getCountsLocked(timesInFreqMs, procState); } @GuardedBy("mBsi") @Override public long[] getScreenOffCpuFreqTimes(int which, int procState) { public boolean getScreenOffCpuFreqTimes(long[] timesInFreqMs, int procState) { if (procState < 0 || procState >= NUM_PROCESS_STATE) { return null; return false; } if (mProcStateScreenOffTimeMs == null) { return null; return false; } if (!mBsi.mPerProcStateCpuTimesAvailable) { mProcStateScreenOffTimeMs = null; return null; return false; } return mProcStateScreenOffTimeMs.getCountsLocked(which, procState); return mProcStateScreenOffTimeMs.getCountsLocked(timesInFreqMs, procState); } public long getBinderCallCount() { Loading Loading @@ -11577,18 +11579,30 @@ public class BatteryStatsImpl extends BatteryStats { } } @GuardedBy("this") @Override public long[] getCpuFreqs() { if (!mCpuFreqsInitialized) { mCpuFreqs = mCpuUidFreqTimeReader.readFreqs(mPowerProfile); mCpuFreqsInitialized = true; } return mCpuFreqs; } /** * Returns the total number of frequencies across all CPU clusters. */ private int getCpuFreqCount() { if (mCpuFreqs == null) { mCpuFreqs = mCpuUidFreqTimeReader.readFreqs(mPowerProfile); @GuardedBy("this") @Override public int getCpuFreqCount() { final long[] cpuFreqs = getCpuFreqs(); return cpuFreqs != null ? cpuFreqs.length : 0; } @GuardedBy("this") private LongArrayMultiStateCounter.LongArrayContainer getCpuTimeInFreqContainer() { if (mTmpCpuTimeInFreq == null) { mTmpCpuTimeInFreq = new LongArrayMultiStateCounter.LongArrayContainer(getCpuFreqCount()); } return mCpuFreqs != null ? mCpuFreqs.length : 0; return mTmpCpuTimeInFreq; } public BatteryStatsImpl(File systemDir, Handler handler, PlatformIdleStateCallback cb, Loading
core/java/com/android/internal/os/CpuPowerCalculator.java +7 −4 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ public class CpuPowerCalculator extends PowerCalculator { public long durationFgMs; public String packageWithHighestDrain; public double[] perProcStatePowerMah; public long[] cpuFreqTimes; } public CpuPowerCalculator(PowerProfile profile) { Loading Loading @@ -98,6 +99,9 @@ public class CpuPowerCalculator extends PowerCalculator { BatteryConsumer.Key[] keys = UNINITIALIZED_KEYS; Result result = new Result(); if (query.isProcessStateDataNeeded()) { result.cpuFreqTimes = new long[batteryStats.getCpuFreqCount()]; } final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders = builder.getUidBatteryConsumerBuilders(); for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) { Loading Loading @@ -187,11 +191,10 @@ public class CpuPowerCalculator extends PowerCalculator { // TODO(b/191921016): use per-state CPU cluster times final long[] cpuClusterTimes = null; final long[] cpuFreqTimes = u.getCpuFreqTimes(BatteryStats.STATS_SINCE_CHARGED, uidProcState); if (cpuClusterTimes != null || cpuFreqTimes != null) { boolean hasCpuFreqTimes = u.getCpuFreqTimes(result.cpuFreqTimes, uidProcState); if (cpuClusterTimes != null || hasCpuFreqTimes) { result.perProcStatePowerMah[procState] += calculateUidModeledPowerMah(u, 0, cpuClusterTimes, cpuFreqTimes); 0, cpuClusterTimes, result.cpuFreqTimes); } } Loading
core/java/com/android/internal/os/LongArrayMultiStateCounter.java +16 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import dalvik.annotation.optimization.FastNative; import libcore.util.NativeAllocationRegistry; import java.util.Arrays; import java.util.concurrent.atomic.AtomicReference; /** * Performs per-state counting of multi-element values over time. The class' behavior is illustrated Loading Loading @@ -120,6 +121,8 @@ public final class LongArrayMultiStateCounter implements Parcelable { private static final NativeAllocationRegistry sRegistry = NativeAllocationRegistry.createMalloced( LongArrayMultiStateCounter.class.getClassLoader(), native_getReleaseFunc()); private static final AtomicReference<LongArrayContainer> sTmpArrayContainer = new AtomicReference<>(); private final int mStateCount; private final int mLength; Loading Loading @@ -203,6 +206,19 @@ public final class LongArrayMultiStateCounter implements Parcelable { native_reset(mNativeObject); } /** * Populates the array with the accumulated counts for the specified state. */ public void getCounts(long[] counts, int state) { LongArrayContainer container = sTmpArrayContainer.getAndSet(null); if (container == null || container.mLength != counts.length) { container = new LongArrayContainer(counts.length); } getCounts(container, state); container.getValues(counts); sTmpArrayContainer.set(container); } /** * Populates longArrayContainer with the accumulated counts for the specified state. */ Loading
core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java +34 −27 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package com.android.internal.os; import static android.os.BatteryStats.STATS_SINCE_CHARGED; import static android.os.BatteryStats.Uid.NUM_PROCESS_STATE; import static android.os.BatteryStats.Uid.PROCESS_STATE_BACKGROUND; import static android.os.BatteryStats.Uid.PROCESS_STATE_CACHED; Loading @@ -25,8 +24,10 @@ import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; Loading Loading @@ -115,14 +116,17 @@ public class BatteryStatsImplTest { {989834, 384098, 98483, 23809, 4984}, {4859048, 348903, 4578967, 5973894, 298549} }; final long[] timeInFreqs = new long[NUM_CPU_FREQS]; for (int i = 0; i < testUids.length; ++i) { mockKernelSingleUidTimeReader(testUids[i], cpuTimes[i]); // Verify there are no cpu times initially. final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUids[i]); for (int procState = 0; procState < NUM_PROCESS_STATE; ++procState) { assertNull(u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertFalse(u.getCpuFreqTimes(timeInFreqs, procState)); assertFalse(u.getScreenOffCpuFreqTimes(timeInFreqs, procState)); } } addPendingUids(testUids, testProcStates); Loading @@ -134,13 +138,13 @@ public class BatteryStatsImplTest { for (int i = 0; i < testUids.length; ++i) { final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]); for (int procState = 0; procState < NUM_PROCESS_STATE; ++procState) { final boolean hasTimeInFreq = u.getCpuFreqTimes(timeInFreqs, procState); if (procState == testProcStates[i]) { assertArrayEquals("Uid=" + testUids[i], cpuTimes[i], u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertArrayEquals("Uid=" + testUids[i], cpuTimes[i], timeInFreqs); } else { assertNull(u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertFalse(hasTimeInFreq); } assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertFalse(u.getScreenOffCpuFreqTimes(timeInFreqs, procState)); } } Loading Loading @@ -172,12 +176,12 @@ public class BatteryStatsImplTest { for (int j = 0; j < expectedCpuTimes.length; ++j) { expectedCpuTimes[j] += delta1[i][j]; } assertArrayEquals("Uid=" + testUids[i], expectedCpuTimes, u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertTrue(u.getCpuFreqTimes(timeInFreqs, procState)); assertArrayEquals("Uid=" + testUids[i], expectedCpuTimes, timeInFreqs); } else { assertNull(u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertFalse(u.getCpuFreqTimes(timeInFreqs, procState)); } assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertFalse(u.getScreenOffCpuFreqTimes(timeInFreqs, procState)); } } Loading Loading @@ -214,13 +218,13 @@ public class BatteryStatsImplTest { for (int j = 0; j < expectedCpuTimes.length; ++j) { expectedCpuTimes[j] += delta1[i][j] + delta2[i][j]; } assertArrayEquals("Uid=" + testUids[i], expectedCpuTimes, u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertArrayEquals("Uid=" + testUids[i], delta2[i], u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertTrue(u.getCpuFreqTimes(timeInFreqs, procState)); assertArrayEquals("Uid=" + testUids[i], expectedCpuTimes, timeInFreqs); assertTrue(u.getScreenOffCpuFreqTimes(timeInFreqs, procState)); assertArrayEquals("Uid=" + testUids[i], delta2[i], timeInFreqs); } else { assertNull(u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertFalse(u.getCpuFreqTimes(timeInFreqs, procState)); assertFalse(u.getScreenOffCpuFreqTimes(timeInFreqs, procState)); } } } Loading Loading @@ -262,18 +266,18 @@ public class BatteryStatsImplTest { expectedCpuTimes[j] += delta1[i][j] + delta2[i][j] + delta3[i][j] + (testUids[i] == parentUid ? isolatedUidCpuTimes[j] : 0); } assertArrayEquals("Uid=" + testUids[i], expectedCpuTimes, u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertTrue(u.getCpuFreqTimes(timeInFreqs, procState)); assertArrayEquals("Uid=" + testUids[i], expectedCpuTimes, timeInFreqs); long[] expectedScreenOffTimes = delta2[i].clone(); for (int j = 0; j < expectedScreenOffTimes.length; ++j) { expectedScreenOffTimes[j] += delta3[i][j] + (testUids[i] == parentUid ? isolatedUidCpuTimes[j] : 0); } assertArrayEquals("Uid=" + testUids[i], expectedScreenOffTimes, u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertTrue(u.getScreenOffCpuFreqTimes(timeInFreqs, procState)); assertArrayEquals("Uid=" + testUids[i], expectedScreenOffTimes, timeInFreqs); } else { assertNull(u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertFalse(u.getCpuFreqTimes(timeInFreqs, procState)); assertFalse(u.getScreenOffCpuFreqTimes(timeInFreqs, procState)); } } } Loading Loading @@ -329,16 +333,19 @@ public class BatteryStatsImplTest { mBatteryStatsImpl.copyFromAllUidsCpuTimes(true, false); verifyNoPendingUids(); final long[] timeInFreqs = new long[NUM_CPU_FREQS]; for (int i = 0; i < testUids.length; ++i) { final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]); for (int procState = 0; procState < NUM_PROCESS_STATE; ++procState) { if (procState == testProcStates[i]) { assertArrayEquals("Uid=" + testUids[i], expectedCpuTimes[i], u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertTrue(u.getCpuFreqTimes(timeInFreqs, procState)); assertArrayEquals("Uid=" + testUids[i], expectedCpuTimes[i], timeInFreqs); } else { assertNull(u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertFalse(u.getCpuFreqTimes(timeInFreqs, procState)); } assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState)); assertFalse(u.getScreenOffCpuFreqTimes(timeInFreqs, procState)); } } } Loading