Loading core/java/android/os/BatteryStats.java +20 −16 Original line number Diff line number Diff line Loading @@ -3667,9 +3667,12 @@ public abstract class BatteryStats implements Parcelable { 0 /* old cpu power, keep for compatibility */); } // If the cpuFreqs is null, then don't bother checking for cpu freq times. if (cpuFreqs != null) { final long[] cpuFreqTimeMs = u.getCpuFreqTimes(which); // If total cpuFreqTimes is null, then we don't need to check for screenOffCpuFreqTimes. if (cpuFreqTimeMs != null) { // If total cpuFreqTimes is null, then we don't need to check for // screenOffCpuFreqTimes. if (cpuFreqTimeMs != null && cpuFreqTimeMs.length == cpuFreqs.length) { sb.setLength(0); for (int i = 0; i < cpuFreqTimeMs.length; ++i) { sb.append((i == 0 ? "" : ",") + cpuFreqTimeMs[i]); Loading @@ -3687,6 +3690,7 @@ public abstract class BatteryStats implements Parcelable { dumpLine(pw, uid, category, CPU_TIMES_AT_FREQ_DATA, UID_TIMES_TYPE_ALL, cpuFreqTimeMs.length, sb.toString()); } } final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats(); Loading core/java/com/android/internal/os/BatteryStatsImpl.java +114 −41 Original line number Diff line number Diff line Loading @@ -119,7 +119,7 @@ public class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version private static final int VERSION = 164 + (USE_OLD_HISTORY ? 1000 : 0); private static final int VERSION = 165 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS; Loading Loading @@ -232,7 +232,7 @@ public class BatteryStatsImpl extends BatteryStats { switch (msg.what) { case MSG_UPDATE_WAKELOCKS: synchronized (BatteryStatsImpl.this) { updateCpuTimeLocked(false /* updateCpuFreqData */); updateCpuTimeLocked(); } if (cb != null) { cb.batteryNeedsCpuUpdate(); Loading Loading @@ -1082,6 +1082,10 @@ public class BatteryStatsImpl extends BatteryStats { } } public int getSize() { return mCounts == null ? 0 : mCounts.length; } /** * Clear state of this counter. */ Loading Loading @@ -3530,7 +3534,7 @@ public class BatteryStatsImpl extends BatteryStats { Slog.d(TAG, "Updating cpu time because screen is now " + (screenOff ? "off" : "on") + " and battery is " + (unplugged ? "on" : "off")); } updateCpuTimeLocked(true /* updateCpuFreqData */); updateCpuTimeLocked(); mOnBatteryTimeBase.setRunning(unplugged, uptime, realtime); mOnBatteryScreenOffTimeBase.setRunning(unplugged && screenOff, uptime, realtime); Loading Loading @@ -10246,6 +10250,7 @@ public class BatteryStatsImpl extends BatteryStats { // Used in updateCpuTimeLocked(). long mTempTotalCpuUserTimeUs; long mTempTotalCpuSystemTimeUs; long[][] mWakeLockAllocationsUs; /** * Reads the newest memory stats from the kernel. Loading Loading @@ -10279,7 +10284,7 @@ public class BatteryStatsImpl extends BatteryStats { * and we are on battery with screen off, we give more of the cpu time to those apps holding * wakelocks. If the screen is on, we just assign the actual cpu time an app used. */ public void updateCpuTimeLocked(boolean updateCpuFreqData) { public void updateCpuTimeLocked() { if (mPowerProfile == null) { return; } Loading @@ -10288,6 +10293,10 @@ public class BatteryStatsImpl extends BatteryStats { Slog.d(TAG, "!Cpu updating!"); } if (mCpuFreqs == null) { mCpuFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mPowerProfile); } // Calculate the wakelocks we have to distribute amongst. The system is excluded as it is // usually holding the wakelock on behalf of an app. // And Only distribute cpu power to wakelocks if the screen is off and we're on battery. Loading Loading @@ -10320,12 +10329,15 @@ public class BatteryStatsImpl extends BatteryStats { } mUserInfoProvider.refreshUserIds(); final SparseLongArray updatedUids = new SparseLongArray(); final SparseLongArray updatedUids = mKernelUidCpuFreqTimeReader.perClusterTimesAvailable() ? null : new SparseLongArray(); readKernelUidCpuTimesLocked(partialTimersToConsider, updatedUids); // updatedUids=null means /proc/uid_time_in_state provides snapshots of per-cluster cpu // freqs, so no need to approximate these values. if (updatedUids != null) { updateClusterSpeedTimes(updatedUids); if (updateCpuFreqData) { readKernelUidCpuFreqTimesLocked(); } readKernelUidCpuFreqTimesLocked(partialTimersToConsider); } /** Loading Loading @@ -10526,17 +10538,17 @@ public class BatteryStatsImpl extends BatteryStats { /** * Take a snapshot of the cpu times spent by each uid in each freq and update the * corresponding counters. * * @param partialTimers The wakelock holders among which the cpu freq times will be distributed. */ @VisibleForTesting public void readKernelUidCpuFreqTimesLocked() { mKernelUidCpuFreqTimeReader.readDelta(new KernelUidCpuFreqTimeReader.Callback() { @Override public void onCpuFreqs(long[] cpuFreqs) { mCpuFreqs = cpuFreqs; } @Override public void onUidCpuFreqTime(int uid, long[] cpuFreqTimeMs) { public void readKernelUidCpuFreqTimesLocked(@Nullable ArrayList<StopwatchTimer> partialTimers) { final boolean perClusterTimesAvailable = mKernelUidCpuFreqTimeReader.perClusterTimesAvailable(); final int numWakelocks = partialTimers == null ? 0 : partialTimers.size(); final int numClusters = mPowerProfile.getNumCpuClusters(); mWakeLockAllocationsUs = null; mKernelUidCpuFreqTimeReader.readDelta((uid, cpuFreqTimeMs) -> { uid = mapUid(uid); if (Process.isIsolated(uid)) { mKernelUidCpuFreqTimeReader.removeUid(uid); Loading @@ -10549,17 +10561,86 @@ public class BatteryStatsImpl extends BatteryStats { return; } final Uid u = getUidStatsLocked(uid); if (u.mCpuFreqTimeMs == null) { if (u.mCpuFreqTimeMs == null || u.mCpuFreqTimeMs.getSize() != cpuFreqTimeMs.length) { u.mCpuFreqTimeMs = new LongSamplingCounterArray(mOnBatteryTimeBase); } u.mCpuFreqTimeMs.addCountLocked(cpuFreqTimeMs); if (u.mScreenOffCpuFreqTimeMs == null) { if (u.mScreenOffCpuFreqTimeMs == null || u.mScreenOffCpuFreqTimeMs.getSize() != cpuFreqTimeMs.length) { u.mScreenOffCpuFreqTimeMs = new LongSamplingCounterArray( mOnBatteryScreenOffTimeBase); } u.mScreenOffCpuFreqTimeMs.addCountLocked(cpuFreqTimeMs); if (perClusterTimesAvailable) { if (u.mCpuClusterSpeedTimesUs == null || u.mCpuClusterSpeedTimesUs.length != numClusters) { u.mCpuClusterSpeedTimesUs = new LongSamplingCounter[numClusters][]; } if (numWakelocks > 0 && mWakeLockAllocationsUs == null) { mWakeLockAllocationsUs = new long[numClusters][]; } int freqIndex = 0; for (int cluster = 0; cluster < numClusters; ++cluster) { final int speedsInCluster = mPowerProfile.getNumSpeedStepsInCpuCluster(cluster); if (u.mCpuClusterSpeedTimesUs[cluster] == null || u.mCpuClusterSpeedTimesUs[cluster].length != speedsInCluster) { u.mCpuClusterSpeedTimesUs[cluster] = new LongSamplingCounter[speedsInCluster]; } if (numWakelocks > 0 && mWakeLockAllocationsUs[cluster] == null) { mWakeLockAllocationsUs[cluster] = new long[speedsInCluster]; } final LongSamplingCounter[] cpuTimesUs = u.mCpuClusterSpeedTimesUs[cluster]; for (int speed = 0; speed < speedsInCluster; ++speed) { if (cpuTimesUs[speed] == null) { cpuTimesUs[speed] = new LongSamplingCounter(mOnBatteryTimeBase); } final long appAllocationUs; if (mWakeLockAllocationsUs != null) { appAllocationUs = (cpuFreqTimeMs[freqIndex] * 1000 * WAKE_LOCK_WEIGHT) / 100; mWakeLockAllocationsUs[cluster][speed] += (cpuFreqTimeMs[freqIndex] * 1000 - appAllocationUs); } else { appAllocationUs = cpuFreqTimeMs[freqIndex] * 1000; } cpuTimesUs[speed].addCountLocked(appAllocationUs); freqIndex++; } } } }); if (mWakeLockAllocationsUs != null) { for (int i = 0; i < numWakelocks; ++i) { final Uid u = partialTimers.get(i).mUid; if (u.mCpuClusterSpeedTimesUs == null || u.mCpuClusterSpeedTimesUs.length != numClusters) { u.mCpuClusterSpeedTimesUs = new LongSamplingCounter[numClusters][]; } for (int cluster = 0; cluster < numClusters; ++cluster) { final int speedsInCluster = mPowerProfile.getNumSpeedStepsInCpuCluster(cluster); if (u.mCpuClusterSpeedTimesUs[cluster] == null || u.mCpuClusterSpeedTimesUs[cluster].length != speedsInCluster) { u.mCpuClusterSpeedTimesUs[cluster] = new LongSamplingCounter[speedsInCluster]; } final LongSamplingCounter[] cpuTimeUs = u.mCpuClusterSpeedTimesUs[cluster]; for (int speed = 0; speed < speedsInCluster; ++speed) { if (cpuTimeUs[speed] == null) { cpuTimeUs[speed] = new LongSamplingCounter(mOnBatteryTimeBase); } final long allocationUs = mWakeLockAllocationsUs[cluster][speed] / (numWakelocks - i); cpuTimeUs[speed].addCountLocked(allocationUs); mWakeLockAllocationsUs[cluster][speed] -= allocationUs; } } } } } boolean setChargingLocked(boolean charging) { Loading Loading @@ -11668,8 +11749,6 @@ public class BatteryStatsImpl extends BatteryStats { } } mCpuFreqs = in.createLongArray(); final int NU = in.readInt(); if (NU > 10000) { throw new ParcelFormatException("File corrupt: too many uids " + NU); Loading Loading @@ -12062,8 +12141,6 @@ public class BatteryStatsImpl extends BatteryStats { } } out.writeLongArray(mCpuFreqs); final int NU = mUidStats.size(); out.writeInt(NU); for (int iu = 0; iu < NU; iu++) { Loading Loading @@ -12528,8 +12605,6 @@ public class BatteryStatsImpl extends BatteryStats { mFlashlightTurnedOnTimers.clear(); mCameraTurnedOnTimers.clear(); mCpuFreqs = in.createLongArray(); int numUids = in.readInt(); mUidStats.clear(); for (int i = 0; i < numUids; i++) { Loading Loading @@ -12689,8 +12764,6 @@ public class BatteryStatsImpl extends BatteryStats { } } out.writeLongArray(mCpuFreqs); if (inclUids) { int size = mUidStats.size(); out.writeInt(size); Loading core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java +86 −15 Original line number Diff line number Diff line Loading @@ -16,8 +16,12 @@ package com.android.internal.os; import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.SystemClock; import android.util.IntArray; import android.util.Slog; import android.util.SparseArray; import android.util.TimeUtils; Loading Loading @@ -46,7 +50,6 @@ public class KernelUidCpuFreqTimeReader { private static final String UID_TIMES_PROC_FILE = "/proc/uid_time_in_state"; public interface Callback { void onCpuFreqs(long[] cpuFreqs); void onUidCpuFreqTime(int uid, long[] cpuFreqTimeMs); } Loading @@ -62,18 +65,51 @@ public class KernelUidCpuFreqTimeReader { private static final int TOTAL_READ_ERROR_COUNT = 5; private int mReadErrorCounter; private boolean mProcFileAvailable; private boolean mPerClusterTimesAvailable; public void readDelta(@Nullable Callback callback) { public boolean perClusterTimesAvailable() { return mPerClusterTimesAvailable; } public long[] readFreqs(@NonNull PowerProfile powerProfile) { checkNotNull(powerProfile); if (mCpuFreqs != null) { // No need to read cpu freqs more than once. return mCpuFreqs; } if (!mProcFileAvailable && mReadErrorCounter >= TOTAL_READ_ERROR_COUNT) { return null; } try (BufferedReader reader = new BufferedReader(new FileReader(UID_TIMES_PROC_FILE))) { mProcFileAvailable = true; return readFreqs(reader, powerProfile); } catch (IOException e) { mReadErrorCounter++; Slog.e(TAG, "Failed to read " + UID_TIMES_PROC_FILE + ": " + e); return null; } } @VisibleForTesting public long[] readFreqs(BufferedReader reader, PowerProfile powerProfile) throws IOException { final String line = reader.readLine(); if (line == null) { return null; } return readCpuFreqs(line, powerProfile); } public void readDelta(@Nullable Callback callback) { if (!mProcFileAvailable) { return; } try (BufferedReader reader = new BufferedReader(new FileReader(UID_TIMES_PROC_FILE))) { mNowTimeMs = SystemClock.elapsedRealtime(); readDelta(reader, callback); mLastTimeReadMs = mNowTimeMs; mProcFileAvailable = true; } catch (IOException e) { mReadErrorCounter++; Slog.e(TAG, "Failed to read " + UID_TIMES_PROC_FILE + ": " + e); } } Loading @@ -99,7 +135,6 @@ public class KernelUidCpuFreqTimeReader { if (line == null) { return; } readCpuFreqs(line, callback); while ((line = reader.readLine()) != null) { final int index = line.indexOf(' '); final int uid = Integer.parseInt(line.substring(0, index - 1), 10); Loading Loading @@ -151,18 +186,54 @@ public class KernelUidCpuFreqTimeReader { } } private void readCpuFreqs(String line, Callback callback) { if (mCpuFreqs == null) { private long[] readCpuFreqs(String line, PowerProfile powerProfile) { final String[] freqStr = line.split(" "); // First item would be "uid:" which needs to be ignored // First item would be "uid: " which needs to be ignored. mCpuFreqsCount = freqStr.length - 1; mCpuFreqs = new long[mCpuFreqsCount]; for (int i = 0; i < mCpuFreqsCount; ++i) { mCpuFreqs[i] = Long.parseLong(freqStr[i + 1], 10); } // Check if the freqs in the proc file correspond to per-cluster freqs. final IntArray numClusterFreqs = extractClusterInfoFromProcFileFreqs(); final int numClusters = powerProfile.getNumCpuClusters(); if (numClusterFreqs.size() == numClusters) { mPerClusterTimesAvailable = true; for (int i = 0; i < numClusters; ++i) { if (numClusterFreqs.get(i) != powerProfile.getNumSpeedStepsInCpuCluster(i)) { mPerClusterTimesAvailable = false; break; } } } else { mPerClusterTimesAvailable = false; } Slog.i(TAG, "mPerClusterTimesAvailable=" + mPerClusterTimesAvailable); return mCpuFreqs; } /** * Extracts no. of cpu clusters and no. of freqs in each of these clusters from the freqs * read from the proc file. * * We need to assume that freqs in each cluster are strictly increasing. * For e.g. if the freqs read from proc file are: 12, 34, 15, 45, 12, 15, 52. Then it means * there are 3 clusters: (12, 34), (15, 45), (12, 15, 52) * * @return an IntArray filled with no. of freqs in each cluster. */ private IntArray extractClusterInfoFromProcFileFreqs() { final IntArray numClusterFreqs = new IntArray(); int freqsFound = 0; for (int i = 0; i < mCpuFreqsCount; ++i) { freqsFound++; if (i + 1 == mCpuFreqsCount || mCpuFreqs[i + 1] <= mCpuFreqs[i]) { numClusterFreqs.add(freqsFound); freqsFound = 0; } if (callback != null) { callback.onCpuFreqs(mCpuFreqs); } return numClusterFreqs; } } core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java +316 −33 File changed.Preview size limit exceeded, changes collapsed. Show changes core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java +90 −10 Original line number Diff line number Diff line Loading @@ -16,6 +16,11 @@ package com.android.internal.os; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; Loading @@ -32,6 +37,7 @@ import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.io.BufferedReader; import java.util.Arrays; /** * Test class for {@link KernelUidCpuFreqTimeReader}. Loading @@ -47,12 +53,17 @@ import java.io.BufferedReader; * ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk * Run: adb shell am instrument -e class com.android.internal.os.KernelUidCpuFreqTimeReaderTest -w \ * com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner * * or * * bit FrameworksCoreTests:com.android.internal.os.KernelUidCpuFreqTimeReaderTest */ @SmallTest @RunWith(AndroidJUnit4.class) public class KernelUidCpuFreqTimeReaderTest { @Mock private BufferedReader mBufferedReader; @Mock private KernelUidCpuFreqTimeReader.Callback mCallback; @Mock private PowerProfile mPowerProfile; private KernelUidCpuFreqTimeReader mKernelUidCpuFreqTimeReader; Loading @@ -62,6 +73,69 @@ public class KernelUidCpuFreqTimeReaderTest { mKernelUidCpuFreqTimeReader = new KernelUidCpuFreqTimeReader(); } @Test public void testReadFreqs_perClusterTimesNotAvailable() throws Exception { final long[][] freqs = { {1, 12, 123, 1234}, {1, 12, 123, 23, 123, 1234, 12345, 123456}, {1, 12, 123, 23, 123, 1234, 12345, 123456, 12, 123, 12345}, {1, 12, 123, 23, 2345, 234567} }; final int[] numClusters = {2, 2, 3, 1}; final int[][] numFreqs = {{3, 6}, {4, 5}, {3, 5, 4}, {3}}; for (int i = 0; i < freqs.length; ++i) { setCpuClusterFreqs(numClusters[i], numFreqs[i]); when(mBufferedReader.readLine()).thenReturn(getFreqsLine(freqs[i])); long[] actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs( mBufferedReader, mPowerProfile); assertArrayEquals(freqs[i], actualFreqs); verifyZeroInteractions(mCallback); final String errMsg = String.format("Freqs=%s, nClusters=%d, nFreqs=%s", Arrays.toString(freqs[i]), numClusters[i], Arrays.toString(numFreqs[i])); assertFalse(errMsg, mKernelUidCpuFreqTimeReader.perClusterTimesAvailable()); // Verify that a second call won't read the proc file again Mockito.reset(mBufferedReader); actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mPowerProfile); assertArrayEquals(freqs[i], actualFreqs); assertFalse(errMsg, mKernelUidCpuFreqTimeReader.perClusterTimesAvailable()); // Prepare for next iteration Mockito.reset(mBufferedReader, mPowerProfile); } } @Test public void testReadFreqs_perClusterTimesAvailable() throws Exception { final long[][] freqs = { {1, 12, 123, 1234}, {1, 12, 123, 23, 123, 1234, 12345, 123456}, {1, 12, 123, 23, 123, 1234, 12345, 123456, 12, 123, 12345, 1234567} }; final int[] numClusters = {1, 2, 3}; final int[][] numFreqs = {{4}, {3, 5}, {3, 5, 4}}; for (int i = 0; i < freqs.length; ++i) { setCpuClusterFreqs(numClusters[i], numFreqs[i]); when(mBufferedReader.readLine()).thenReturn(getFreqsLine(freqs[i])); long[] actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs( mBufferedReader, mPowerProfile); assertArrayEquals(freqs[i], actualFreqs); verifyZeroInteractions(mCallback); final String errMsg = String.format("Freqs=%s, nClusters=%d, nFreqs=%s", Arrays.toString(freqs[i]), numClusters[i], Arrays.toString(numFreqs[i])); assertTrue(errMsg, mKernelUidCpuFreqTimeReader.perClusterTimesAvailable()); // Verify that a second call won't read the proc file again Mockito.reset(mBufferedReader); actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mPowerProfile); assertArrayEquals(freqs[i], actualFreqs); assertTrue(errMsg, mKernelUidCpuFreqTimeReader.perClusterTimesAvailable()); // Prepare for next iteration Mockito.reset(mBufferedReader, mPowerProfile); } } @Test public void testReadDelta() throws Exception { final long[] freqs = {1, 12, 123, 1234, 12345, 123456}; Loading @@ -72,10 +146,13 @@ public class KernelUidCpuFreqTimeReaderTest { times[i][j] = uids[i] * freqs[j] * 10; } } when(mBufferedReader.readLine()).thenReturn(getFreqsLine(freqs)); long[] actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mBufferedReader, mPowerProfile); assertArrayEquals(freqs, actualFreqs); when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, times)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); for (int i = 0; i < uids.length; ++i) { verify(mCallback).onUidCpuFreqTime(uids[i], times[i]); } Loading @@ -92,7 +169,6 @@ public class KernelUidCpuFreqTimeReaderTest { when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes1)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); for (int i = 0; i < uids.length; ++i) { verify(mCallback).onUidCpuFreqTime(uids[i], subtract(newTimes1[i], times[i])); } Loading @@ -103,7 +179,6 @@ public class KernelUidCpuFreqTimeReaderTest { when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes1)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); verifyNoMoreInteractions(mCallback); // Verify that calling with a null callback doesn't result in any crashes Loading @@ -117,7 +192,6 @@ public class KernelUidCpuFreqTimeReaderTest { when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes2)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, null); verifyZeroInteractions(mCallback); // Verify that the readDelta call will only return deltas when // the previous call had null callback. Loading @@ -131,7 +205,6 @@ public class KernelUidCpuFreqTimeReaderTest { when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes3)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); for (int i = 0; i < uids.length; ++i) { verify(mCallback).onUidCpuFreqTime(uids[i], subtract(newTimes3[i], newTimes2[i])); } Loading @@ -148,10 +221,13 @@ public class KernelUidCpuFreqTimeReaderTest { times[i][j] = uids[i] * freqs[j] * 10; } } when(mBufferedReader.readLine()).thenReturn(getFreqsLine(freqs)); long[] actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mBufferedReader, mPowerProfile); assertArrayEquals(freqs, actualFreqs); when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, times)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); for (int i = 0; i < uids.length; ++i) { verify(mCallback).onUidCpuFreqTime(uids[i], times[i]); } Loading @@ -169,7 +245,6 @@ public class KernelUidCpuFreqTimeReaderTest { when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes1)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); for (int i = 0; i < uids.length; ++i) { if (i == uids.length - 1) { continue; Loading @@ -186,7 +261,6 @@ public class KernelUidCpuFreqTimeReaderTest { when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes1)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); verifyNoMoreInteractions(mCallback); // Verify that there is no callback if the values in the proc file are decreased. Loading @@ -202,7 +276,6 @@ public class KernelUidCpuFreqTimeReaderTest { when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes2)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); for (int i = 0; i < uids.length; ++i) { if (i == uids.length - 1) { continue; Loading @@ -219,7 +292,6 @@ public class KernelUidCpuFreqTimeReaderTest { when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes2)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); verifyNoMoreInteractions(mCallback); } Loading Loading @@ -254,4 +326,12 @@ public class KernelUidCpuFreqTimeReaderTest { lines[uids.length] = null; return lines; } private void setCpuClusterFreqs(int numClusters, int... clusterFreqs) { assertEquals(numClusters, clusterFreqs.length); when(mPowerProfile.getNumCpuClusters()).thenReturn(numClusters); for (int i = 0; i < numClusters; ++i) { when(mPowerProfile.getNumSpeedStepsInCpuCluster(i)).thenReturn(clusterFreqs[i]); } } } Loading
core/java/android/os/BatteryStats.java +20 −16 Original line number Diff line number Diff line Loading @@ -3667,9 +3667,12 @@ public abstract class BatteryStats implements Parcelable { 0 /* old cpu power, keep for compatibility */); } // If the cpuFreqs is null, then don't bother checking for cpu freq times. if (cpuFreqs != null) { final long[] cpuFreqTimeMs = u.getCpuFreqTimes(which); // If total cpuFreqTimes is null, then we don't need to check for screenOffCpuFreqTimes. if (cpuFreqTimeMs != null) { // If total cpuFreqTimes is null, then we don't need to check for // screenOffCpuFreqTimes. if (cpuFreqTimeMs != null && cpuFreqTimeMs.length == cpuFreqs.length) { sb.setLength(0); for (int i = 0; i < cpuFreqTimeMs.length; ++i) { sb.append((i == 0 ? "" : ",") + cpuFreqTimeMs[i]); Loading @@ -3687,6 +3690,7 @@ public abstract class BatteryStats implements Parcelable { dumpLine(pw, uid, category, CPU_TIMES_AT_FREQ_DATA, UID_TIMES_TYPE_ALL, cpuFreqTimeMs.length, sb.toString()); } } final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats(); Loading
core/java/com/android/internal/os/BatteryStatsImpl.java +114 −41 Original line number Diff line number Diff line Loading @@ -119,7 +119,7 @@ public class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version private static final int VERSION = 164 + (USE_OLD_HISTORY ? 1000 : 0); private static final int VERSION = 165 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS; Loading Loading @@ -232,7 +232,7 @@ public class BatteryStatsImpl extends BatteryStats { switch (msg.what) { case MSG_UPDATE_WAKELOCKS: synchronized (BatteryStatsImpl.this) { updateCpuTimeLocked(false /* updateCpuFreqData */); updateCpuTimeLocked(); } if (cb != null) { cb.batteryNeedsCpuUpdate(); Loading Loading @@ -1082,6 +1082,10 @@ public class BatteryStatsImpl extends BatteryStats { } } public int getSize() { return mCounts == null ? 0 : mCounts.length; } /** * Clear state of this counter. */ Loading Loading @@ -3530,7 +3534,7 @@ public class BatteryStatsImpl extends BatteryStats { Slog.d(TAG, "Updating cpu time because screen is now " + (screenOff ? "off" : "on") + " and battery is " + (unplugged ? "on" : "off")); } updateCpuTimeLocked(true /* updateCpuFreqData */); updateCpuTimeLocked(); mOnBatteryTimeBase.setRunning(unplugged, uptime, realtime); mOnBatteryScreenOffTimeBase.setRunning(unplugged && screenOff, uptime, realtime); Loading Loading @@ -10246,6 +10250,7 @@ public class BatteryStatsImpl extends BatteryStats { // Used in updateCpuTimeLocked(). long mTempTotalCpuUserTimeUs; long mTempTotalCpuSystemTimeUs; long[][] mWakeLockAllocationsUs; /** * Reads the newest memory stats from the kernel. Loading Loading @@ -10279,7 +10284,7 @@ public class BatteryStatsImpl extends BatteryStats { * and we are on battery with screen off, we give more of the cpu time to those apps holding * wakelocks. If the screen is on, we just assign the actual cpu time an app used. */ public void updateCpuTimeLocked(boolean updateCpuFreqData) { public void updateCpuTimeLocked() { if (mPowerProfile == null) { return; } Loading @@ -10288,6 +10293,10 @@ public class BatteryStatsImpl extends BatteryStats { Slog.d(TAG, "!Cpu updating!"); } if (mCpuFreqs == null) { mCpuFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mPowerProfile); } // Calculate the wakelocks we have to distribute amongst. The system is excluded as it is // usually holding the wakelock on behalf of an app. // And Only distribute cpu power to wakelocks if the screen is off and we're on battery. Loading Loading @@ -10320,12 +10329,15 @@ public class BatteryStatsImpl extends BatteryStats { } mUserInfoProvider.refreshUserIds(); final SparseLongArray updatedUids = new SparseLongArray(); final SparseLongArray updatedUids = mKernelUidCpuFreqTimeReader.perClusterTimesAvailable() ? null : new SparseLongArray(); readKernelUidCpuTimesLocked(partialTimersToConsider, updatedUids); // updatedUids=null means /proc/uid_time_in_state provides snapshots of per-cluster cpu // freqs, so no need to approximate these values. if (updatedUids != null) { updateClusterSpeedTimes(updatedUids); if (updateCpuFreqData) { readKernelUidCpuFreqTimesLocked(); } readKernelUidCpuFreqTimesLocked(partialTimersToConsider); } /** Loading Loading @@ -10526,17 +10538,17 @@ public class BatteryStatsImpl extends BatteryStats { /** * Take a snapshot of the cpu times spent by each uid in each freq and update the * corresponding counters. * * @param partialTimers The wakelock holders among which the cpu freq times will be distributed. */ @VisibleForTesting public void readKernelUidCpuFreqTimesLocked() { mKernelUidCpuFreqTimeReader.readDelta(new KernelUidCpuFreqTimeReader.Callback() { @Override public void onCpuFreqs(long[] cpuFreqs) { mCpuFreqs = cpuFreqs; } @Override public void onUidCpuFreqTime(int uid, long[] cpuFreqTimeMs) { public void readKernelUidCpuFreqTimesLocked(@Nullable ArrayList<StopwatchTimer> partialTimers) { final boolean perClusterTimesAvailable = mKernelUidCpuFreqTimeReader.perClusterTimesAvailable(); final int numWakelocks = partialTimers == null ? 0 : partialTimers.size(); final int numClusters = mPowerProfile.getNumCpuClusters(); mWakeLockAllocationsUs = null; mKernelUidCpuFreqTimeReader.readDelta((uid, cpuFreqTimeMs) -> { uid = mapUid(uid); if (Process.isIsolated(uid)) { mKernelUidCpuFreqTimeReader.removeUid(uid); Loading @@ -10549,17 +10561,86 @@ public class BatteryStatsImpl extends BatteryStats { return; } final Uid u = getUidStatsLocked(uid); if (u.mCpuFreqTimeMs == null) { if (u.mCpuFreqTimeMs == null || u.mCpuFreqTimeMs.getSize() != cpuFreqTimeMs.length) { u.mCpuFreqTimeMs = new LongSamplingCounterArray(mOnBatteryTimeBase); } u.mCpuFreqTimeMs.addCountLocked(cpuFreqTimeMs); if (u.mScreenOffCpuFreqTimeMs == null) { if (u.mScreenOffCpuFreqTimeMs == null || u.mScreenOffCpuFreqTimeMs.getSize() != cpuFreqTimeMs.length) { u.mScreenOffCpuFreqTimeMs = new LongSamplingCounterArray( mOnBatteryScreenOffTimeBase); } u.mScreenOffCpuFreqTimeMs.addCountLocked(cpuFreqTimeMs); if (perClusterTimesAvailable) { if (u.mCpuClusterSpeedTimesUs == null || u.mCpuClusterSpeedTimesUs.length != numClusters) { u.mCpuClusterSpeedTimesUs = new LongSamplingCounter[numClusters][]; } if (numWakelocks > 0 && mWakeLockAllocationsUs == null) { mWakeLockAllocationsUs = new long[numClusters][]; } int freqIndex = 0; for (int cluster = 0; cluster < numClusters; ++cluster) { final int speedsInCluster = mPowerProfile.getNumSpeedStepsInCpuCluster(cluster); if (u.mCpuClusterSpeedTimesUs[cluster] == null || u.mCpuClusterSpeedTimesUs[cluster].length != speedsInCluster) { u.mCpuClusterSpeedTimesUs[cluster] = new LongSamplingCounter[speedsInCluster]; } if (numWakelocks > 0 && mWakeLockAllocationsUs[cluster] == null) { mWakeLockAllocationsUs[cluster] = new long[speedsInCluster]; } final LongSamplingCounter[] cpuTimesUs = u.mCpuClusterSpeedTimesUs[cluster]; for (int speed = 0; speed < speedsInCluster; ++speed) { if (cpuTimesUs[speed] == null) { cpuTimesUs[speed] = new LongSamplingCounter(mOnBatteryTimeBase); } final long appAllocationUs; if (mWakeLockAllocationsUs != null) { appAllocationUs = (cpuFreqTimeMs[freqIndex] * 1000 * WAKE_LOCK_WEIGHT) / 100; mWakeLockAllocationsUs[cluster][speed] += (cpuFreqTimeMs[freqIndex] * 1000 - appAllocationUs); } else { appAllocationUs = cpuFreqTimeMs[freqIndex] * 1000; } cpuTimesUs[speed].addCountLocked(appAllocationUs); freqIndex++; } } } }); if (mWakeLockAllocationsUs != null) { for (int i = 0; i < numWakelocks; ++i) { final Uid u = partialTimers.get(i).mUid; if (u.mCpuClusterSpeedTimesUs == null || u.mCpuClusterSpeedTimesUs.length != numClusters) { u.mCpuClusterSpeedTimesUs = new LongSamplingCounter[numClusters][]; } for (int cluster = 0; cluster < numClusters; ++cluster) { final int speedsInCluster = mPowerProfile.getNumSpeedStepsInCpuCluster(cluster); if (u.mCpuClusterSpeedTimesUs[cluster] == null || u.mCpuClusterSpeedTimesUs[cluster].length != speedsInCluster) { u.mCpuClusterSpeedTimesUs[cluster] = new LongSamplingCounter[speedsInCluster]; } final LongSamplingCounter[] cpuTimeUs = u.mCpuClusterSpeedTimesUs[cluster]; for (int speed = 0; speed < speedsInCluster; ++speed) { if (cpuTimeUs[speed] == null) { cpuTimeUs[speed] = new LongSamplingCounter(mOnBatteryTimeBase); } final long allocationUs = mWakeLockAllocationsUs[cluster][speed] / (numWakelocks - i); cpuTimeUs[speed].addCountLocked(allocationUs); mWakeLockAllocationsUs[cluster][speed] -= allocationUs; } } } } } boolean setChargingLocked(boolean charging) { Loading Loading @@ -11668,8 +11749,6 @@ public class BatteryStatsImpl extends BatteryStats { } } mCpuFreqs = in.createLongArray(); final int NU = in.readInt(); if (NU > 10000) { throw new ParcelFormatException("File corrupt: too many uids " + NU); Loading Loading @@ -12062,8 +12141,6 @@ public class BatteryStatsImpl extends BatteryStats { } } out.writeLongArray(mCpuFreqs); final int NU = mUidStats.size(); out.writeInt(NU); for (int iu = 0; iu < NU; iu++) { Loading Loading @@ -12528,8 +12605,6 @@ public class BatteryStatsImpl extends BatteryStats { mFlashlightTurnedOnTimers.clear(); mCameraTurnedOnTimers.clear(); mCpuFreqs = in.createLongArray(); int numUids = in.readInt(); mUidStats.clear(); for (int i = 0; i < numUids; i++) { Loading Loading @@ -12689,8 +12764,6 @@ public class BatteryStatsImpl extends BatteryStats { } } out.writeLongArray(mCpuFreqs); if (inclUids) { int size = mUidStats.size(); out.writeInt(size); Loading
core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java +86 −15 Original line number Diff line number Diff line Loading @@ -16,8 +16,12 @@ package com.android.internal.os; import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.SystemClock; import android.util.IntArray; import android.util.Slog; import android.util.SparseArray; import android.util.TimeUtils; Loading Loading @@ -46,7 +50,6 @@ public class KernelUidCpuFreqTimeReader { private static final String UID_TIMES_PROC_FILE = "/proc/uid_time_in_state"; public interface Callback { void onCpuFreqs(long[] cpuFreqs); void onUidCpuFreqTime(int uid, long[] cpuFreqTimeMs); } Loading @@ -62,18 +65,51 @@ public class KernelUidCpuFreqTimeReader { private static final int TOTAL_READ_ERROR_COUNT = 5; private int mReadErrorCounter; private boolean mProcFileAvailable; private boolean mPerClusterTimesAvailable; public void readDelta(@Nullable Callback callback) { public boolean perClusterTimesAvailable() { return mPerClusterTimesAvailable; } public long[] readFreqs(@NonNull PowerProfile powerProfile) { checkNotNull(powerProfile); if (mCpuFreqs != null) { // No need to read cpu freqs more than once. return mCpuFreqs; } if (!mProcFileAvailable && mReadErrorCounter >= TOTAL_READ_ERROR_COUNT) { return null; } try (BufferedReader reader = new BufferedReader(new FileReader(UID_TIMES_PROC_FILE))) { mProcFileAvailable = true; return readFreqs(reader, powerProfile); } catch (IOException e) { mReadErrorCounter++; Slog.e(TAG, "Failed to read " + UID_TIMES_PROC_FILE + ": " + e); return null; } } @VisibleForTesting public long[] readFreqs(BufferedReader reader, PowerProfile powerProfile) throws IOException { final String line = reader.readLine(); if (line == null) { return null; } return readCpuFreqs(line, powerProfile); } public void readDelta(@Nullable Callback callback) { if (!mProcFileAvailable) { return; } try (BufferedReader reader = new BufferedReader(new FileReader(UID_TIMES_PROC_FILE))) { mNowTimeMs = SystemClock.elapsedRealtime(); readDelta(reader, callback); mLastTimeReadMs = mNowTimeMs; mProcFileAvailable = true; } catch (IOException e) { mReadErrorCounter++; Slog.e(TAG, "Failed to read " + UID_TIMES_PROC_FILE + ": " + e); } } Loading @@ -99,7 +135,6 @@ public class KernelUidCpuFreqTimeReader { if (line == null) { return; } readCpuFreqs(line, callback); while ((line = reader.readLine()) != null) { final int index = line.indexOf(' '); final int uid = Integer.parseInt(line.substring(0, index - 1), 10); Loading Loading @@ -151,18 +186,54 @@ public class KernelUidCpuFreqTimeReader { } } private void readCpuFreqs(String line, Callback callback) { if (mCpuFreqs == null) { private long[] readCpuFreqs(String line, PowerProfile powerProfile) { final String[] freqStr = line.split(" "); // First item would be "uid:" which needs to be ignored // First item would be "uid: " which needs to be ignored. mCpuFreqsCount = freqStr.length - 1; mCpuFreqs = new long[mCpuFreqsCount]; for (int i = 0; i < mCpuFreqsCount; ++i) { mCpuFreqs[i] = Long.parseLong(freqStr[i + 1], 10); } // Check if the freqs in the proc file correspond to per-cluster freqs. final IntArray numClusterFreqs = extractClusterInfoFromProcFileFreqs(); final int numClusters = powerProfile.getNumCpuClusters(); if (numClusterFreqs.size() == numClusters) { mPerClusterTimesAvailable = true; for (int i = 0; i < numClusters; ++i) { if (numClusterFreqs.get(i) != powerProfile.getNumSpeedStepsInCpuCluster(i)) { mPerClusterTimesAvailable = false; break; } } } else { mPerClusterTimesAvailable = false; } Slog.i(TAG, "mPerClusterTimesAvailable=" + mPerClusterTimesAvailable); return mCpuFreqs; } /** * Extracts no. of cpu clusters and no. of freqs in each of these clusters from the freqs * read from the proc file. * * We need to assume that freqs in each cluster are strictly increasing. * For e.g. if the freqs read from proc file are: 12, 34, 15, 45, 12, 15, 52. Then it means * there are 3 clusters: (12, 34), (15, 45), (12, 15, 52) * * @return an IntArray filled with no. of freqs in each cluster. */ private IntArray extractClusterInfoFromProcFileFreqs() { final IntArray numClusterFreqs = new IntArray(); int freqsFound = 0; for (int i = 0; i < mCpuFreqsCount; ++i) { freqsFound++; if (i + 1 == mCpuFreqsCount || mCpuFreqs[i + 1] <= mCpuFreqs[i]) { numClusterFreqs.add(freqsFound); freqsFound = 0; } if (callback != null) { callback.onCpuFreqs(mCpuFreqs); } return numClusterFreqs; } }
core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java +316 −33 File changed.Preview size limit exceeded, changes collapsed. Show changes
core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java +90 −10 Original line number Diff line number Diff line Loading @@ -16,6 +16,11 @@ package com.android.internal.os; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; Loading @@ -32,6 +37,7 @@ import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.io.BufferedReader; import java.util.Arrays; /** * Test class for {@link KernelUidCpuFreqTimeReader}. Loading @@ -47,12 +53,17 @@ import java.io.BufferedReader; * ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk * Run: adb shell am instrument -e class com.android.internal.os.KernelUidCpuFreqTimeReaderTest -w \ * com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner * * or * * bit FrameworksCoreTests:com.android.internal.os.KernelUidCpuFreqTimeReaderTest */ @SmallTest @RunWith(AndroidJUnit4.class) public class KernelUidCpuFreqTimeReaderTest { @Mock private BufferedReader mBufferedReader; @Mock private KernelUidCpuFreqTimeReader.Callback mCallback; @Mock private PowerProfile mPowerProfile; private KernelUidCpuFreqTimeReader mKernelUidCpuFreqTimeReader; Loading @@ -62,6 +73,69 @@ public class KernelUidCpuFreqTimeReaderTest { mKernelUidCpuFreqTimeReader = new KernelUidCpuFreqTimeReader(); } @Test public void testReadFreqs_perClusterTimesNotAvailable() throws Exception { final long[][] freqs = { {1, 12, 123, 1234}, {1, 12, 123, 23, 123, 1234, 12345, 123456}, {1, 12, 123, 23, 123, 1234, 12345, 123456, 12, 123, 12345}, {1, 12, 123, 23, 2345, 234567} }; final int[] numClusters = {2, 2, 3, 1}; final int[][] numFreqs = {{3, 6}, {4, 5}, {3, 5, 4}, {3}}; for (int i = 0; i < freqs.length; ++i) { setCpuClusterFreqs(numClusters[i], numFreqs[i]); when(mBufferedReader.readLine()).thenReturn(getFreqsLine(freqs[i])); long[] actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs( mBufferedReader, mPowerProfile); assertArrayEquals(freqs[i], actualFreqs); verifyZeroInteractions(mCallback); final String errMsg = String.format("Freqs=%s, nClusters=%d, nFreqs=%s", Arrays.toString(freqs[i]), numClusters[i], Arrays.toString(numFreqs[i])); assertFalse(errMsg, mKernelUidCpuFreqTimeReader.perClusterTimesAvailable()); // Verify that a second call won't read the proc file again Mockito.reset(mBufferedReader); actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mPowerProfile); assertArrayEquals(freqs[i], actualFreqs); assertFalse(errMsg, mKernelUidCpuFreqTimeReader.perClusterTimesAvailable()); // Prepare for next iteration Mockito.reset(mBufferedReader, mPowerProfile); } } @Test public void testReadFreqs_perClusterTimesAvailable() throws Exception { final long[][] freqs = { {1, 12, 123, 1234}, {1, 12, 123, 23, 123, 1234, 12345, 123456}, {1, 12, 123, 23, 123, 1234, 12345, 123456, 12, 123, 12345, 1234567} }; final int[] numClusters = {1, 2, 3}; final int[][] numFreqs = {{4}, {3, 5}, {3, 5, 4}}; for (int i = 0; i < freqs.length; ++i) { setCpuClusterFreqs(numClusters[i], numFreqs[i]); when(mBufferedReader.readLine()).thenReturn(getFreqsLine(freqs[i])); long[] actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs( mBufferedReader, mPowerProfile); assertArrayEquals(freqs[i], actualFreqs); verifyZeroInteractions(mCallback); final String errMsg = String.format("Freqs=%s, nClusters=%d, nFreqs=%s", Arrays.toString(freqs[i]), numClusters[i], Arrays.toString(numFreqs[i])); assertTrue(errMsg, mKernelUidCpuFreqTimeReader.perClusterTimesAvailable()); // Verify that a second call won't read the proc file again Mockito.reset(mBufferedReader); actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mPowerProfile); assertArrayEquals(freqs[i], actualFreqs); assertTrue(errMsg, mKernelUidCpuFreqTimeReader.perClusterTimesAvailable()); // Prepare for next iteration Mockito.reset(mBufferedReader, mPowerProfile); } } @Test public void testReadDelta() throws Exception { final long[] freqs = {1, 12, 123, 1234, 12345, 123456}; Loading @@ -72,10 +146,13 @@ public class KernelUidCpuFreqTimeReaderTest { times[i][j] = uids[i] * freqs[j] * 10; } } when(mBufferedReader.readLine()).thenReturn(getFreqsLine(freqs)); long[] actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mBufferedReader, mPowerProfile); assertArrayEquals(freqs, actualFreqs); when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, times)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); for (int i = 0; i < uids.length; ++i) { verify(mCallback).onUidCpuFreqTime(uids[i], times[i]); } Loading @@ -92,7 +169,6 @@ public class KernelUidCpuFreqTimeReaderTest { when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes1)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); for (int i = 0; i < uids.length; ++i) { verify(mCallback).onUidCpuFreqTime(uids[i], subtract(newTimes1[i], times[i])); } Loading @@ -103,7 +179,6 @@ public class KernelUidCpuFreqTimeReaderTest { when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes1)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); verifyNoMoreInteractions(mCallback); // Verify that calling with a null callback doesn't result in any crashes Loading @@ -117,7 +192,6 @@ public class KernelUidCpuFreqTimeReaderTest { when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes2)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, null); verifyZeroInteractions(mCallback); // Verify that the readDelta call will only return deltas when // the previous call had null callback. Loading @@ -131,7 +205,6 @@ public class KernelUidCpuFreqTimeReaderTest { when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes3)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); for (int i = 0; i < uids.length; ++i) { verify(mCallback).onUidCpuFreqTime(uids[i], subtract(newTimes3[i], newTimes2[i])); } Loading @@ -148,10 +221,13 @@ public class KernelUidCpuFreqTimeReaderTest { times[i][j] = uids[i] * freqs[j] * 10; } } when(mBufferedReader.readLine()).thenReturn(getFreqsLine(freqs)); long[] actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mBufferedReader, mPowerProfile); assertArrayEquals(freqs, actualFreqs); when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, times)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); for (int i = 0; i < uids.length; ++i) { verify(mCallback).onUidCpuFreqTime(uids[i], times[i]); } Loading @@ -169,7 +245,6 @@ public class KernelUidCpuFreqTimeReaderTest { when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes1)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); for (int i = 0; i < uids.length; ++i) { if (i == uids.length - 1) { continue; Loading @@ -186,7 +261,6 @@ public class KernelUidCpuFreqTimeReaderTest { when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes1)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); verifyNoMoreInteractions(mCallback); // Verify that there is no callback if the values in the proc file are decreased. Loading @@ -202,7 +276,6 @@ public class KernelUidCpuFreqTimeReaderTest { when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes2)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); for (int i = 0; i < uids.length; ++i) { if (i == uids.length - 1) { continue; Loading @@ -219,7 +292,6 @@ public class KernelUidCpuFreqTimeReaderTest { when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes2)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); verifyNoMoreInteractions(mCallback); } Loading Loading @@ -254,4 +326,12 @@ public class KernelUidCpuFreqTimeReaderTest { lines[uids.length] = null; return lines; } private void setCpuClusterFreqs(int numClusters, int... clusterFreqs) { assertEquals(numClusters, clusterFreqs.length); when(mPowerProfile.getNumCpuClusters()).thenReturn(numClusters); for (int i = 0; i < numClusters; ++i) { when(mPowerProfile.getNumSpeedStepsInCpuCluster(i)).thenReturn(clusterFreqs[i]); } } }