1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.os; 18 19 import static org.junit.Assert.assertArrayEquals; 20 import static org.junit.Assert.assertEquals; 21 import static org.junit.Assert.assertFalse; 22 import static org.junit.Assert.assertNotNull; 23 import static org.junit.Assert.assertTrue; 24 import static org.mockito.Mockito.verifyZeroInteractions; 25 import static org.mockito.Mockito.when; 26 27 import android.support.test.filters.SmallTest; 28 import android.support.test.runner.AndroidJUnit4; 29 import android.util.SparseArray; 30 31 import org.junit.Before; 32 import org.junit.Test; 33 import org.junit.runner.RunWith; 34 import org.mockito.Mock; 35 import org.mockito.Mockito; 36 import org.mockito.MockitoAnnotations; 37 38 import java.io.BufferedReader; 39 import java.nio.ByteBuffer; 40 import java.nio.ByteOrder; 41 import java.util.Arrays; 42 43 /** 44 * Test class for {@link KernelUidCpuFreqTimeReader}. 45 * 46 * To run the tests, use 47 * 48 * runtest -c com.android.internal.os.KernelUidCpuFreqTimeReaderTest frameworks-core 49 * 50 * or the following steps: 51 * 52 * Build: m FrameworksCoreTests 53 * Install: adb install -r \ 54 * ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk 55 * Run: adb shell am instrument -e class com.android.internal.os.KernelUidCpuFreqTimeReaderTest -w \ 56 * com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner 57 * 58 * or 59 * 60 * bit FrameworksCoreTests:com.android.internal.os.KernelUidCpuFreqTimeReaderTest 61 */ 62 @SmallTest 63 @RunWith(AndroidJUnit4.class) 64 public class KernelUidCpuFreqTimeReaderTest { 65 @Mock 66 private BufferedReader mBufferedReader; 67 @Mock 68 private KernelUidCpuFreqTimeReader.Callback mCallback; 69 @Mock 70 private PowerProfile mPowerProfile; 71 @Mock 72 private KernelCpuProcReader mProcReader; 73 74 private KernelUidCpuFreqTimeReader mKernelUidCpuFreqTimeReader; 75 76 @Before 77 public void setUp() { 78 MockitoAnnotations.initMocks(this); 79 mKernelUidCpuFreqTimeReader = new KernelUidCpuFreqTimeReader(mProcReader); 80 mKernelUidCpuFreqTimeReader.setThrottleInterval(0); 81 } 82 83 @Test 84 public void testReadFreqs_perClusterTimesNotAvailable() throws Exception { 85 final long[][] freqs = { 86 {1, 12, 123, 1234}, 87 {1, 12, 123, 23, 123, 1234, 12345, 123456}, 88 {1, 12, 123, 23, 123, 1234, 12345, 123456, 12, 123, 12345}, 89 {1, 12, 123, 23, 2345, 234567} 90 }; 91 final int[] numClusters = {2, 2, 3, 1}; 92 final int[][] numFreqs = {{3, 6}, {4, 5}, {3, 5, 4}, {3}}; 93 for (int i = 0; i < freqs.length; ++i) { 94 setCpuClusterFreqs(numClusters[i], numFreqs[i]); 95 when(mBufferedReader.readLine()).thenReturn(getFreqsLine(freqs[i])); 96 long[] actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs( 97 mBufferedReader, mPowerProfile); 98 assertArrayEquals(freqs[i], actualFreqs); 99 verifyZeroInteractions(mCallback); 100 final String errMsg = String.format("Freqs=%s, nClusters=%d, nFreqs=%s", 101 Arrays.toString(freqs[i]), numClusters[i], Arrays.toString(numFreqs[i])); 102 assertFalse(errMsg, mKernelUidCpuFreqTimeReader.perClusterTimesAvailable()); 103 104 // Verify that a second call won't read the proc file again 105 Mockito.reset(mBufferedReader); 106 actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mPowerProfile); 107 assertArrayEquals(freqs[i], actualFreqs); 108 assertFalse(errMsg, mKernelUidCpuFreqTimeReader.perClusterTimesAvailable()); 109 110 // Prepare for next iteration 111 Mockito.reset(mBufferedReader, mPowerProfile); 112 } 113 } 114 115 @Test 116 public void testReadFreqs_perClusterTimesAvailable() throws Exception { 117 final long[][] freqs = { 118 {1, 12, 123, 1234}, 119 {1, 12, 123, 23, 123, 1234, 12345, 123456}, 120 {1, 12, 123, 23, 123, 1234, 12345, 123456, 12, 123, 12345, 1234567} 121 }; 122 final int[] numClusters = {1, 2, 3}; 123 final int[][] numFreqs = {{4}, {3, 5}, {3, 5, 4}}; 124 for (int i = 0; i < freqs.length; ++i) { 125 setCpuClusterFreqs(numClusters[i], numFreqs[i]); 126 when(mBufferedReader.readLine()).thenReturn(getFreqsLine(freqs[i])); 127 long[] actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs( 128 mBufferedReader, mPowerProfile); 129 assertArrayEquals(freqs[i], actualFreqs); 130 verifyZeroInteractions(mCallback); 131 final String errMsg = String.format("Freqs=%s, nClusters=%d, nFreqs=%s", 132 Arrays.toString(freqs[i]), numClusters[i], Arrays.toString(numFreqs[i])); 133 assertTrue(errMsg, mKernelUidCpuFreqTimeReader.perClusterTimesAvailable()); 134 135 // Verify that a second call won't read the proc file again 136 Mockito.reset(mBufferedReader); 137 actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mPowerProfile); 138 assertArrayEquals(freqs[i], actualFreqs); 139 assertTrue(errMsg, mKernelUidCpuFreqTimeReader.perClusterTimesAvailable()); 140 141 // Prepare for next iteration 142 Mockito.reset(mBufferedReader, mPowerProfile); 143 } 144 } 145 146 @Test 147 public void testReadDelta_Binary() throws Exception { 148 VerifiableCallback cb = new VerifiableCallback(); 149 final long[] freqs = {110, 123, 145, 167, 289, 997}; 150 final int[] uids = {1, 22, 333, 444, 555}; 151 final long[][] times = new long[uids.length][freqs.length]; 152 for (int i = 0; i < uids.length; ++i) { 153 for (int j = 0; j < freqs.length; ++j) { 154 times[i][j] = uids[i] * freqs[j] * 10; 155 } 156 } 157 when(mBufferedReader.readLine()).thenReturn(getFreqsLine(freqs)); 158 long[] actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mBufferedReader, mPowerProfile); 159 160 assertArrayEquals(freqs, actualFreqs); 161 when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times)); 162 mKernelUidCpuFreqTimeReader.readDeltaImpl(cb); 163 for (int i = 0; i < uids.length; ++i) { 164 cb.verify(uids[i], times[i]); 165 } 166 cb.verifyNoMoreInteractions(); 167 168 // Verify that a second call will only return deltas. 169 cb.clear(); 170 Mockito.reset(mProcReader); 171 final long[][] newTimes1 = new long[uids.length][freqs.length]; 172 for (int i = 0; i < uids.length; ++i) { 173 for (int j = 0; j < freqs.length; ++j) { 174 newTimes1[i][j] = times[i][j] + (uids[i] + freqs[j]) * 50; 175 } 176 } 177 when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, newTimes1)); 178 mKernelUidCpuFreqTimeReader.readDeltaImpl(cb); 179 for (int i = 0; i < uids.length; ++i) { 180 cb.verify(uids[i], subtract(newTimes1[i], times[i])); 181 } 182 cb.verifyNoMoreInteractions(); 183 184 // Verify that there won't be a callback if the proc file values didn't change. 185 cb.clear(); 186 Mockito.reset(mProcReader); 187 when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, newTimes1)); 188 mKernelUidCpuFreqTimeReader.readDeltaImpl(cb); 189 cb.verifyNoMoreInteractions(); 190 191 // Verify that calling with a null callback doesn't result in any crashes 192 cb.clear(); 193 Mockito.reset(mProcReader); 194 final long[][] newTimes2 = new long[uids.length][freqs.length]; 195 for (int i = 0; i < uids.length; ++i) { 196 for (int j = 0; j < freqs.length; ++j) { 197 newTimes2[i][j] = newTimes1[i][j] + (uids[i] * freqs[j]) * 30; 198 } 199 } 200 when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, newTimes2)); 201 mKernelUidCpuFreqTimeReader.readDeltaImpl(null); 202 cb.verifyNoMoreInteractions(); 203 204 // Verify that the readDelta call will only return deltas when 205 // the previous call had null callback. 206 cb.clear(); 207 Mockito.reset(mProcReader); 208 final long[][] newTimes3 = new long[uids.length][freqs.length]; 209 for (int i = 0; i < uids.length; ++i) { 210 for (int j = 0; j < freqs.length; ++j) { 211 newTimes3[i][j] = newTimes2[i][j] + (uids[i] + freqs[j]) * 40; 212 } 213 } 214 when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, newTimes3)); 215 mKernelUidCpuFreqTimeReader.readDeltaImpl(cb); 216 for (int i = 0; i < uids.length; ++i) { 217 cb.verify(uids[i], subtract(newTimes3[i], newTimes2[i])); 218 } 219 cb.verifyNoMoreInteractions(); 220 } 221 222 @Test 223 public void testReadAbsolute() throws Exception { 224 VerifiableCallback cb = new VerifiableCallback(); 225 final long[] freqs = {110, 123, 145, 167, 289, 997}; 226 final int[] uids = {1, 22, 333, 444, 555}; 227 final long[][] times = new long[uids.length][freqs.length]; 228 for (int i = 0; i < uids.length; ++i) { 229 for (int j = 0; j < freqs.length; ++j) { 230 times[i][j] = uids[i] * freqs[j] * 10; 231 } 232 } 233 when(mBufferedReader.readLine()).thenReturn(getFreqsLine(freqs)); 234 long[] actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mBufferedReader, mPowerProfile); 235 236 assertArrayEquals(freqs, actualFreqs); 237 // Verify that the absolute values are returned 238 when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times)); 239 mKernelUidCpuFreqTimeReader.readAbsolute(cb); 240 for (int i = 0; i < uids.length; ++i) { 241 cb.verify(uids[i], times[i]); 242 } 243 cb.verifyNoMoreInteractions(); 244 245 // Verify that a second call should still return absolute values 246 cb.clear(); 247 Mockito.reset(mProcReader); 248 final long[][] newTimes1 = new long[uids.length][freqs.length]; 249 for (int i = 0; i < uids.length; ++i) { 250 for (int j = 0; j < freqs.length; ++j) { 251 newTimes1[i][j] = times[i][j] + (uids[i] + freqs[j]) * 50; 252 } 253 } 254 when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, newTimes1)); 255 mKernelUidCpuFreqTimeReader.readAbsolute(cb); 256 for (int i = 0; i < uids.length; ++i) { 257 cb.verify(uids[i], newTimes1[i]); 258 } 259 cb.verifyNoMoreInteractions(); 260 } 261 262 private long[] subtract(long[] a1, long[] a2) { 263 long[] val = new long[a1.length]; 264 for (int i = 0; i < val.length; ++i) { 265 val[i] = a1[i] - a2[i]; 266 } 267 return val; 268 } 269 270 private String getFreqsLine(long[] freqs) { 271 final StringBuilder sb = new StringBuilder(); 272 sb.append("uid:"); 273 for (int i = 0; i < freqs.length; ++i) { 274 sb.append(" " + freqs[i]); 275 } 276 return sb.toString(); 277 } 278 279 private ByteBuffer getUidTimesBytes(int[] uids, long[][] times) { 280 int size = (1 + uids.length + uids.length * times[0].length) * 4; 281 ByteBuffer buf = ByteBuffer.allocate(size); 282 buf.order(ByteOrder.nativeOrder()); 283 buf.putInt(times[0].length); 284 for (int i = 0; i < uids.length; i++) { 285 buf.putInt(uids[i]); 286 for (int j = 0; j < times[i].length; j++) { 287 buf.putInt((int) (times[i][j] / 10)); 288 } 289 } 290 buf.flip(); 291 return buf.asReadOnlyBuffer().order(ByteOrder.nativeOrder()); 292 } 293 294 private void setCpuClusterFreqs(int numClusters, int... clusterFreqs) { 295 assertEquals(numClusters, clusterFreqs.length); 296 when(mPowerProfile.getNumCpuClusters()).thenReturn(numClusters); 297 for (int i = 0; i < numClusters; ++i) { 298 when(mPowerProfile.getNumSpeedStepsInCpuCluster(i)).thenReturn(clusterFreqs[i]); 299 } 300 } 301 302 private class VerifiableCallback implements KernelUidCpuFreqTimeReader.Callback { 303 304 SparseArray<long[]> mData = new SparseArray<>(); 305 int count = 0; 306 307 public void verify(int uid, long[] cpuFreqTimeMs) { 308 long[] array = mData.get(uid); 309 assertNotNull(array); 310 assertArrayEquals(cpuFreqTimeMs, array); 311 count++; 312 } 313 314 public void clear() { 315 mData.clear(); 316 count = 0; 317 } 318 319 @Override 320 public void onUidCpuFreqTime(int uid, long[] cpuFreqTimeMs) { 321 long[] array = new long[cpuFreqTimeMs.length]; 322 System.arraycopy(cpuFreqTimeMs, 0, array, 0, array.length); 323 mData.put(uid, array); 324 } 325 326 public void verifyNoMoreInteractions() { 327 assertEquals(mData.size(), count); 328 } 329 } 330 } 331