blob: 312af16cc8a665a014d80993d9e480b70314d2f5 [file] [log] [blame]
Mike Ma3d422c32017-10-25 11:08:57 -07001/*
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
17package com.android.internal.os;
18
Mike Ma3d422c32017-10-25 11:08:57 -070019import static org.mockito.Mockito.verify;
20import static org.mockito.Mockito.verifyNoMoreInteractions;
21import static org.mockito.Mockito.when;
22
23import android.support.test.filters.SmallTest;
24import android.support.test.runner.AndroidJUnit4;
25
Mike Ma3d422c32017-10-25 11:08:57 -070026import org.junit.Before;
27import org.junit.Test;
28import org.junit.runner.RunWith;
Mike Ma3d422c32017-10-25 11:08:57 -070029import org.mockito.Mock;
30import org.mockito.Mockito;
31import org.mockito.MockitoAnnotations;
32
Mike Ma2ab01442018-02-13 14:22:47 -080033import java.nio.ByteBuffer;
34import java.nio.ByteOrder;
Mike Ma3d422c32017-10-25 11:08:57 -070035import java.util.Random;
36
37/**
38 * Test class for {@link KernelUidCpuActiveTimeReader}.
39 *
40 * To run it:
41 * bit FrameworksCoreTests:com.android.internal.os.KernelUidCpuActiveTimeReaderTest
Mike Ma3d422c32017-10-25 11:08:57 -070042 */
43@SmallTest
44@RunWith(AndroidJUnit4.class)
45public class KernelUidCpuActiveTimeReaderTest {
Mike Ma2ab01442018-02-13 14:22:47 -080046 @Mock
47 private KernelCpuProcReader mProcReader;
48 @Mock
49 private KernelUidCpuActiveTimeReader.Callback mCallback;
Mike Ma3d422c32017-10-25 11:08:57 -070050 private KernelUidCpuActiveTimeReader mReader;
51
52 @Before
53 public void setUp() {
54 MockitoAnnotations.initMocks(this);
Mike Ma2ab01442018-02-13 14:22:47 -080055 mReader = new KernelUidCpuActiveTimeReader(mProcReader);
56 mReader.setThrottleInterval(0);
Mike Ma3d422c32017-10-25 11:08:57 -070057 }
58
59 @Test
60 public void testReadDelta() throws Exception {
61 final int cores = 8;
Mike Ma3d422c32017-10-25 11:08:57 -070062 final int[] uids = {1, 22, 333, 4444, 5555};
63
64 final long[][] times = increaseTime(new long[uids.length][cores]);
Mike Ma2ab01442018-02-13 14:22:47 -080065 when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times));
66 mReader.readDelta(mCallback);
67 for (int i = 0; i < uids.length; i++) {
Mike Ma3d422c32017-10-25 11:08:57 -070068 verify(mCallback).onUidCpuActiveTime(uids[i], getTotal(times[i]));
69 }
70 verifyNoMoreInteractions(mCallback);
71
72 // Verify that a second call will only return deltas.
Mike Ma2ab01442018-02-13 14:22:47 -080073 Mockito.reset(mCallback);
Mike Ma3d422c32017-10-25 11:08:57 -070074 final long[][] times1 = increaseTime(times);
Mike Ma2ab01442018-02-13 14:22:47 -080075 when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times1));
76 mReader.readDelta(mCallback);
77 for (int i = 0; i < uids.length; i++) {
Mike Ma3d422c32017-10-25 11:08:57 -070078 verify(mCallback).onUidCpuActiveTime(uids[i], getTotal(subtract(times1[i], times[i])));
79 }
80 verifyNoMoreInteractions(mCallback);
81
82 // Verify that there won't be a callback if the proc file values didn't change.
Mike Ma2ab01442018-02-13 14:22:47 -080083 Mockito.reset(mCallback);
84 when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times1));
85 mReader.readDelta(mCallback);
Mike Ma3d422c32017-10-25 11:08:57 -070086 verifyNoMoreInteractions(mCallback);
87
88 // Verify that calling with a null callback doesn't result in any crashes
Mike Ma2ab01442018-02-13 14:22:47 -080089 Mockito.reset(mCallback);
Mike Ma3d422c32017-10-25 11:08:57 -070090 final long[][] times2 = increaseTime(times1);
Mike Ma2ab01442018-02-13 14:22:47 -080091 when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times2));
92 mReader.readDelta(null);
Mike Ma3d422c32017-10-25 11:08:57 -070093
94 // Verify that the readDelta call will only return deltas when
95 // the previous call had null callback.
Mike Ma2ab01442018-02-13 14:22:47 -080096 Mockito.reset(mCallback);
Mike Ma3d422c32017-10-25 11:08:57 -070097 final long[][] times3 = increaseTime(times2);
Mike Ma2ab01442018-02-13 14:22:47 -080098 when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times3));
99 mReader.readDelta(mCallback);
Mike Ma3d422c32017-10-25 11:08:57 -0700100 for (int i = 0; i < uids.length; ++i) {
101 verify(mCallback).onUidCpuActiveTime(uids[i], getTotal(subtract(times3[i], times2[i])));
102 }
103 verifyNoMoreInteractions(mCallback);
104 }
105
106 @Test
107 public void testReadDelta_malformedData() throws Exception {
108 final int cores = 8;
Mike Ma3d422c32017-10-25 11:08:57 -0700109 final int[] uids = {1, 22, 333, 4444, 5555};
110 final long[][] times = increaseTime(new long[uids.length][cores]);
Mike Ma2ab01442018-02-13 14:22:47 -0800111 when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times));
112 mReader.readDelta(mCallback);
113 for (int i = 0; i < uids.length; i++) {
Mike Ma3d422c32017-10-25 11:08:57 -0700114 verify(mCallback).onUidCpuActiveTime(uids[i], getTotal(times[i]));
115 }
116 verifyNoMoreInteractions(mCallback);
117
Mike Ma2ab01442018-02-13 14:22:47 -0800118 // Verify that there is no callback if subsequent call is in wrong format.
119 Mockito.reset(mCallback);
120 final long[][] times1 = increaseTime(times);
121 when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times1).putInt(0, 5));
122 mReader.readDelta(mCallback);
Mike Ma3d422c32017-10-25 11:08:57 -0700123 verifyNoMoreInteractions(mCallback);
124
125 // Verify that the internal state was not modified if the given core count does not match
126 // the following # of entries.
Mike Ma2ab01442018-02-13 14:22:47 -0800127 Mockito.reset(mCallback);
Mike Ma3d422c32017-10-25 11:08:57 -0700128 final long[][] times2 = increaseTime(times);
Mike Ma2ab01442018-02-13 14:22:47 -0800129 when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times2));
130 mReader.readDelta(mCallback);
131 for (int i = 0; i < uids.length; i++) {
Mike Ma3d422c32017-10-25 11:08:57 -0700132 verify(mCallback).onUidCpuActiveTime(uids[i], getTotal(subtract(times2[i], times[i])));
133 }
134 verifyNoMoreInteractions(mCallback);
135
136 // Verify that there is no callback if any value in the proc file is -ve.
Mike Ma2ab01442018-02-13 14:22:47 -0800137 Mockito.reset(mCallback);
Mike Ma3d422c32017-10-25 11:08:57 -0700138 final long[][] times3 = increaseTime(times2);
139 times3[uids.length - 1][cores - 1] *= -1;
Mike Ma2ab01442018-02-13 14:22:47 -0800140 when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times3));
141 mReader.readDelta(mCallback);
Mike Ma3d422c32017-10-25 11:08:57 -0700142 for (int i = 0; i < uids.length - 1; ++i) {
143 verify(mCallback).onUidCpuActiveTime(uids[i], getTotal(subtract(times3[i], times2[i])));
144 }
145 verifyNoMoreInteractions(mCallback);
146
147 // Verify that the internal state was not modified when the proc file had -ve value.
Mike Ma2ab01442018-02-13 14:22:47 -0800148 Mockito.reset(mCallback);
Mike Ma3d422c32017-10-25 11:08:57 -0700149 for (int i = 0; i < cores; i++) {
Mike Ma2ab01442018-02-13 14:22:47 -0800150 times3[uids.length - 1][i] = times2[uids.length - 1][i] + uids[uids.length - 1] * 2520;
Mike Ma3d422c32017-10-25 11:08:57 -0700151 }
Mike Ma2ab01442018-02-13 14:22:47 -0800152 when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times3));
153 mReader.readDelta(mCallback);
154 verify(mCallback).onUidCpuActiveTime(uids[uids.length - 1],
155 getTotal(subtract(times3[uids.length - 1], times2[uids.length - 1])));
Mike Ma3d422c32017-10-25 11:08:57 -0700156 verifyNoMoreInteractions(mCallback);
157
158 // Verify that there is no callback if the values in the proc file are decreased.
Mike Ma2ab01442018-02-13 14:22:47 -0800159 Mockito.reset(mCallback);
Mike Ma3d422c32017-10-25 11:08:57 -0700160 final long[][] times4 = increaseTime(times3);
Mike Ma2ab01442018-02-13 14:22:47 -0800161 System.arraycopy(times3[uids.length - 1], 0, times4[uids.length - 1], 0, cores);
162 times4[uids.length - 1][cores - 1] -= 100;
163 when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times4));
164 mReader.readDelta(mCallback);
Mike Ma3d422c32017-10-25 11:08:57 -0700165 for (int i = 0; i < uids.length - 1; ++i) {
166 verify(mCallback).onUidCpuActiveTime(uids[i], getTotal(subtract(times4[i], times3[i])));
167 }
168 verifyNoMoreInteractions(mCallback);
169
170 // Verify that the internal state was not modified when the proc file had decreased values.
Mike Ma2ab01442018-02-13 14:22:47 -0800171 Mockito.reset(mCallback);
Mike Ma3d422c32017-10-25 11:08:57 -0700172 for (int i = 0; i < cores; i++) {
Mike Ma2ab01442018-02-13 14:22:47 -0800173 times4[uids.length - 1][i] = times3[uids.length - 1][i] + uids[uids.length - 1] * 2520;
Mike Ma3d422c32017-10-25 11:08:57 -0700174 }
Mike Ma2ab01442018-02-13 14:22:47 -0800175 when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times4));
176 mReader.readDelta(mCallback);
177 verify(mCallback).onUidCpuActiveTime(uids[uids.length - 1],
178 getTotal(subtract(times4[uids.length - 1], times3[uids.length - 1])));
Mike Ma3d422c32017-10-25 11:08:57 -0700179 verifyNoMoreInteractions(mCallback);
180 }
181
182 private long[] subtract(long[] a1, long[] a2) {
183 long[] val = new long[a1.length];
184 for (int i = 0; i < val.length; ++i) {
185 val[i] = a1[i] - a2[i];
186 }
187 return val;
188 }
189
Mike Ma2ab01442018-02-13 14:22:47 -0800190 /**
191 * Unit of original and return value is 10ms. What's special about 2520? 2520 is LCM of 1, 2, 3,
192 * ..., 10. So that when wedivide shared cpu time by concurrent thread count, we always get a
193 * nice integer, avoiding rounding errors.
194 */
Mike Ma3d422c32017-10-25 11:08:57 -0700195 private long[][] increaseTime(long[][] original) {
196 long[][] newTime = new long[original.length][original[0].length];
197 Random rand = new Random();
Mike Ma2ab01442018-02-13 14:22:47 -0800198 for (int i = 0; i < original.length; i++) {
199 for (int j = 0; j < original[0].length; j++) {
200 newTime[i][j] = original[i][j] + rand.nextInt(1000) * 2520 + 2520;
Mike Ma3d422c32017-10-25 11:08:57 -0700201 }
202 }
203 return newTime;
204 }
205
Mike Ma2ab01442018-02-13 14:22:47 -0800206 // Unit of times is 10ms
Mike Ma3d422c32017-10-25 11:08:57 -0700207 private long getTotal(long[] times) {
208 long sum = 0;
Mike Ma2ab01442018-02-13 14:22:47 -0800209 for (int i = 0; i < times.length; i++) {
210 sum += times[i] * 10 / (i + 1);
Mike Ma3d422c32017-10-25 11:08:57 -0700211 }
212 return sum;
213 }
Mike Ma2ab01442018-02-13 14:22:47 -0800214
215 /**
216 * Format uids and times (in 10ms) into the following format:
217 * [n, uid0, time0a, time0b, ..., time0n,
218 * uid1, time1a, time1b, ..., time1n,
219 * uid2, time2a, time2b, ..., time2n, etc.]
220 * where n is the total number of cpus (num_possible_cpus)
221 */
222 private ByteBuffer getUidTimesBytes(int[] uids, long[][] times) {
223 int size = (1 + uids.length * (times[0].length + 1)) * 4;
224 ByteBuffer buf = ByteBuffer.allocate(size);
225 buf.order(ByteOrder.nativeOrder());
226 buf.putInt(times[0].length);
227 for (int i = 0; i < uids.length; i++) {
228 buf.putInt(uids[i]);
229 for (int j = 0; j < times[i].length; j++) {
230 buf.putInt((int) times[i][j]);
231 }
232 }
233 buf.flip();
234 return buf.order(ByteOrder.nativeOrder());
235 }
Mike Ma3d422c32017-10-25 11:08:57 -0700236}