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