• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.car.storagemonitoring;
18 
19 import android.car.storagemonitoring.IoStatsEntry;
20 import android.car.storagemonitoring.UidIoRecord;
21 import android.util.SparseArray;
22 
23 import androidx.test.filters.MediumTest;
24 
25 import com.android.car.procfsinspector.ProcessInfo;
26 import com.android.car.systeminterface.SystemStateInterface;
27 import com.android.internal.annotations.GuardedBy;
28 
29 import junit.framework.TestCase;
30 
31 import java.time.Duration;
32 import java.util.ArrayList;
33 import java.util.Collections;
34 import java.util.List;
35 import java.util.stream.Collectors;
36 
37 /**
38  * Tests IoStatsTracker functionality.
39  */
40 @MediumTest
41 public class IoStatsTrackerTest extends TestCase {
42     private static final int SAMPLE_WINDOW_MS = 1000;
43     private static final List<IoStatsEntry> EMPTY = Collections.emptyList();
44     private static final String TAG = IoStatsTrackerTest.class.getSimpleName();
45 
testNewUsersAppear()46     public void testNewUsersAppear() throws Exception {
47         final MockSystemStateInterface mockSystemStateInterface = new MockSystemStateInterface();
48         IoStatsTracker ioStatsTracker = new IoStatsTracker(EMPTY,
49             SAMPLE_WINDOW_MS, mockSystemStateInterface);
50 
51         assertEquals(0, ioStatsTracker.getCurrentSample().size());
52         assertEquals(0, ioStatsTracker.getTotal().size());
53 
54         UserActivity user0 = new UserActivity(0);
55         user0.foreground_rchar = 50;
56         user0.background_wchar = 10;
57 
58         UserActivity user1 = new UserActivity(1);
59         user1.foreground_rchar = 30;
60         user1.background_wchar = 50;
61 
62         UidIoRecord process0 = user0.updateSystemState(mockSystemStateInterface);
63         UidIoRecord process1 = user1.updateSystemState(mockSystemStateInterface);
64 
65         ioStatsTracker.update(mockSystemStateInterface.mIoRecords);
66 
67         assertEquals(2, ioStatsTracker.getCurrentSample().size());
68         assertEquals(2, ioStatsTracker.getTotal().size());
69 
70         assertTrue(ioStatsTracker.getCurrentSample().get(0).representsSameMetrics(process0));
71         assertTrue(ioStatsTracker.getCurrentSample().get(1).representsSameMetrics(process1));
72 
73         assertTrue(ioStatsTracker.getTotal().get(0).representsSameMetrics(process0));
74         assertTrue(ioStatsTracker.getTotal().get(1).representsSameMetrics(process1));
75     }
76 
testUserMetricsChange()77     public void testUserMetricsChange() throws Exception {
78         final MockSystemStateInterface mockSystemStateInterface = new MockSystemStateInterface();
79         IoStatsTracker ioStatsTracker = new IoStatsTracker(EMPTY,
80             SAMPLE_WINDOW_MS, mockSystemStateInterface);
81 
82         UserActivity user0 = new UserActivity(0);
83         user0.foreground_rchar = 50;
84         user0.background_wchar = 10;
85 
86         user0.updateSystemState(mockSystemStateInterface);
87         ioStatsTracker.update(mockSystemStateInterface.mIoRecords);
88 
89         user0.foreground_rchar = 60;
90         user0.foreground_wchar = 10;
91         UidIoRecord process0 = user0.updateSystemState(mockSystemStateInterface);
92         ioStatsTracker.update(mockSystemStateInterface.mIoRecords);
93 
94         assertEquals(1, ioStatsTracker.getCurrentSample().size());
95         assertEquals(1, ioStatsTracker.getTotal().size());
96 
97         IoStatsEntry sample0 = ioStatsTracker.getCurrentSample().get(0);
98         IoStatsEntry total0 = ioStatsTracker.getTotal().get(0);
99 
100         assertNotNull(sample0);
101         assertNotNull(total0);
102 
103         assertTrue(total0.representsSameMetrics(process0));
104 
105         assertEquals(10, sample0.foreground.bytesRead);
106         assertEquals(10, sample0.foreground.bytesWritten);
107         assertEquals(0, sample0.background.bytesWritten);
108     }
109 
testUpdateNoIoProcessActive()110     public void testUpdateNoIoProcessActive() throws Exception {
111         final MockSystemStateInterface mockSystemStateInterface = new MockSystemStateInterface();
112         IoStatsTracker ioStatsTracker = new IoStatsTracker(EMPTY,
113             SAMPLE_WINDOW_MS, mockSystemStateInterface);
114 
115         UserActivity user0 = new UserActivity(0);
116         user0.foreground_rchar = 50;
117         user0.background_wchar = 10;
118 
119         user0.updateSystemState(mockSystemStateInterface);
120         ioStatsTracker.update(mockSystemStateInterface.mIoRecords);
121 
122         user0.spawnProcess();
123         user0.updateSystemState(mockSystemStateInterface);
124         ioStatsTracker.update(mockSystemStateInterface.mIoRecords);
125 
126         assertEquals(1, ioStatsTracker.getCurrentSample().size());
127         assertEquals(1, ioStatsTracker.getTotal().size());
128 
129         IoStatsEntry sample0 = ioStatsTracker.getCurrentSample().get(0);
130         IoStatsEntry total0 = ioStatsTracker.getTotal().get(0);
131 
132         assertEquals(2 * SAMPLE_WINDOW_MS, sample0.runtimeMillis);
133         assertEquals(2 * SAMPLE_WINDOW_MS, total0.runtimeMillis);
134 
135         assertEquals(0, sample0.foreground.bytesRead);
136         assertEquals(0, sample0.background.bytesWritten);
137     }
138 
testUpdateNoIoProcessInactive()139     public void testUpdateNoIoProcessInactive() throws Exception {
140         final MockSystemStateInterface mockSystemStateInterface = new MockSystemStateInterface();
141         IoStatsTracker ioStatsTracker = new IoStatsTracker(EMPTY,
142             SAMPLE_WINDOW_MS, mockSystemStateInterface);
143 
144         UserActivity user0 = new UserActivity(0);
145         user0.foreground_rchar = 50;
146         user0.background_wchar = 10;
147 
148         user0.updateSystemState(mockSystemStateInterface);
149         ioStatsTracker.update(mockSystemStateInterface.mIoRecords);
150 
151         user0.killProcess();
152         UidIoRecord record0 = user0.updateSystemState(mockSystemStateInterface);
153         ioStatsTracker.update(mockSystemStateInterface.mIoRecords);
154 
155         assertEquals(0, ioStatsTracker.getCurrentSample().size());
156         assertEquals(1, ioStatsTracker.getTotal().size());
157 
158         IoStatsEntry total0 = ioStatsTracker.getTotal().get(0);
159         assertEquals(SAMPLE_WINDOW_MS, total0.runtimeMillis);
160         assertTrue(total0.representsSameMetrics(record0));
161     }
162 
testUpdateIoHappens()163     public void testUpdateIoHappens() throws Exception {
164         final MockSystemStateInterface mockSystemStateInterface = new MockSystemStateInterface();
165         IoStatsTracker ioStatsTracker = new IoStatsTracker(EMPTY,
166             SAMPLE_WINDOW_MS, mockSystemStateInterface);
167 
168         UserActivity user0 = new UserActivity(0);
169         user0.foreground_rchar = 50;
170         user0.background_wchar = 10;
171 
172         user0.updateSystemState(mockSystemStateInterface);
173         ioStatsTracker.update(mockSystemStateInterface.mIoRecords);
174 
175         user0.foreground_rchar = 60;
176         UidIoRecord record0 = user0.updateSystemState(mockSystemStateInterface);
177         ioStatsTracker.update(mockSystemStateInterface.mIoRecords);
178 
179         assertEquals(1, ioStatsTracker.getCurrentSample().size());
180         assertEquals(1, ioStatsTracker.getTotal().size());
181 
182         IoStatsEntry sample0 = ioStatsTracker.getCurrentSample().get(0);
183         IoStatsEntry total0 = ioStatsTracker.getTotal().get(0);
184 
185         assertTrue(total0.representsSameMetrics(record0));
186         assertEquals(2 * SAMPLE_WINDOW_MS, total0.runtimeMillis);
187         assertEquals(2 * SAMPLE_WINDOW_MS, sample0.runtimeMillis);
188         assertEquals(10, sample0.foreground.bytesRead);
189         assertEquals(0, sample0.background.bytesWritten);
190     }
191 
testUpdateGoAwayComeBackProcess()192     public void testUpdateGoAwayComeBackProcess() throws Exception {
193         final MockSystemStateInterface mockSystemStateInterface = new MockSystemStateInterface();
194         IoStatsTracker ioStatsTracker = new IoStatsTracker(EMPTY,
195             SAMPLE_WINDOW_MS, mockSystemStateInterface);
196 
197         UserActivity user0 = new UserActivity(0);
198         user0.foreground_rchar = 50;
199         user0.background_wchar = 10;
200 
201         user0.updateSystemState(mockSystemStateInterface);
202         ioStatsTracker.update(mockSystemStateInterface.mIoRecords);
203 
204         ioStatsTracker.update(mockSystemStateInterface.mIoRecords);
205 
206         assertEquals(0, ioStatsTracker.getCurrentSample().size());
207         assertEquals(1, ioStatsTracker.getTotal().size());
208 
209         user0.spawnProcess();
210         user0.updateSystemState(mockSystemStateInterface);
211         ioStatsTracker.update(mockSystemStateInterface.mIoRecords);
212 
213         assertEquals(1, ioStatsTracker.getCurrentSample().size());
214         IoStatsEntry sample0 = ioStatsTracker.getCurrentSample().get(0);
215         assertEquals(2 * SAMPLE_WINDOW_MS, sample0.runtimeMillis);
216     }
217 
testUpdateGoAwayComeBackIo()218     public void testUpdateGoAwayComeBackIo() throws Exception {
219         final MockSystemStateInterface mockSystemStateInterface = new MockSystemStateInterface();
220         IoStatsTracker ioStatsTracker = new IoStatsTracker(EMPTY,
221             SAMPLE_WINDOW_MS, mockSystemStateInterface);
222 
223         UserActivity user0 = new UserActivity(0);
224         user0.foreground_rchar = 50;
225         user0.background_wchar = 10;
226 
227         user0.updateSystemState(mockSystemStateInterface);
228         ioStatsTracker.update(mockSystemStateInterface.mIoRecords);
229 
230         ioStatsTracker.update(mockSystemStateInterface.mIoRecords);
231 
232         assertEquals(0, ioStatsTracker.getCurrentSample().size());
233         assertEquals(1, ioStatsTracker.getTotal().size());
234 
235         user0.foreground_fsync = 1;
236 
237         user0.updateSystemState(mockSystemStateInterface);
238         ioStatsTracker.update(mockSystemStateInterface.mIoRecords);
239 
240         assertEquals(1, ioStatsTracker.getCurrentSample().size());
241 
242         IoStatsEntry sample0 = ioStatsTracker.getCurrentSample().get(0);
243         assertEquals(2 * SAMPLE_WINDOW_MS, sample0.runtimeMillis);
244         assertEquals(1, sample0.foreground.fsyncCalls);
245     }
246 
247     private static final class UserActivity {
248         private final int mUid;
249         private boolean mHasProcess;
250 
251         private long foreground_rchar;
252         private long foreground_wchar;
253         private long foreground_read_bytes;
254         private long foreground_write_bytes;
255         private long foreground_fsync;
256 
257         private long background_rchar;
258         private long background_wchar;
259         private long background_read_bytes;
260         private long background_write_bytes;
261         private long background_fsync;
262 
UserActivity(int uid)263         UserActivity(int uid) {
264             mUid = uid;
265         }
266 
spawnProcess()267         void spawnProcess() {
268             mHasProcess = true;
269         }
killProcess()270         void killProcess() {
271             mHasProcess = false;
272         }
273 
updateSystemState(MockSystemStateInterface systemState)274         UidIoRecord updateSystemState(MockSystemStateInterface systemState) {
275             UidIoRecord uidIoRecord = new UidIoRecord(mUid,
276                 foreground_rchar,
277                 foreground_wchar,
278                 foreground_read_bytes,
279                 foreground_write_bytes,
280                 foreground_fsync,
281                 background_rchar,
282                 background_wchar,
283                 background_read_bytes,
284                 background_write_bytes,
285                 background_fsync);
286 
287             systemState.addIoRecord(uidIoRecord);
288             if (mHasProcess) {
289                 systemState.addProcess(new ProcessInfo(1, mUid));
290             } else {
291                 systemState.removeUserProcesses(mUid);
292             }
293 
294             return uidIoRecord;
295         }
296     }
297 
298     private static final class MockSystemStateInterface implements SystemStateInterface {
299 
300         private final Object mLock = new Object();
301 
302         @GuardedBy("mLock")
303         private final List<ProcessInfo> mProcesses = new ArrayList<>();
304 
305         @GuardedBy("mLock")
306         private final SparseArray<UidIoRecord> mIoRecords = new SparseArray<>();
307 
308         @Override
shutdown()309         public void shutdown() {
310         }
311 
312         @Override
enterDeepSleep()313         public boolean enterDeepSleep() {
314             return true;
315         }
316 
317         @Override
enterHibernation()318         public boolean enterHibernation() {
319             return true;
320         }
321 
322         @Override
scheduleActionForBootCompleted(Runnable action, Duration delay, Duration delayRange)323         public void scheduleActionForBootCompleted(Runnable action, Duration delay,
324                 Duration delayRange) {
325         }
326 
327         @Override
isWakeupCausedByTimer()328         public boolean isWakeupCausedByTimer() {
329             return false;
330         }
331 
332         @Override
isSystemSupportingDeepSleep()333         public boolean isSystemSupportingDeepSleep() {
334             return false;
335         }
336 
337         @Override
getRunningProcesses()338         public List<ProcessInfo> getRunningProcesses() {
339             synchronized (mLock) {
340                 return mProcesses;
341             }
342         }
343 
addProcess(ProcessInfo processInfo)344         void addProcess(ProcessInfo processInfo) {
345             synchronized (mLock) {
346                 mProcesses.add(processInfo);
347             }
348         }
349 
removeUserProcesses(int uid)350         void removeUserProcesses(int uid) {
351             synchronized (mLock) {
352                 mProcesses.removeAll(
353                         mProcesses.stream().filter(pi -> pi.uid == uid).collect(
354                                 Collectors.toList()));
355             }
356         }
357 
addIoRecord(UidIoRecord record)358         void addIoRecord(UidIoRecord record) {
359             synchronized (mLock) {
360                 mIoRecords.put(record.uid, record);
361             }
362         }
363     }
364 }
365