Home | History | Annotate | Download | only in os
      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