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