1 /*
2 * Copyright 2020 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 #include "MockPressureMonitor.h"
18 #include "MockProcStatCollector.h"
19 #include "MockUidStatsCollector.h"
20 #include "MockWatchdogServiceHelper.h"
21 #include "PackageInfoTestUtils.h"
22 #include "PerformanceProfiler.h"
23
24 #include <WatchdogProperties.sysprop.h>
25 #include <android-base/file.h>
26 #include <gmock/gmock.h>
27 #include <utils/RefBase.h>
28
29 #include <android_car_feature.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32
33 #include <algorithm>
34 #include <string>
35 #include <type_traits>
36 #include <vector>
37
38 #include <carwatchdog_daemon_dump.pb.h>
39 #include <performance_stats.pb.h>
40
41 namespace android {
42 namespace automotive {
43 namespace watchdog {
44
45 namespace {
46
47 using ::aidl::android::automotive::watchdog::internal::ResourceStats;
48 using ::aidl::android::automotive::watchdog::internal::ResourceUsageStats;
49 using ::aidl::android::automotive::watchdog::internal::UidResourceUsageStats;
50 using ::android::RefBase;
51 using ::android::sp;
52 using ::android::base::ReadFdToString;
53 using ::android::base::Result;
54 using ::android::base::StringAppendF;
55 using ::android::car::feature::car_watchdog_memory_profiling;
56 using ::android::util::ProtoReader;
57 using ::google::protobuf::RepeatedPtrField;
58 using ::testing::_;
59 using ::testing::AllOf;
60 using ::testing::ElementsAreArray;
61 using ::testing::Eq;
62 using ::testing::ExplainMatchResult;
63 using ::testing::Field;
64 using ::testing::IsSubsetOf;
65 using ::testing::Matcher;
66 using ::testing::Pointer;
67 using ::testing::Property;
68 using ::testing::Return;
69 using ::testing::Test;
70 using ::testing::UnorderedElementsAreArray;
71 using ::testing::VariantWith;
72
73 using PressureLevelDurationPair = std::pair<PressureMonitorInterface::PressureLevel, int64_t>;
74 using PressureLevelTransitions = std::vector<PressureLevelDurationPair>;
75 using PressureLevelDurations =
76 std::unordered_map<PressureMonitorInterface::PressureLevel, std::chrono::milliseconds>;
77
78 constexpr int kTestBaseUserId = 100;
79 constexpr bool kTestIsSmapsRollupSupported = true;
80 constexpr int kTestTopNStatsPerCategory = 5;
81 constexpr int kTestTopNStatsPerSubcategory = 5;
82 constexpr int kTestMaxUserSwitchEvents = 3;
83 constexpr size_t kTestPeriodicCollectionBufferSize = 3;
84 constexpr std::chrono::seconds kTestSystemEventDataCacheDurationSec = 60s;
85 const auto kTestNowMillis = std::chrono::time_point_cast<std::chrono::milliseconds>(
86 std::chrono::system_clock::from_time_t(1'683'270'000));
87 constexpr int64_t kTestElapsedRealtimeSinceBootMillis = 19'000;
88
applyFeatureFilter(UserPackageSummaryStats * userPackageSummaryStatsOut)89 void applyFeatureFilter(UserPackageSummaryStats* userPackageSummaryStatsOut) {
90 if (car_watchdog_memory_profiling()) {
91 return;
92 }
93 userPackageSummaryStatsOut->totalRssKb = 0;
94 userPackageSummaryStatsOut->totalPssKb = 0;
95 userPackageSummaryStatsOut->topNMemStats = {};
96 }
97
98 MATCHER_P(IoStatsViewEq, expected, "") {
99 return ExplainMatchResult(AllOf(Field("bytes", &UserPackageStats::IoStatsView::bytes,
100 ElementsAreArray(expected.bytes)),
101 Field("fsync", &UserPackageStats::IoStatsView::fsync,
102 ElementsAreArray(expected.fsync))),
103 arg, result_listener);
104 }
105
106 MATCHER_P(ProcessValueEq, expected, "") {
107 return ExplainMatchResult(AllOf(Field("comm",
108 &UserPackageStats::ProcSingleStatsView::ProcessValue::
109 comm,
110 Eq(expected.comm)),
111 Field("value",
112 &UserPackageStats::ProcSingleStatsView::ProcessValue::
113 value,
114 Eq(expected.value))),
115 arg, result_listener);
116 }
117
118 MATCHER_P(ProcSingleStatsViewEq, expected, "") {
119 std::vector<Matcher<const UserPackageStats::ProcSingleStatsView::ProcessValue&>>
120 processValueMatchers;
121 processValueMatchers.reserve(expected.topNProcesses.size());
122 for (const auto& processValue : expected.topNProcesses) {
123 processValueMatchers.push_back(ProcessValueEq(processValue));
124 }
125 return ExplainMatchResult(AllOf(Field("value", &UserPackageStats::ProcSingleStatsView::value,
126 Eq(expected.value)),
127 Field("topNProcesses",
128 &UserPackageStats::ProcSingleStatsView::topNProcesses,
129 ElementsAreArray(processValueMatchers))),
130 arg, result_listener);
131 }
132
133 MATCHER_P(ProcessCpuValueEq, expected, "") {
134 return ExplainMatchResult(AllOf(Field("pid",
135 &UserPackageStats::ProcCpuStatsView::ProcessCpuValue::pid,
136 Eq(expected.pid)),
137 Field("comm",
138 &UserPackageStats::ProcCpuStatsView::ProcessCpuValue::
139 comm,
140 Eq(expected.comm)),
141 Field("cpuTimeMillis",
142 &UserPackageStats::ProcCpuStatsView::ProcessCpuValue::
143 cpuTimeMillis,
144 Eq(expected.cpuTimeMillis)),
145 Field("cpuCycles",
146 &UserPackageStats::ProcCpuStatsView::ProcessCpuValue::
147 cpuCycles,
148 Eq(expected.cpuCycles))),
149 arg, result_listener);
150 }
151
152 MATCHER_P(ProcCpuStatsViewEq, expected, "") {
153 std::vector<Matcher<const UserPackageStats::ProcCpuStatsView::ProcessCpuValue&>>
154 processValueMatchers;
155 processValueMatchers.reserve(expected.topNProcesses.size());
156 for (const auto& processValue : expected.topNProcesses) {
157 processValueMatchers.push_back(ProcessCpuValueEq(processValue));
158 }
159 return ExplainMatchResult(AllOf(Field("cpuTimeMillis",
160 &UserPackageStats::ProcCpuStatsView::cpuTimeMillis,
161 Eq(expected.cpuTimeMillis)),
162 Field("cpuCycles",
163 &UserPackageStats::ProcCpuStatsView::cpuCycles,
164 Eq(expected.cpuCycles)),
165 Field("topNProcesses",
166 &UserPackageStats::ProcCpuStatsView::topNProcesses,
167 ElementsAreArray(processValueMatchers))),
168 arg, result_listener);
169 }
170
171 MATCHER_P(MemoryStatsEq, expected, "") {
172 return ExplainMatchResult(AllOf(Field("rssKb", &UserPackageStats::MemoryStats::rssKb,
173 Eq(expected.rssKb)),
174 Field("pssKb", &UserPackageStats::MemoryStats::pssKb,
175 Eq(expected.pssKb)),
176 Field("ussKb", &UserPackageStats::MemoryStats::ussKb,
177 Eq(expected.ussKb)),
178 Field("swapPssKb", &UserPackageStats::MemoryStats::swapPssKb,
179 Eq(expected.swapPssKb))),
180 arg, result_listener);
181 }
182
183 MATCHER_P(ProcessMemoryStatsEq, expected, "") {
184 return ExplainMatchResult(AllOf(Field("comm",
185 &UserPackageStats::UidMemoryStats::ProcessMemoryStats::
186 comm,
187 Eq(expected.comm)),
188 Field("memoryStats",
189 &UserPackageStats::UidMemoryStats::ProcessMemoryStats::
190 memoryStats,
191 MemoryStatsEq(expected.memoryStats))),
192 arg, result_listener);
193 }
194
195 MATCHER_P(UidMemoryStatsEq, expected, "") {
196 std::vector<Matcher<const UserPackageStats::UidMemoryStats::ProcessMemoryStats&>>
197 processValueMatchers;
198 processValueMatchers.reserve(expected.topNProcesses.size());
199 for (const auto& processValue : expected.topNProcesses) {
200 processValueMatchers.push_back(ProcessMemoryStatsEq(processValue));
201 }
202 return ExplainMatchResult(AllOf(Field("memoryStats",
203 &UserPackageStats::UidMemoryStats::memoryStats,
204 MemoryStatsEq(expected.memoryStats)),
205 Field("isSmapsRollupSupported",
206 &UserPackageStats::UidMemoryStats::isSmapsRollupSupported,
207 Eq(expected.isSmapsRollupSupported)),
208 Field("topNProcesses",
209 &UserPackageStats::UidMemoryStats::topNProcesses,
210 ElementsAreArray(processValueMatchers))),
211 arg, result_listener);
212 }
213
214 MATCHER_P(UserPackageStatsEq, expected, "") {
215 const auto uidMatcher = Field("uid", &UserPackageStats::uid, Eq(expected.uid));
216 const auto packageNameMatcher =
217 Field("genericPackageName", &UserPackageStats::genericPackageName,
218 Eq(expected.genericPackageName));
219 return std::visit(
__anon725ac8c50202(const auto& statsView) 220 [&](const auto& statsView) -> bool {
221 using T = std::decay_t<decltype(statsView)>;
222 if constexpr (std::is_same_v<T, UserPackageStats::IoStatsView>) {
223 return ExplainMatchResult(AllOf(uidMatcher, packageNameMatcher,
224 Field("statsView:IoStatsView",
225 &UserPackageStats::statsView,
226 VariantWith<
227 UserPackageStats::IoStatsView>(
228 IoStatsViewEq(statsView)))),
229 arg, result_listener);
230 } else if constexpr (std::is_same_v<T, UserPackageStats::ProcSingleStatsView>) {
231 return ExplainMatchResult(AllOf(uidMatcher, packageNameMatcher,
232 Field("statsView:ProcSingleStatsView",
233 &UserPackageStats::statsView,
234 VariantWith<UserPackageStats::
235 ProcSingleStatsView>(
236 ProcSingleStatsViewEq(
237 statsView)))),
238 arg, result_listener);
239 } else if constexpr (std::is_same_v<T, UserPackageStats::ProcCpuStatsView>) {
240 return ExplainMatchResult(AllOf(uidMatcher, packageNameMatcher,
241 Field("statsView:ProcCpuStatsView",
242 &UserPackageStats::statsView,
243 VariantWith<UserPackageStats::
244 ProcCpuStatsView>(
245 ProcCpuStatsViewEq(statsView)))),
246 arg, result_listener);
247 } else if constexpr (std::is_same_v<T, UserPackageStats::UidMemoryStats>) {
248 return ExplainMatchResult(AllOf(uidMatcher, packageNameMatcher,
249 Field("statsView:UidMemoryStats",
250 &UserPackageStats::statsView,
251 VariantWith<
252 UserPackageStats::UidMemoryStats>(
253 UidMemoryStatsEq(statsView)))),
254 arg, result_listener);
255 }
256 *result_listener << "Unexpected variant in UserPackageStats::stats";
257 return false;
258 },
259 expected.statsView);
260 }
261
262 MATCHER_P(UserPackageSummaryStatsEq, expected, "") {
__anon725ac8c50302(const std::vector<UserPackageStats>& stats) 263 const auto& userPackageStatsMatchers = [&](const std::vector<UserPackageStats>& stats) {
264 std::vector<Matcher<const UserPackageStats&>> matchers;
265 for (const auto& curStats : stats) {
266 matchers.push_back(UserPackageStatsEq(curStats));
267 }
268 return ElementsAreArray(matchers);
269 };
__anon725ac8c50402(const int64_t expected[][UID_STATES]) 270 const auto& totalIoStatsArrayMatcher = [&](const int64_t expected[][UID_STATES]) {
271 std::vector<Matcher<const int64_t[UID_STATES]>> matchers;
272 for (int i = 0; i < METRIC_TYPES; ++i) {
273 matchers.push_back(ElementsAreArray(expected[i], UID_STATES));
274 }
275 return ElementsAreArray(matchers);
276 };
277 return ExplainMatchResult(AllOf(Field("topNCpuTimes", &UserPackageSummaryStats::topNCpuTimes,
278 userPackageStatsMatchers(expected.topNCpuTimes)),
279 Field("topNIoReads", &UserPackageSummaryStats::topNIoReads,
280 userPackageStatsMatchers(expected.topNIoReads)),
281 Field("topNIoWrites", &UserPackageSummaryStats::topNIoWrites,
282 userPackageStatsMatchers(expected.topNIoWrites)),
283 Field("topNIoBlocked", &UserPackageSummaryStats::topNIoBlocked,
284 userPackageStatsMatchers(expected.topNIoBlocked)),
285 Field("topNMajorFaults",
286 &UserPackageSummaryStats::topNMajorFaults,
287 userPackageStatsMatchers(expected.topNMajorFaults)),
288 Field("topNMemStats", &UserPackageSummaryStats::topNMemStats,
289 userPackageStatsMatchers(expected.topNMemStats)),
290 Field("totalIoStats", &UserPackageSummaryStats::totalIoStats,
291 totalIoStatsArrayMatcher(expected.totalIoStats)),
292 Field("taskCountByUid",
293 &UserPackageSummaryStats::taskCountByUid,
294 IsSubsetOf(expected.taskCountByUid)),
295 Field("totalCpuTimeMillis",
296 &UserPackageSummaryStats::totalCpuTimeMillis,
297 Eq(expected.totalCpuTimeMillis)),
298 Field("totalCpuCycles",
299 &UserPackageSummaryStats::totalCpuCycles,
300 Eq(expected.totalCpuCycles)),
301 Field("totalMajorFaults",
302 &UserPackageSummaryStats::totalMajorFaults,
303 Eq(expected.totalMajorFaults)),
304 Field("totalRssKb", &UserPackageSummaryStats::totalRssKb,
305 Eq(expected.totalRssKb)),
306 Field("totalPssKb", &UserPackageSummaryStats::totalPssKb,
307 Eq(expected.totalPssKb)),
308 Field("majorFaultsPercentChange",
309 &UserPackageSummaryStats::majorFaultsPercentChange,
310 Eq(expected.majorFaultsPercentChange))),
311 arg, result_listener);
312 }
313
314 MATCHER_P(SystemSummaryStatsEq, expected, "") {
315 return ExplainMatchResult(AllOf(Field("cpuIoWaitTimeMillis",
316 &SystemSummaryStats::cpuIoWaitTimeMillis,
317 Eq(expected.cpuIoWaitTimeMillis)),
318 Field("cpuIdleTimeMillis",
319 &SystemSummaryStats::cpuIdleTimeMillis,
320 Eq(expected.cpuIdleTimeMillis)),
321 Field("totalCpuTimeMillis",
322 &SystemSummaryStats::totalCpuTimeMillis,
323 Eq(expected.totalCpuTimeMillis)),
324 Field("totalCpuCycles", &SystemSummaryStats::totalCpuCycles,
325 Eq(expected.totalCpuCycles)),
326 Field("contextSwitchesCount",
327 &SystemSummaryStats::contextSwitchesCount,
328 Eq(expected.contextSwitchesCount)),
329 Field("ioBlockedProcessCount",
330 &SystemSummaryStats::ioBlockedProcessCount,
331 Eq(expected.ioBlockedProcessCount)),
332 Field("totalProcessCount",
333 &SystemSummaryStats::totalProcessCount,
334 Eq(expected.totalProcessCount))),
335 arg, result_listener);
336 }
337
338 MATCHER_P(PerfStatsRecordEq, expected, "") {
339 return ExplainMatchResult(AllOf(Field(&PerfStatsRecord::collectionTimeMillis,
340 Eq(expected.collectionTimeMillis)),
341 Field(&PerfStatsRecord::systemSummaryStats,
342 SystemSummaryStatsEq(expected.systemSummaryStats)),
343 Field(&PerfStatsRecord::userPackageSummaryStats,
344 UserPackageSummaryStatsEq(
345 expected.userPackageSummaryStats)),
346 Field(&PerfStatsRecord::memoryPressureLevelDurations,
347 UnorderedElementsAreArray(
348 expected.memoryPressureLevelDurations))),
349 arg, result_listener);
350 }
351
constructPerfStatsRecordMatchers(const std::vector<PerfStatsRecord> & records)352 const std::vector<Matcher<const PerfStatsRecord&>> constructPerfStatsRecordMatchers(
353 const std::vector<PerfStatsRecord>& records) {
354 std::vector<Matcher<const PerfStatsRecord&>> matchers;
355 for (const auto& record : records) {
356 matchers.push_back(PerfStatsRecordEq(record));
357 }
358 return matchers;
359 }
360
361 MATCHER_P(CollectionInfoEq, expected, "") {
362 return ExplainMatchResult(AllOf(Field("maxCacheSize", &CollectionInfo::maxCacheSize,
363 Eq(expected.maxCacheSize)),
364 Field("records", &CollectionInfo::records,
365 ElementsAreArray(constructPerfStatsRecordMatchers(
366 expected.records)))),
367 arg, result_listener);
368 }
369
370 MATCHER_P(UserSwitchCollectionInfoEq, expected, "") {
371 return ExplainMatchResult(AllOf(Field("from", &UserSwitchCollectionInfo::from,
372 Eq(expected.from)),
373 Field("to", &UserSwitchCollectionInfo::to, Eq(expected.to)),
374 Field("maxCacheSize", &UserSwitchCollectionInfo::maxCacheSize,
375 Eq(expected.maxCacheSize)),
376 Field("records", &UserSwitchCollectionInfo::records,
377 ElementsAreArray(constructPerfStatsRecordMatchers(
378 expected.records)))),
379 arg, result_listener);
380 }
381
382 MATCHER_P(UserSwitchCollectionsEq, expected, "") {
383 std::vector<Matcher<const UserSwitchCollectionInfo&>> userSwitchCollectionMatchers;
384 for (const auto& curCollection : expected) {
385 userSwitchCollectionMatchers.push_back(UserSwitchCollectionInfoEq(curCollection));
386 }
387 return ExplainMatchResult(ElementsAreArray(userSwitchCollectionMatchers), arg, result_listener);
388 }
389
countOccurrences(std::string str,std::string subStr)390 int countOccurrences(std::string str, std::string subStr) {
391 size_t pos = 0;
392 int occurrences = 0;
393 while ((pos = str.find(subStr, pos)) != std::string::npos) {
394 ++occurrences;
395 pos += subStr.length();
396 }
397 return occurrences;
398 }
399
sampleUidStats(auto int64Multiplier,auto uint64Multiplier,bool isSmapsRollupSupported=true)400 std::tuple<std::vector<UidStats>, UserPackageSummaryStats> sampleUidStats(
401 auto int64Multiplier, auto uint64Multiplier, bool isSmapsRollupSupported = true) {
402 /* The number of returned sample stats are less that the top N stats per category/sub-category.
403 * The top N stats per category/sub-category is set to % during test setup. Thus, the default
404 * testing behavior is # reported stats < top N stats.
405 */
406 std::vector<UidStats>
407 uidStats{{.packageInfo = constructPackageInfo("mount", 1009),
408 .cpuTimeMillis = int64Multiplier(50),
409 .ioStats = {/*fgRdBytes=*/0,
410 /*bgRdBytes=*/int64Multiplier(14'000),
411 /*fgWrBytes=*/0,
412 /*bgWrBytes=*/int64Multiplier(16'000),
413 /*fgFsync=*/0, /*bgFsync=*/int64Multiplier(100)},
414 .procStats = {.cpuTimeMillis = int64Multiplier(50),
415 .cpuCycles = 4000,
416 .totalMajorFaults = uint64Multiplier(11'000),
417 .totalTasksCount = 1,
418 .ioBlockedTasksCount = 1,
419 .totalRssKb = 2010,
420 .totalPssKb = 1635,
421 .processStatsByPid =
422 {{/*pid=*/100,
423 {/*comm=*/"disk I/O", /*startTime=*/234,
424 /*cpuTimeMillis=*/int64Multiplier(50),
425 /*totalCpuCycles=*/4000,
426 /*totalMajorFaults=*/uint64Multiplier(11'000),
427 /*totalTasksCount=*/1,
428 /*ioBlockedTasksCount=*/1,
429 /*cpuCyclesByTid=*/{{100, 4000}},
430 /*rssKb=*/2010, /*pssKb=*/1635,
431 /*ussKb=*/1286, /*swapPssKb=*/600}}}}},
432 {.packageInfo =
433 constructPackageInfo("com.google.android.car.kitchensink", 1002001),
434 .cpuTimeMillis = int64Multiplier(60),
435 .ioStats = {/*fgRdBytes=*/0,
436 /*bgRdBytes=*/int64Multiplier(3'400),
437 /*fgWrBytes=*/0,
438 /*bgWrBytes=*/int64Multiplier(6'700),
439 /*fgFsync=*/0,
440 /*bgFsync=*/int64Multiplier(200)},
441 .procStats = {.cpuTimeMillis = int64Multiplier(50),
442 .cpuCycles = 10'000,
443 .totalMajorFaults = uint64Multiplier(22'445),
444 .totalTasksCount = 5,
445 .ioBlockedTasksCount = 3,
446 .totalRssKb = 2000,
447 .totalPssKb = 1645,
448 .processStatsByPid =
449 {{/*pid=*/1001,
450 {/*comm=*/"CTS", /*startTime=*/789,
451 /*cpuTimeMillis=*/int64Multiplier(30),
452 /*totalCpuCycles=*/5000,
453 /*totalMajorFaults=*/uint64Multiplier(10'100),
454 /*totalTasksCount=*/3,
455 /*ioBlockedTasksCount=*/2,
456 /*cpuCyclesByTid=*/{{1001, 3000}, {1002, 2000}},
457 /*rssKb=*/1000, /*pssKb=*/770,
458 /*ussKb=*/656, /*swapPssKb=*/200}},
459 {/*pid=*/1000,
460 {/*comm=*/"KitchenSinkApp", /*startTime=*/467,
461 /*cpuTimeMillis=*/int64Multiplier(25),
462 /*totalCpuCycles=*/4000,
463 /*totalMajorFaults=*/uint64Multiplier(12'345),
464 /*totalTasksCount=*/2,
465 /*ioBlockedTasksCount=*/1,
466 /*cpuCyclesByTid=*/{{1000, 4000}},
467 /*rssKb=*/1000, /*pssKb=*/875,
468 /*ussKb=*/630, /*swapPssKb=*/400}}}}},
469 {.packageInfo = constructPackageInfo("", 1012345),
470 .cpuTimeMillis = int64Multiplier(100),
471 .ioStats = {/*fgRdBytes=*/int64Multiplier(1'000),
472 /*bgRdBytes=*/int64Multiplier(4'200),
473 /*fgWrBytes=*/int64Multiplier(300),
474 /*bgWrBytes=*/int64Multiplier(5'600),
475 /*fgFsync=*/int64Multiplier(600),
476 /*bgFsync=*/int64Multiplier(300)},
477 .procStats = {.cpuTimeMillis = int64Multiplier(100),
478 .cpuCycles = 50'000,
479 .totalMajorFaults = uint64Multiplier(50'900),
480 .totalTasksCount = 4,
481 .ioBlockedTasksCount = 2,
482 .totalRssKb = 1000,
483 .totalPssKb = 865,
484 .processStatsByPid =
485 {{/*pid=*/2345,
486 {/*comm=*/"MapsApp", /*startTime=*/6789,
487 /*cpuTimeMillis=*/int64Multiplier(100),
488 /*totalCpuCycles=*/50'000,
489 /*totalMajorFaults=*/uint64Multiplier(50'900),
490 /*totalTasksCount=*/4,
491 /*ioBlockedTasksCount=*/2,
492 /*cpuCyclesByTid=*/{{2345, 50'000}},
493 /*rssKb=*/1000, /*pssKb=*/865,
494 /*ussKb=*/656, /*swapPssKb=*/200}}}}},
495 {.packageInfo = constructPackageInfo("com.google.radio", 1015678),
496 .cpuTimeMillis = 0,
497 .ioStats = {/*fgRdBytes=*/0,
498 /*bgRdBytes=*/0,
499 /*fgWrBytes=*/0,
500 /*bgWrBytes=*/0,
501 /*fgFsync=*/0, /*bgFsync=*/0},
502 .procStats = {.cpuTimeMillis = 0,
503 .cpuCycles = 0,
504 .totalMajorFaults = 0,
505 .totalTasksCount = 4,
506 .ioBlockedTasksCount = 0,
507 .processStatsByPid = {
508 {/*pid=*/2345,
509 {/*comm=*/"RadioApp", /*startTime=*/10789,
510 /*cpuTimeMillis=*/0,
511 /*totalCpuCycles=*/0,
512 /*totalMajorFaults=*/0,
513 /*totalTasksCount=*/4,
514 /*ioBlockedTasksCount=*/0,
515 /*cpuCyclesByTid=*/{}}}}}}};
516
517 std::vector<UserPackageStats> topNMemStatsRankedByPss =
518 {{1002001, "com.google.android.car.kitchensink",
519 UserPackageStats::UidMemoryStats{{/*rssKb=*/2000, /*pssKb=*/1645,
520 /*ussKb=*/1286, /*swapPssKb=*/600},
521 isSmapsRollupSupported,
522 {{"KitchenSinkApp",
523 {/*rssKb=*/1000, /*pssKb=*/875,
524 /*ussKb=*/630, /*swapPssKb=*/400}},
525 {"CTS",
526 {/*rssKb=*/1000, /*pssKb=*/770,
527 /*ussKb=*/656, /*swapPssKb=*/200}}}}},
528 {1009, "mount",
529 UserPackageStats::UidMemoryStats{{/*rssKb=*/2010, /*pssKb=*/1635,
530 /*ussKb=*/1286, /*swapPssKb=*/600},
531 isSmapsRollupSupported,
532 {{"disk I/O",
533 {/*rssKb=*/2010, /*pssKb=*/1635,
534 /*ussKb=*/1286, /*swapPssKb=*/600}}}}},
535 {1012345, "1012345",
536 UserPackageStats::UidMemoryStats{{/*rssKb=*/1000, /*pssKb=*/865,
537 /*ussKb=*/656, /*swapPssKb=*/200},
538 isSmapsRollupSupported,
539 {{"MapsApp",
540 {/*rssKb=*/1000, /*pssKb=*/865,
541 /*ussKb=*/656, /*swapPssKb=*/200}}}}}};
542 std::vector<UserPackageStats> topNMemStatsRankedByRss =
543 {{1009, "mount",
544 UserPackageStats::UidMemoryStats{{/*rssKb=*/2010, /*pssKb=*/1635,
545 /*ussKb=*/1286, /*swapPssKb=*/600},
546 isSmapsRollupSupported,
547 {{"disk I/O",
548 {/*rssKb=*/2010, /*pssKb=*/1635,
549 /*ussKb=*/1286, /*swapPssKb=*/600}}}}},
550 {1002001, "com.google.android.car.kitchensink",
551 UserPackageStats::UidMemoryStats{{/*rssKb=*/2000, /*pssKb=*/1645,
552 /*ussKb=*/1286, /*swapPssKb=*/600},
553 isSmapsRollupSupported,
554 {{"KitchenSinkApp",
555 {/*rssKb=*/1000, /*pssKb=*/875,
556 /*ussKb=*/630, /*swapPssKb=*/400}},
557 {"CTS",
558 {/*rssKb=*/1000, /*pssKb=*/770,
559 /*ussKb=*/656, /*swapPssKb=*/200}}}}},
560 {1012345, "1012345",
561 UserPackageStats::UidMemoryStats{{/*rssKb=*/1000, /*pssKb=*/865,
562 /*ussKb=*/656, /*swapPssKb=*/200},
563 isSmapsRollupSupported,
564 {{"MapsApp",
565 {/*rssKb=*/1000, /*pssKb=*/865,
566 /*ussKb=*/656, /*swapPssKb=*/200}}}}}};
567 UserPackageSummaryStats userPackageSummaryStats{
568 .topNCpuTimes = {{1012345, "1012345",
569 UserPackageStats::ProcCpuStatsView{int64Multiplier(100),
570 50'000,
571 {{2345, "MapsApp",
572 int64Multiplier(100), 50'000}}}},
573 {1002001, "com.google.android.car.kitchensink",
574 UserPackageStats::ProcCpuStatsView{int64Multiplier(60),
575 10'000,
576 {{1001, "CTS", int64Multiplier(30),
577 5000},
578 {1000, "KitchenSinkApp",
579 int64Multiplier(25), 4000}}}},
580 {1009, "mount",
581 UserPackageStats::ProcCpuStatsView{int64Multiplier(50),
582 4000,
583 {{100, "disk I/O",
584 int64Multiplier(50), 4000}}}}},
585 .topNIoReads = {{1009, "mount",
586 UserPackageStats::IoStatsView{{0, int64Multiplier(14'000)},
587 {0, int64Multiplier(100)}}},
588 {1012345, "1012345",
589 UserPackageStats::IoStatsView{{int64Multiplier(1'000),
590 int64Multiplier(4'200)},
591 {int64Multiplier(600),
592 int64Multiplier(300)}}},
593 {1002001, "com.google.android.car.kitchensink",
594 UserPackageStats::IoStatsView{{0, int64Multiplier(3'400)},
595 {0, int64Multiplier(200)}}}},
596 .topNIoWrites =
597 {{1009, "mount",
598 UserPackageStats::IoStatsView{{0, int64Multiplier(16'000)},
599 {0, int64Multiplier(100)}}},
600 {1002001, "com.google.android.car.kitchensink",
601 UserPackageStats::IoStatsView{{0, int64Multiplier(6'700)},
602 {0, int64Multiplier(200)}}},
603 {1012345, "1012345",
604 UserPackageStats::IoStatsView{{int64Multiplier(300), int64Multiplier(5'600)},
605 {int64Multiplier(600), int64Multiplier(300)}}}},
606 .topNIoBlocked =
607 {{1002001, "com.google.android.car.kitchensink",
608 UserPackageStats::ProcSingleStatsView{3,
609 {{"CTS", 2}, {"KitchenSinkApp", 1}}}},
610 {1012345, "1012345",
611 UserPackageStats::ProcSingleStatsView{2, {{"MapsApp", 2}}}},
612 {1009, "mount", UserPackageStats::ProcSingleStatsView{1, {{"disk I/O", 1}}}}},
613 .topNMajorFaults =
614 {{1012345, "1012345",
615 UserPackageStats::ProcSingleStatsView{uint64Multiplier(50'900),
616 {{"MapsApp",
617 uint64Multiplier(50'900)}}}},
618 {1002001, "com.google.android.car.kitchensink",
619 UserPackageStats::ProcSingleStatsView{uint64Multiplier(22'445),
620 {{"KitchenSinkApp",
621 uint64Multiplier(12'345)},
622 {"CTS", uint64Multiplier(10'100)}}}},
623 {1009, "mount",
624 UserPackageStats::ProcSingleStatsView{uint64Multiplier(11'000),
625 {{"disk I/O",
626 uint64Multiplier(11'000)}}}}},
627 .topNMemStats =
628 isSmapsRollupSupported ? topNMemStatsRankedByPss : topNMemStatsRankedByRss,
629 .totalIoStats = {{int64Multiplier(1'000), int64Multiplier(21'600)},
630 {int64Multiplier(300), int64Multiplier(28'300)},
631 {int64Multiplier(600), int64Multiplier(600)}},
632 .taskCountByUid = {{1009, 1}, {1002001, 5}, {1012345, 4}},
633 .totalCpuTimeMillis = int64Multiplier(48'376),
634 .totalCpuCycles = 64'000,
635 .totalMajorFaults = uint64Multiplier(84'345),
636 .totalRssKb = 5010,
637 .totalPssKb = 4145,
638 .majorFaultsPercentChange = 0.0,
639 };
640 applyFeatureFilter(&userPackageSummaryStats);
641 return std::make_tuple(uidStats, userPackageSummaryStats);
642 }
643
sampleProcStat(auto int64Multiplier,auto uint64Multiplier,auto uint32Multiplier)644 std::tuple<ProcStatInfo, SystemSummaryStats> sampleProcStat(auto int64Multiplier,
645 auto uint64Multiplier,
646 auto uint32Multiplier) {
647 ProcStatInfo procStatInfo{/*stats=*/{int64Multiplier(2'900), int64Multiplier(7'900),
648 int64Multiplier(4'900), int64Multiplier(8'900),
649 /*ioWaitTimeMillis=*/int64Multiplier(5'900),
650 int64Multiplier(6'966), int64Multiplier(7'980), 0, 0,
651 int64Multiplier(2'930)},
652 /*ctxtSwitches=*/uint64Multiplier(500),
653 /*runnableCnt=*/uint32Multiplier(100),
654 /*ioBlockedCnt=*/uint32Multiplier(57)};
655 SystemSummaryStats systemSummaryStats{/*cpuIoWaitTimeMillis=*/int64Multiplier(5'900),
656 /*cpuIdleTimeMillis=*/int64Multiplier(8'900),
657 /*totalCpuTimeMillis=*/int64Multiplier(48'376),
658 /*totalCpuCycles=*/64'000,
659 /*contextSwitchesCount=*/uint64Multiplier(500),
660 /*ioBlockedProcessCount=*/uint32Multiplier(57),
661 /*totalProcessCount=*/uint32Multiplier(157)};
662 return std::make_tuple(procStatInfo, systemSummaryStats);
663 }
664
samplePressureLevels(int advanceUptimeSec=1)665 std::tuple<PressureLevelTransitions, PressureLevelDurations> samplePressureLevels(
666 int advanceUptimeSec = 1) {
667 PressureLevelTransitions pressureLevelTransitions{
668 PressureLevelDurationPair{PressureMonitor::PRESSURE_LEVEL_NONE, 100 * advanceUptimeSec},
669 PressureLevelDurationPair{PressureMonitor::PRESSURE_LEVEL_HIGH, 200 * advanceUptimeSec},
670 PressureLevelDurationPair{PressureMonitor::PRESSURE_LEVEL_HIGH, 100 * advanceUptimeSec},
671 PressureLevelDurationPair{PressureMonitor::PRESSURE_LEVEL_LOW, 200 * advanceUptimeSec},
672 PressureLevelDurationPair{PressureMonitor::PRESSURE_LEVEL_MEDIUM,
673 100 * advanceUptimeSec},
674 PressureLevelDurationPair{PressureMonitor::PRESSURE_LEVEL_LOW, 200 * advanceUptimeSec},
675 PressureLevelDurationPair{PressureMonitor::PRESSURE_LEVEL_MEDIUM,
676 100 * advanceUptimeSec},
677 };
678 PressureLevelDurations pressureLevelDurations{
679 {PressureMonitor::PRESSURE_LEVEL_NONE, 100ms * advanceUptimeSec},
680 {PressureMonitor::PRESSURE_LEVEL_LOW, 400ms * advanceUptimeSec},
681 {PressureMonitor::PRESSURE_LEVEL_MEDIUM, 200ms * advanceUptimeSec},
682 {PressureMonitor::PRESSURE_LEVEL_HIGH, 300ms * advanceUptimeSec},
683 };
684 return std::make_tuple(pressureLevelTransitions, pressureLevelDurations);
685 }
686
getResourceStatsForSampledStats(auto int32Multiplier,auto int64Multiplier,time_point_millis nowMillis,int64_t elapsedRealtimeSinceBootMillis)687 ResourceStats getResourceStatsForSampledStats(auto int32Multiplier, auto int64Multiplier,
688 time_point_millis nowMillis,
689 int64_t elapsedRealtimeSinceBootMillis) {
690 // clang-format off
691 return {
692 .resourceUsageStats = std::make_optional<ResourceUsageStats>({
693 .startTimeEpochMillis = nowMillis.time_since_epoch().count(),
694 // Set durationInMillis to zero since this field is set by WatchdogPerfService.
695 .durationInMillis = 0,
696 .systemSummaryUsageStats = {
697 .cpuNonIdleCycles = 64'000,
698 .cpuNonIdleTimeMillis = int32Multiplier(39'476),
699 .cpuIdleTimeMillis = int32Multiplier(8'900),
700 .contextSwitchesCount = int32Multiplier(500),
701 .ioBlockedProcessCount = int32Multiplier(57),
702 .totalProcessCount = int32Multiplier(157),
703 .totalMajorPageFaults = int32Multiplier(84'345),
704 .totalIoReads = {
705 .foregroundBytes = int32Multiplier(1'000),
706 .backgroundBytes = int32Multiplier(21'600),
707 .garageModeBytes = 0,
708 },
709 .totalIoWrites = {
710 .foregroundBytes = int32Multiplier(300),
711 .backgroundBytes = int32Multiplier(28'300),
712 .garageModeBytes = 0,
713 },
714 },
715 .uidResourceUsageStats = {
716 {
717 .packageIdentifier = {
718 .name = "mount",
719 .uid = 1009,
720 },
721 .uidUptimeMillis = elapsedRealtimeSinceBootMillis - 234,
722 .cpuUsageStats = {
723 .cpuTimeMillis = int64Multiplier(50),
724 .cpuCycles = 4'000,
725 .cpuTimePercentage = (50. / 48'376.) * 100.0,
726 },
727 .processCpuUsageStats = {
728 {
729 .pid = 100,
730 .name = "disk I/O",
731 .cpuTimeMillis = int64Multiplier(50),
732 .cpuCycles = 4'000,
733 },
734 },
735 .ioUsageStats = {
736 .writtenBytes = {
737 .foregroundBytes = 0,
738 .backgroundBytes = int32Multiplier(16'000),
739 .garageModeBytes = 0,
740 },
741 .readBytes = {
742 .foregroundBytes = 0,
743 .backgroundBytes = int32Multiplier(14'000),
744 .garageModeBytes = 0,
745 },
746 },
747 },
748 {
749 .packageIdentifier = {
750 .name = "com.google.android.car.kitchensink",
751 .uid = 1002001,
752 },
753 .uidUptimeMillis = elapsedRealtimeSinceBootMillis - 467,
754 .cpuUsageStats = {
755 .cpuTimeMillis = int64Multiplier(60),
756 .cpuCycles = 10'000,
757 .cpuTimePercentage = (60. / 48'376.) * 100.0,
758 },
759 .processCpuUsageStats = {
760 {
761 .pid = 1001,
762 .name = "CTS",
763 .cpuTimeMillis = int64Multiplier(30),
764 .cpuCycles = 5'000,
765 },
766 {
767 .pid = 1000,
768 .name = "KitchenSinkApp",
769 .cpuTimeMillis = int64Multiplier(25),
770 .cpuCycles = 4'000,
771 },
772 },
773 .ioUsageStats = {
774 .writtenBytes = {
775 .foregroundBytes = 0,
776 .backgroundBytes = int32Multiplier(6'700),
777 .garageModeBytes = 0,
778 },
779 .readBytes = {
780 .foregroundBytes = 0,
781 .backgroundBytes = int32Multiplier(3'400),
782 .garageModeBytes = 0,
783 },
784 },
785 },
786 {
787 .packageIdentifier = {
788 .name = "1012345",
789 .uid = 1012345,
790 },
791 .uidUptimeMillis = elapsedRealtimeSinceBootMillis - 6789,
792 .cpuUsageStats = {
793 .cpuTimeMillis = int64Multiplier(100),
794 .cpuCycles = 50'000,
795 .cpuTimePercentage = (100. / 48'376.) * 100.0,
796 },
797 .processCpuUsageStats = {
798 {
799 .pid = 2345,
800 .name = "MapsApp",
801 .cpuTimeMillis = int64Multiplier(100),
802 .cpuCycles = 50'000,
803 },
804 },
805 .ioUsageStats = {
806 .writtenBytes = {
807 .foregroundBytes = int32Multiplier(300),
808 .backgroundBytes = int32Multiplier(5'600),
809 .garageModeBytes = 0,
810 },
811 .readBytes = {
812 .foregroundBytes = int32Multiplier(1'000),
813 .backgroundBytes = int32Multiplier(4'200),
814 .garageModeBytes = 0,
815 },
816 },
817 },
818 {
819 .packageIdentifier = {
820 .name = "com.google.radio",
821 .uid = 1015678,
822 },
823 .uidUptimeMillis = elapsedRealtimeSinceBootMillis - 10789,
824 .cpuUsageStats = {
825 .cpuTimeMillis = 0,
826 .cpuCycles = 0,
827 .cpuTimePercentage = 0,
828 },
829 .ioUsageStats = {
830 .writtenBytes = {
831 .foregroundBytes = 0,
832 .backgroundBytes = 0,
833 .garageModeBytes = 0,
834 },
835 .readBytes = {
836 .foregroundBytes = 0,
837 .backgroundBytes = 0,
838 .garageModeBytes = 0,
839 },
840 },
841 },
842 },
843 }),
844 };
845 // clang-format on
846 }
847
848 struct StatsInfo {
849 std::vector<UidStats> uidStats = {};
850 UserPackageSummaryStats userPackageSummaryStats = {};
851 ProcStatInfo procStatInfo = {};
852 SystemSummaryStats systemSummaryStats = {};
853 ResourceStats resourceStats = {};
854 };
855
856 MATCHER_P(UserPackageInfoProtoEq, expected, "") {
857 return ExplainMatchResult(AllOf(Property("user_id", &UserPackageInfo::user_id,
858 static_cast<int>(multiuser_get_user_id(expected.uid))),
859 Property("package_name", &UserPackageInfo::package_name,
860 expected.genericPackageName)),
861 arg, result_listener);
862 }
863
864 MATCHER_P(CpuStatsProtoEq, expected, "") {
865 return ExplainMatchResult(AllOf(Property("cpu_time_millis",
866 &PackageCpuStats_CpuStats::cpu_time_millis,
867 expected.cpuTimeMillis),
868 Property("cpu_cycles", &PackageCpuStats_CpuStats::cpu_cycles,
869 expected.cpuCycles)),
870 arg, result_listener);
871 }
872
873 MATCHER_P(ProcessCpuStatsProtoEq, expected, "") {
874 return ExplainMatchResult(AllOf(Property("command", &PackageCpuStats_ProcessCpuStats::command,
875 expected.comm),
876 Property("cpu_stats",
877 &PackageCpuStats_ProcessCpuStats::cpu_stats,
878 CpuStatsProtoEq(expected))),
879 arg, result_listener);
880 }
881
882 MATCHER_P(PackageCpuStatsProtoEq, expected, "") {
883 const auto& procCpuStatsView =
884 std::get_if<UserPackageStats::ProcCpuStatsView>(&expected.statsView);
885 std::vector<Matcher<const PackageCpuStats_ProcessCpuStats&>> processCpuStatsMatchers;
886 for (const auto& expectedProcessCpuValue : procCpuStatsView->topNProcesses) {
887 processCpuStatsMatchers.push_back(ProcessCpuStatsProtoEq(expectedProcessCpuValue));
888 }
889 return ExplainMatchResult(AllOf(Property("user_package_info",
890 &PackageCpuStats::user_package_info,
891 UserPackageInfoProtoEq(expected)),
892 Property("cpu_stats", &PackageCpuStats::cpu_stats,
893 CpuStatsProtoEq(*procCpuStatsView)),
894 Property("process_cpu_stats",
895 &PackageCpuStats::process_cpu_stats,
896 ElementsAreArray(processCpuStatsMatchers))),
897 arg, result_listener);
898 }
899
900 MATCHER_P4(StorageIoStatsProtoEq, fgBytes, fgFsync, bgBytes, byFsync, "") {
901 return ExplainMatchResult(AllOf(Property("fg_bytes", &StorageIoStats::fg_bytes, fgBytes),
902 Property("fg_fsync", &StorageIoStats::fg_fsync, fgFsync),
903 Property("bg_bytes", &StorageIoStats::bg_bytes, bgBytes),
904 Property("bg_fsync", &StorageIoStats::bg_fsync, byFsync)),
905 arg, result_listener);
906 }
907
908 MATCHER_P(PackageStorageIoStatsProtoEq, expected, "") {
909 const auto& ioStatsView = std::get_if<UserPackageStats::IoStatsView>(&expected.statsView);
910 return ExplainMatchResult(AllOf(Property("user_package_info",
911 &PackageStorageIoStats::user_package_info,
912 UserPackageInfoProtoEq(expected)),
913 Property("storage_io_stats",
914 &PackageStorageIoStats::storage_io_stats,
915 StorageIoStatsProtoEq(ioStatsView->bytes[FOREGROUND],
916 ioStatsView->fsync[FOREGROUND],
917 ioStatsView->bytes[BACKGROUND],
918 ioStatsView
919 ->fsync[BACKGROUND]))),
920 arg, result_listener);
921 }
922
923 MATCHER_P(ProcessTaskStateStatsProtoEq, expected, "") {
924 return ExplainMatchResult(AllOf(Property("command",
925 &PackageTaskStateStats_ProcessTaskStateStats::command,
926 expected.comm),
927 Property("io_blocked_task_count",
928 &PackageTaskStateStats_ProcessTaskStateStats::
929 io_blocked_task_count,
930 expected.value)),
931 arg, result_listener);
932 }
933
934 MATCHER_P2(PackageTaskStateStatsProtoEq, expected, taskCountByUid, "") {
935 const auto& procSingleStatsView =
936 std::get_if<UserPackageStats::ProcSingleStatsView>(&expected.statsView);
937 std::vector<Matcher<const PackageTaskStateStats_ProcessTaskStateStats&>>
938 processTaskStateStatsMatchers;
939 for (const auto& expectedProcessValue : procSingleStatsView->topNProcesses) {
940 processTaskStateStatsMatchers.push_back(ProcessTaskStateStatsProtoEq(expectedProcessValue));
941 }
942 return ExplainMatchResult(AllOf(Property("user_package_info",
943 &PackageTaskStateStats::user_package_info,
944 UserPackageInfoProtoEq(expected)),
945 Property("io_blocked_task_count",
946 &PackageTaskStateStats::io_blocked_task_count,
947 procSingleStatsView->value),
948 Property("total_task_count",
949 &PackageTaskStateStats::total_task_count,
950 taskCountByUid.at(expected.uid)),
951 Property("process_task_state_stats",
952 &PackageTaskStateStats::process_task_state_stats,
953 ElementsAreArray(processTaskStateStatsMatchers))),
954 arg, result_listener);
955 }
956
957 MATCHER_P(PackageMajorPageFaultsProtoEq, expected, "") {
958 const auto& procSingleStatsView =
959 std::get_if<UserPackageStats::ProcSingleStatsView>(&expected.statsView);
960 return ExplainMatchResult(AllOf(Property("user_package_info",
961 &PackageMajorPageFaults::user_package_info,
962 UserPackageInfoProtoEq(expected)),
963 Property("major_page_faults_count",
964 &PackageMajorPageFaults::major_page_faults_count,
965 procSingleStatsView->value)),
966 arg, result_listener);
967 }
968
969 MATCHER_P(DateProtoEq, expected, "") {
970 return ExplainMatchResult(AllOf(Property("year", &Date::year, expected.tm_year + 1900),
971 Property("month", &Date::month, expected.tm_mon),
972 Property("day", &Date::day, expected.tm_mday)),
973 arg, result_listener);
974 }
975
976 MATCHER_P2(TimeOfDayProtoEq, expected, nowTimeMs, "") {
977 return ExplainMatchResult(AllOf(Property("hours", &TimeOfDay::hours, expected.tm_hour),
978 Property("minutes", &TimeOfDay::minutes, expected.tm_min),
979 Property("seconds", &TimeOfDay::seconds, expected.tm_sec),
980 Property("millis", &TimeOfDay::millis, nowTimeMs.count())),
981 arg, result_listener);
982 }
983
984 MATCHER_P2(SystemWideStatsProtoEq, userPackageSummaryStats, systemSummaryStats, "") {
985 return ExplainMatchResult(AllOf(Property("io_wait_time_millis",
986 &SystemWideStats::io_wait_time_millis,
987 systemSummaryStats.cpuIoWaitTimeMillis),
988 Property("idle_cpu_time_millis",
989 &SystemWideStats::idle_cpu_time_millis,
990 systemSummaryStats.cpuIdleTimeMillis),
991 Property("total_cpu_time_millis",
992 &SystemWideStats::total_cpu_time_millis,
993 systemSummaryStats.totalCpuTimeMillis),
994 Property("total_cpu_cycles", &SystemWideStats::total_cpu_cycles,
995 systemSummaryStats.totalCpuCycles),
996 Property("total_context_switches",
997 &SystemWideStats::total_context_switches,
998 systemSummaryStats.contextSwitchesCount),
999 Property("total_io_blocked_processes",
1000 &SystemWideStats::total_io_blocked_processes,
1001 systemSummaryStats.ioBlockedProcessCount),
1002 Property("total_major_page_faults",
1003 &SystemWideStats::total_major_page_faults,
1004 userPackageSummaryStats.totalMajorFaults),
1005 Property("total_storage_io_stats",
1006 &SystemWideStats::total_storage_io_stats,
1007 StorageIoStatsProtoEq(userPackageSummaryStats
1008 .totalIoStats
1009 [WRITE_BYTES]
1010 [FOREGROUND],
1011 userPackageSummaryStats
1012 .totalIoStats
1013 [FSYNC_COUNT]
1014 [FOREGROUND],
1015 userPackageSummaryStats
1016 .totalIoStats
1017 [WRITE_BYTES]
1018 [BACKGROUND],
1019 userPackageSummaryStats
1020 .totalIoStats
1021 [FSYNC_COUNT]
1022 [BACKGROUND]))),
1023 arg, result_listener);
1024 }
1025
1026 MATCHER_P3(StatsRecordProtoEq, userPackageSummaryStats, systemSummaryStats, nowMs, "") {
1027 struct tm timeinfo;
1028 memset(&timeinfo, 0, sizeof(timeinfo));
1029 auto dateTime = std::chrono::system_clock::to_time_t(nowMs);
1030 auto nowTimeMs = std::chrono::duration_cast<std::chrono::milliseconds>(
1031 nowMs - std::chrono::system_clock::from_time_t(dateTime));
1032 localtime_r(&dateTime, &timeinfo);
1033
1034 std::vector<Matcher<const PackageCpuStats&>> packageCpuStatsMatchers;
1035 for (const auto& expectedProcCpuStatsView : userPackageSummaryStats.topNCpuTimes) {
1036 packageCpuStatsMatchers.push_back(PackageCpuStatsProtoEq(expectedProcCpuStatsView));
1037 }
1038 std::vector<Matcher<const PackageStorageIoStats&>> packageStorageReadIoStatsMatchers;
1039 for (const auto& expectedPackageStorageReadIoStat : userPackageSummaryStats.topNIoReads) {
1040 packageStorageReadIoStatsMatchers.push_back(
1041 PackageStorageIoStatsProtoEq(expectedPackageStorageReadIoStat));
1042 }
1043 std::vector<Matcher<const PackageStorageIoStats&>> packageStorageWriteIoStatsMatchers;
1044 for (const auto& expectedPackageStorageWriteIoStat : userPackageSummaryStats.topNIoWrites) {
1045 packageStorageWriteIoStatsMatchers.push_back(
1046 PackageStorageIoStatsProtoEq(expectedPackageStorageWriteIoStat));
1047 }
1048 std::vector<Matcher<const PackageTaskStateStats&>> packageTaskStateStatsMatchers;
1049 for (const auto& expectedPackageTaskStateStat : userPackageSummaryStats.topNIoBlocked) {
1050 packageTaskStateStatsMatchers.push_back(
1051 PackageTaskStateStatsProtoEq(expectedPackageTaskStateStat,
1052 userPackageSummaryStats.taskCountByUid));
1053 }
1054 std::vector<Matcher<const PackageMajorPageFaults&>> packageMajorPageFaultsMatchers;
1055 for (const auto& expectedPackageMajorPageFault : userPackageSummaryStats.topNMajorFaults) {
1056 packageMajorPageFaultsMatchers.push_back(
1057 PackageMajorPageFaultsProtoEq(expectedPackageMajorPageFault));
1058 }
1059 return ExplainMatchResult(AllOf(Property("date", &StatsRecord::date, DateProtoEq(timeinfo)),
1060 Property("time", &StatsRecord::time,
1061 TimeOfDayProtoEq(timeinfo, nowTimeMs)),
1062 Property("system_wide_stats", &StatsRecord::system_wide_stats,
1063 SystemWideStatsProtoEq(userPackageSummaryStats,
1064 systemSummaryStats)),
1065 Property("package_cpu_stats", &StatsRecord::package_cpu_stats,
1066 ElementsAreArray(packageCpuStatsMatchers)),
1067 Property("package_storage_io_read_stats",
1068 &StatsRecord::package_storage_io_read_stats,
1069 ElementsAreArray(packageStorageReadIoStatsMatchers)),
1070 Property("package_storage_io_read_stats",
1071 &StatsRecord::package_storage_io_write_stats,
1072 ElementsAreArray(packageStorageWriteIoStatsMatchers)),
1073 Property("package_task_state_stats",
1074 &StatsRecord::package_task_state_stats,
1075 ElementsAreArray(packageTaskStateStatsMatchers)),
1076 Property("package_major_page_faults",
1077 &StatsRecord::package_major_page_faults,
1078 ElementsAreArray(packageMajorPageFaultsMatchers))),
1079 arg, result_listener);
1080 }
1081
toString(util::ProtoOutputStream * proto)1082 std::string toString(util::ProtoOutputStream* proto) {
1083 std::string content;
1084 content.reserve(proto->size());
1085 sp<ProtoReader> reader = proto->data();
1086 while (reader->hasNext()) {
1087 content.push_back(reader->next());
1088 }
1089 return content;
1090 }
1091
toString(const std::vector<UserSwitchCollectionInfo> & infos)1092 std::string toString(const std::vector<UserSwitchCollectionInfo>& infos) {
1093 std::string buffer;
1094 StringAppendF(&buffer, "{");
1095 for (const auto& info : infos) {
1096 StringAppendF(&buffer, "%s\n", info.toString().c_str());
1097 }
1098 StringAppendF(&buffer, "}");
1099 return buffer;
1100 }
1101
1102 } // namespace
1103
1104 namespace internal {
1105
1106 // TODO(b/289396065): Refactor class such that variable fields are initialized directly in the
1107 // constructor and remove the setter methods.
1108 class PerformanceProfilerPeer final : public RefBase {
1109 public:
PerformanceProfilerPeer(sp<PerformanceProfiler> collector)1110 explicit PerformanceProfilerPeer(sp<PerformanceProfiler> collector) : mCollector(collector) {}
1111
1112 PerformanceProfilerPeer() = delete;
~PerformanceProfilerPeer()1113 ~PerformanceProfilerPeer() {
1114 mCollector->terminate();
1115 mCollector.clear();
1116 }
1117
init()1118 Result<void> init() { return mCollector->init(); }
1119
setTopNStatsPerCategory(int value)1120 void setTopNStatsPerCategory(int value) { mCollector->mTopNStatsPerCategory = value; }
1121
setTopNStatsPerSubcategory(int value)1122 void setTopNStatsPerSubcategory(int value) { mCollector->mTopNStatsPerSubcategory = value; }
1123
setMaxUserSwitchEvents(int value)1124 void setMaxUserSwitchEvents(int value) { mCollector->mMaxUserSwitchEvents = value; }
1125
setSystemEventDataCacheDuration(std::chrono::seconds value)1126 void setSystemEventDataCacheDuration(std::chrono::seconds value) {
1127 mCollector->mSystemEventDataCacheDurationSec = value;
1128 }
1129
setPeriodicCollectionBufferSize(size_t bufferSize)1130 void setPeriodicCollectionBufferSize(size_t bufferSize) {
1131 mCollector->mPeriodicCollection.maxCacheSize = bufferSize;
1132 }
1133
setSendResourceUsageStatsEnabled(bool enable)1134 void setSendResourceUsageStatsEnabled(bool enable) {
1135 mCollector->mDoSendResourceUsageStats = enable;
1136 }
1137
setSmapsRollupSupportedEnabled(bool enable)1138 void setSmapsRollupSupportedEnabled(bool enable) {
1139 mCollector->mIsSmapsRollupSupported = enable;
1140 }
1141
getBoottimeCollectionInfo()1142 const CollectionInfo& getBoottimeCollectionInfo() {
1143 Mutex::Autolock lock(mCollector->mMutex);
1144 return mCollector->mBoottimeCollection;
1145 }
1146
getPeriodicCollectionInfo()1147 const CollectionInfo& getPeriodicCollectionInfo() {
1148 Mutex::Autolock lock(mCollector->mMutex);
1149 return mCollector->mPeriodicCollection;
1150 }
1151
getUserSwitchCollectionInfos()1152 const std::vector<UserSwitchCollectionInfo>& getUserSwitchCollectionInfos() {
1153 Mutex::Autolock lock(mCollector->mMutex);
1154 return mCollector->mUserSwitchCollections;
1155 }
1156
getWakeUpCollectionInfo()1157 const CollectionInfo& getWakeUpCollectionInfo() {
1158 Mutex::Autolock lock(mCollector->mMutex);
1159 return mCollector->mWakeUpCollection;
1160 }
1161
getCustomCollectionInfo()1162 const CollectionInfo& getCustomCollectionInfo() {
1163 Mutex::Autolock lock(mCollector->mMutex);
1164 return mCollector->mCustomCollection;
1165 }
1166
1167 private:
1168 sp<PerformanceProfiler> mCollector;
1169 };
1170
1171 } // namespace internal
1172
1173 class PerformanceProfilerTest : public Test {
1174 protected:
SetUp()1175 void SetUp() override {
1176 mPeriodicCollectionBufferSize =
1177 static_cast<size_t>(sysprop::periodicCollectionBufferSize().value_or(
1178 kDefaultPeriodicCollectionBufferSize));
1179 mElapsedRealtimeSinceBootMillis = kTestElapsedRealtimeSinceBootMillis;
1180 mNowMillis = kTestNowMillis;
1181 mMockUidStatsCollector = sp<MockUidStatsCollector>::make();
1182 mMockPressureMonitor = sp<MockPressureMonitor>::make();
1183 mMockProcStatCollector = sp<MockProcStatCollector>::make();
1184 mCollector = sp<PerformanceProfiler>::
1185 make(mMockPressureMonitor,
1186 std::bind(&PerformanceProfilerTest::getTestElapsedRealtimeSinceBootMs, this));
1187 mCollectorPeer = sp<internal::PerformanceProfilerPeer>::make(mCollector);
1188
1189 EXPECT_CALL(*mMockPressureMonitor, registerPressureChangeCallback(Eq(mCollector)))
1190 .Times(car_watchdog_memory_profiling() ? 1 : 0);
1191
1192 ASSERT_RESULT_OK(mCollectorPeer->init());
1193
1194 mCollectorPeer->setTopNStatsPerCategory(kTestTopNStatsPerCategory);
1195 mCollectorPeer->setTopNStatsPerSubcategory(kTestTopNStatsPerSubcategory);
1196 mCollectorPeer->setMaxUserSwitchEvents(kTestMaxUserSwitchEvents);
1197 mCollectorPeer->setSystemEventDataCacheDuration(kTestSystemEventDataCacheDurationSec);
1198 mCollectorPeer->setSendResourceUsageStatsEnabled(true);
1199 mCollectorPeer->setSmapsRollupSupportedEnabled(true);
1200 mCollectorPeer->setPeriodicCollectionBufferSize(kTestPeriodicCollectionBufferSize);
1201 }
1202
TearDown()1203 void TearDown() override {
1204 mMockUidStatsCollector.clear();
1205 mMockProcStatCollector.clear();
1206
1207 EXPECT_CALL(*mMockPressureMonitor, unregisterPressureChangeCallback(Eq(mCollector)))
1208 .Times(car_watchdog_memory_profiling() ? 1 : 0);
1209
1210 mCollector.clear();
1211 mCollectorPeer.clear();
1212 }
1213
getTestElapsedRealtimeSinceBootMs()1214 int64_t getTestElapsedRealtimeSinceBootMs() { return mElapsedRealtimeSinceBootMillis; }
1215
1216 protected:
checkDumpContents(int wantedEmptyCollectionInstances)1217 void checkDumpContents(int wantedEmptyCollectionInstances) {
1218 TemporaryFile dump;
1219 ASSERT_RESULT_OK(mCollector->onDump(dump.fd));
1220
1221 checkDumpFd(wantedEmptyCollectionInstances, dump.fd);
1222 }
1223
checkCustomDumpContents()1224 void checkCustomDumpContents() {
1225 TemporaryFile dump;
1226 ASSERT_RESULT_OK(mCollector->onCustomCollectionDump(dump.fd));
1227
1228 checkDumpFd(/*wantedEmptyCollectionInstances=*/0, dump.fd);
1229 }
1230
injectPressureLevelTransitions(int advanceUptimeSec)1231 PressureLevelDurations injectPressureLevelTransitions(int advanceUptimeSec) {
1232 if (!car_watchdog_memory_profiling()) {
1233 mElapsedRealtimeSinceBootMillis += advanceUptimeSec * 1000;
1234 return PressureLevelDurations{};
1235 }
1236 auto [pressureLevelTransitions, pressureLevelDurations] =
1237 samplePressureLevels(advanceUptimeSec);
1238 for (const auto transition : pressureLevelTransitions) {
1239 mElapsedRealtimeSinceBootMillis += transition.second;
1240 mCollector->onPressureChanged(transition.first);
1241 }
1242 return pressureLevelDurations;
1243 }
1244
1245 // Direct use of this method in tests is not recommended because further setup (such as calling
1246 // injectPressureLevelTransitions, constructing CollectionInfo struct, advancing time, and
1247 // setting up EXPECT_CALL) is required before testing a collection. Please consider using one of
1248 // the PerformanceProfilerTest::setup* methods instead. If none of them work for a new use case,
1249 // either update the existing PerformanceProfilerTest::setup* methods or add a new
1250 // PerformanceProfilerTest::setup* method.
getSampleStatsInfo(int multiplier=1,bool isSmapsRollupSupported=kTestIsSmapsRollupSupported)1251 StatsInfo getSampleStatsInfo(int multiplier = 1,
1252 bool isSmapsRollupSupported = kTestIsSmapsRollupSupported) {
1253 const auto int64Multiplier = [&](int64_t bytes) -> int64_t {
1254 return static_cast<int64_t>(bytes * multiplier);
1255 };
1256 const auto uint64Multiplier = [&](uint64_t count) -> uint64_t {
1257 return static_cast<uint64_t>(count * multiplier);
1258 };
1259 const auto int32Multiplier = [&](int32_t bytes) -> int32_t {
1260 return static_cast<int32_t>(bytes * multiplier);
1261 };
1262 const auto uint32Multiplier = [&](uint32_t bytes) -> uint32_t {
1263 return static_cast<uint32_t>(bytes * multiplier);
1264 };
1265
1266 auto [uidStats, userPackageSummaryStats] =
1267 sampleUidStats(int64Multiplier, uint64Multiplier, isSmapsRollupSupported);
1268
1269 applyFeatureFilter(&userPackageSummaryStats);
1270
1271 auto [procStatInfo, systemSummaryStats] =
1272 sampleProcStat(int64Multiplier, uint64Multiplier, uint32Multiplier);
1273
1274 ResourceStats resourceStats =
1275 getResourceStatsForSampledStats(int32Multiplier, int64Multiplier, mNowMillis,
1276 mElapsedRealtimeSinceBootMillis);
1277
1278 StatsInfo statsInfo(uidStats, userPackageSummaryStats, procStatInfo, systemSummaryStats,
1279 resourceStats);
1280 return statsInfo;
1281 }
1282
advanceTime(int durationMillis)1283 void advanceTime(int durationMillis) {
1284 mNowMillis += std::chrono::milliseconds(durationMillis);
1285 }
1286
setupFirstCollection(size_t maxCollectionCacheSize=std::numeric_limits<std::size_t>::max (),bool isSmapsRollupSupported=kTestIsSmapsRollupSupported)1287 std::tuple<CollectionInfo, ResourceStats> setupFirstCollection(
1288 size_t maxCollectionCacheSize = std::numeric_limits<std::size_t>::max(),
1289 bool isSmapsRollupSupported = kTestIsSmapsRollupSupported) {
1290 // Trigger pressure level transitions to test the pressure level accounting done by the
1291 // implementation.
1292 auto pressureLevelDurations = injectPressureLevelTransitions(/*advanceUptimeSec=*/1);
1293 auto statsInfo = getSampleStatsInfo(/*multiplier=*/1, isSmapsRollupSupported);
1294
1295 EXPECT_CALL(*mMockUidStatsCollector, deltaStats()).WillOnce(Return(statsInfo.uidStats));
1296 EXPECT_CALL(*mMockProcStatCollector, deltaStats()).WillOnce(Return(statsInfo.procStatInfo));
1297
1298 auto expectedCollectionInfo =
1299 CollectionInfo{.maxCacheSize = maxCollectionCacheSize,
1300 .records = {{
1301 .collectionTimeMillis = mNowMillis,
1302 .systemSummaryStats = statsInfo.systemSummaryStats,
1303 .userPackageSummaryStats = statsInfo.userPackageSummaryStats,
1304 .memoryPressureLevelDurations = pressureLevelDurations,
1305 }}};
1306 auto expectedResourceStats = statsInfo.resourceStats;
1307 return std::make_tuple(expectedCollectionInfo, expectedResourceStats);
1308 }
1309
setupNextCollection(CollectionInfo * prevCollectionInfo,ResourceStats * outResourceStats,int multiplier=1)1310 void setupNextCollection(CollectionInfo* prevCollectionInfo, ResourceStats* outResourceStats,
1311 int multiplier = 1) {
1312 advanceTime(/*durationMillis=*/1000);
1313 // Trigger pressure level transitions to test the pressure level accounting done by the
1314 // implementation.
1315 auto pressureLevelDurations = injectPressureLevelTransitions(/*advanceUptimeSec=*/1);
1316 auto statsInfo = getSampleStatsInfo(multiplier, kTestIsSmapsRollupSupported);
1317
1318 EXPECT_CALL(*mMockUidStatsCollector, deltaStats()).WillOnce(Return(statsInfo.uidStats));
1319 EXPECT_CALL(*mMockProcStatCollector, deltaStats()).WillOnce(Return(statsInfo.procStatInfo));
1320
1321 auto& prevRecord = prevCollectionInfo->records.back();
1322 statsInfo.userPackageSummaryStats.majorFaultsPercentChange =
1323 (static_cast<double>(statsInfo.userPackageSummaryStats.totalMajorFaults -
1324 prevRecord.userPackageSummaryStats.totalMajorFaults) /
1325 static_cast<double>(prevRecord.userPackageSummaryStats.totalMajorFaults)) *
1326 100.0;
1327
1328 prevCollectionInfo->records.push_back(PerfStatsRecord{
1329 .collectionTimeMillis = mNowMillis,
1330 .systemSummaryStats = statsInfo.systemSummaryStats,
1331 .userPackageSummaryStats = statsInfo.userPackageSummaryStats,
1332 .memoryPressureLevelDurations = pressureLevelDurations,
1333 });
1334 *outResourceStats = statsInfo.resourceStats;
1335 }
1336
setupUserSwitchCollection(userid_t fromUserId,userid_t toUserId)1337 UserSwitchCollectionInfo setupUserSwitchCollection(userid_t fromUserId, userid_t toUserId) {
1338 auto [collectionInfo, _] = setupFirstCollection();
1339 return UserSwitchCollectionInfo{
1340 collectionInfo,
1341 .from = fromUserId,
1342 .to = toUserId,
1343 };
1344 }
1345
1346 // Use this method only in tests where the returned CollectionInfo / UserSwitchCollectionInfo
1347 // is not verified.
setupMultipleCollections()1348 void setupMultipleCollections() {
1349 auto statsInfo = getSampleStatsInfo();
1350
1351 EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
1352 .WillRepeatedly(Return(statsInfo.uidStats));
1353 EXPECT_CALL(*mMockProcStatCollector, deltaStats())
1354 .WillRepeatedly(Return(statsInfo.procStatInfo));
1355 }
1356
getNowMillis()1357 time_point_millis getNowMillis() { return mNowMillis; }
1358
1359 private:
checkDumpFd(int wantedEmptyCollectionInstances,int fd)1360 void checkDumpFd(int wantedEmptyCollectionInstances, int fd) {
1361 lseek(fd, 0, SEEK_SET);
1362 std::string dumpContents;
1363 ASSERT_TRUE(ReadFdToString(fd, &dumpContents));
1364 ASSERT_FALSE(dumpContents.empty());
1365
1366 ASSERT_EQ(countOccurrences(dumpContents, kEmptyCollectionMessage),
1367 wantedEmptyCollectionInstances)
1368 << "Dump contents: " << dumpContents;
1369 }
1370
1371 protected:
1372 size_t mPeriodicCollectionBufferSize;
1373 sp<MockUidStatsCollector> mMockUidStatsCollector;
1374 sp<MockPressureMonitor> mMockPressureMonitor;
1375 sp<MockProcStatCollector> mMockProcStatCollector;
1376 sp<PerformanceProfiler> mCollector;
1377 sp<internal::PerformanceProfilerPeer> mCollectorPeer;
1378
1379 private:
1380 int64_t mElapsedRealtimeSinceBootMillis;
1381 time_point_millis mNowMillis;
1382 };
1383
TEST_F(PerformanceProfilerTest,TestOnBoottimeCollection)1384 TEST_F(PerformanceProfilerTest, TestOnBoottimeCollection) {
1385 auto [expectedCollectionInfo, expectedResourceStats] = setupFirstCollection();
1386
1387 ResourceStats actualResourceStats = {};
1388 ASSERT_RESULT_OK(mCollector->onBoottimeCollection(getNowMillis(), mMockUidStatsCollector,
1389 mMockProcStatCollector,
1390 &actualResourceStats));
1391
1392 const auto actualCollectionInfo = mCollectorPeer->getBoottimeCollectionInfo();
1393
1394 EXPECT_THAT(actualCollectionInfo, CollectionInfoEq(expectedCollectionInfo))
1395 << "Boottime collection info doesn't match.\nExpected:\n"
1396 << expectedCollectionInfo.toString() << "\nActual:\n"
1397 << actualCollectionInfo.toString();
1398
1399 ASSERT_EQ(actualResourceStats, expectedResourceStats)
1400 << "Expected: " << expectedResourceStats.toString()
1401 << "\nActual: " << actualResourceStats.toString();
1402
1403 ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
1404 << "Periodic, wake-up and user-switch collections shouldn't be reported";
1405 }
1406
TEST_F(PerformanceProfilerTest,TestOnWakeUpCollection)1407 TEST_F(PerformanceProfilerTest, TestOnWakeUpCollection) {
1408 auto [expectedCollectionInfo, expectedResourceStats] = setupFirstCollection();
1409
1410 ASSERT_RESULT_OK(mCollector->onWakeUpCollection(getNowMillis(), mMockUidStatsCollector,
1411 mMockProcStatCollector));
1412
1413 const auto actualCollectionInfo = mCollectorPeer->getWakeUpCollectionInfo();
1414
1415 EXPECT_THAT(actualCollectionInfo, CollectionInfoEq(expectedCollectionInfo))
1416 << "Wake-up collection info doesn't match.\nExpected:\n"
1417 << expectedCollectionInfo.toString() << "\nActual:\n"
1418 << actualCollectionInfo.toString();
1419
1420 ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
1421 << "Boot-time, periodic, and user-switch collections shouldn't be reported";
1422 }
1423
TEST_F(PerformanceProfilerTest,TestOnSystemStartup)1424 TEST_F(PerformanceProfilerTest, TestOnSystemStartup) {
1425 setupMultipleCollections();
1426
1427 ResourceStats resourceStats = {};
1428 ASSERT_RESULT_OK(mCollector->onBoottimeCollection(getNowMillis(), mMockUidStatsCollector,
1429 mMockProcStatCollector, &resourceStats));
1430 ASSERT_RESULT_OK(mCollector->onWakeUpCollection(getNowMillis(), mMockUidStatsCollector,
1431 mMockProcStatCollector));
1432
1433 auto actualBoottimeCollection = mCollectorPeer->getBoottimeCollectionInfo();
1434 auto actualWakeUpCollection = mCollectorPeer->getWakeUpCollectionInfo();
1435
1436 EXPECT_THAT(actualBoottimeCollection.records.size(), 1)
1437 << "Boot-time collection records is empty.";
1438 EXPECT_THAT(actualWakeUpCollection.records.size(), 1) << "Wake-up collection records is empty.";
1439
1440 ASSERT_RESULT_OK(mCollector->onSystemStartup());
1441
1442 actualBoottimeCollection = mCollectorPeer->getBoottimeCollectionInfo();
1443 actualWakeUpCollection = mCollectorPeer->getWakeUpCollectionInfo();
1444
1445 EXPECT_THAT(actualBoottimeCollection.records.size(), 0)
1446 << "Boot-time collection records is not empty.";
1447 EXPECT_THAT(actualWakeUpCollection.records.size(), 0)
1448 << "Wake-up collection records is not empty.";
1449 }
1450
TEST_F(PerformanceProfilerTest,TestOnUserSwitchCollection)1451 TEST_F(PerformanceProfilerTest, TestOnUserSwitchCollection) {
1452 std::vector<UserSwitchCollectionInfo> expected;
1453 expected.push_back(setupUserSwitchCollection(kTestBaseUserId, kTestBaseUserId + 1));
1454
1455 ASSERT_RESULT_OK(mCollector->onUserSwitchCollection(getNowMillis(), kTestBaseUserId,
1456 kTestBaseUserId + 1, mMockUidStatsCollector,
1457 mMockProcStatCollector));
1458
1459 auto actual = mCollectorPeer->getUserSwitchCollectionInfos();
1460
1461 EXPECT_THAT(actual, UserSwitchCollectionsEq(expected))
1462 << "User switch collection infos doesn't match.\nExpected:\n"
1463 << toString(expected) << "\nActual:\n"
1464 << toString(actual);
1465
1466 // Continuation of the previous user switch collection
1467 std::vector<UidStats> nextUidStats = {
1468 {.packageInfo = constructPackageInfo("mount", 1009),
1469 .cpuTimeMillis = 0, // No TopNCpuTimes will be registered
1470 .ioStats = {/*fgRdBytes=*/0,
1471 /*bgRdBytes=*/5'000,
1472 /*fgWrBytes=*/0,
1473 /*bgWrBytes=*/3'000,
1474 /*fgFsync=*/0, /*bgFsync=*/50},
1475 .procStats = {.cpuTimeMillis = 50,
1476 .cpuCycles = 3'500,
1477 .totalMajorFaults = 6'000,
1478 .totalTasksCount = 1,
1479 .ioBlockedTasksCount = 2,
1480 .processStatsByPid = {{/*pid=*/100,
1481 {/*comm=*/"disk I/O", /*startTime=*/234,
1482 /*cpuTimeMillis=*/50,
1483 /*totalCpuCycle=*/3'500,
1484 /*totalMajorFaults=*/6'000,
1485 /*totalTasksCount=*/1,
1486 /*ioBlockedTasksCount=*/2,
1487 /*cpuCyclesByTid=*/{{100, 3'500}}}}}}}};
1488
1489 UserPackageSummaryStats nextUserPackageSummaryStats = {
1490 .topNIoReads = {{1009, "mount", UserPackageStats::IoStatsView{{0, 5'000}, {0, 50}}}},
1491 .topNIoWrites = {{1009, "mount", UserPackageStats::IoStatsView{{0, 3'000}, {0, 50}}}},
1492 .topNIoBlocked = {{1009, "mount",
1493 UserPackageStats::ProcSingleStatsView{2, {{"disk I/O", 2}}}}},
1494 .topNMajorFaults = {{1009, "mount",
1495 UserPackageStats::ProcSingleStatsView{6'000,
1496 {{"disk I/O", 6'000}}}}},
1497 .totalIoStats = {{0, 5'000}, {0, 3'000}, {0, 50}},
1498 .taskCountByUid = {{1009, 1}},
1499 .totalCpuTimeMillis = 48'376,
1500 .totalCpuCycles = 3'500,
1501 .totalMajorFaults = 6'000,
1502 .majorFaultsPercentChange = (6'000.0 - 84'345.0) / 84'345.0 * 100.0,
1503 };
1504
1505 // TODO(b/336835345): Revisit this test and update the below logic to use setupNextCollection
1506 // instead.
1507 auto nextPressureLevelDurations = injectPressureLevelTransitions(/*advanceUptimeSec=*/2);
1508 advanceTime(/*durationMillis=*/2000);
1509
1510 const auto statsInfo = getSampleStatsInfo();
1511 ProcStatInfo nextProcStatInfo = statsInfo.procStatInfo;
1512 SystemSummaryStats nextSystemSummaryStats = statsInfo.systemSummaryStats;
1513
1514 nextProcStatInfo.contextSwitchesCount = 300;
1515 nextSystemSummaryStats.totalCpuCycles = 3'500;
1516 nextSystemSummaryStats.contextSwitchesCount = 300;
1517
1518 EXPECT_CALL(*mMockUidStatsCollector, deltaStats()).WillOnce(Return(nextUidStats));
1519 EXPECT_CALL(*mMockProcStatCollector, deltaStats()).WillOnce(Return(nextProcStatInfo));
1520
1521 ASSERT_RESULT_OK(mCollector->onUserSwitchCollection(getNowMillis(), kTestBaseUserId,
1522 kTestBaseUserId + 1, mMockUidStatsCollector,
1523 mMockProcStatCollector));
1524
1525 actual = mCollectorPeer->getUserSwitchCollectionInfos();
1526
1527 expected[0].records.push_back(
1528 PerfStatsRecord{.collectionTimeMillis = getNowMillis(),
1529 .systemSummaryStats = nextSystemSummaryStats,
1530 .userPackageSummaryStats = nextUserPackageSummaryStats,
1531 .memoryPressureLevelDurations = nextPressureLevelDurations});
1532
1533 EXPECT_THAT(actual, UserSwitchCollectionsEq(expected))
1534 << "User switch collection info after continuation doesn't match.\nExpected:\n"
1535 << toString(expected) << "\nActual:\n"
1536 << toString(actual);
1537
1538 ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
1539 << "Boot-time, wake-up and periodic collections shouldn't be reported";
1540 }
1541
TEST_F(PerformanceProfilerTest,TestUserSwitchCollectionsMaxCacheSize)1542 TEST_F(PerformanceProfilerTest, TestUserSwitchCollectionsMaxCacheSize) {
1543 std::vector<UserSwitchCollectionInfo> expected;
1544 userid_t userIdToTriggerEviction = kTestBaseUserId + kTestMaxUserSwitchEvents;
1545
1546 for (userid_t userId = kTestBaseUserId; userId < userIdToTriggerEviction; ++userId) {
1547 expected.push_back(setupUserSwitchCollection(userId, userId + 1));
1548 ASSERT_RESULT_OK(mCollector->onUserSwitchCollection(getNowMillis(), userId, userId + 1,
1549 mMockUidStatsCollector,
1550 mMockProcStatCollector));
1551 }
1552
1553 auto actual = mCollectorPeer->getUserSwitchCollectionInfos();
1554
1555 EXPECT_THAT(actual.size(), kTestMaxUserSwitchEvents);
1556
1557 EXPECT_THAT(actual, UserSwitchCollectionsEq(expected))
1558 << "User switch collection infos don't match before crossing limit.\nExpected:\n"
1559 << toString(expected) << "\nActual:\n"
1560 << toString(actual);
1561
1562 // Add new user switch event with max cache size. The oldest user switch event should be dropped
1563 // and the new one added to the cache.
1564 expected.push_back(
1565 setupUserSwitchCollection(userIdToTriggerEviction, userIdToTriggerEviction + 1));
1566 expected.erase(expected.begin());
1567
1568 ASSERT_RESULT_OK(mCollector->onUserSwitchCollection(getNowMillis(), userIdToTriggerEviction,
1569 userIdToTriggerEviction + 1,
1570 mMockUidStatsCollector,
1571 mMockProcStatCollector));
1572
1573 actual = mCollectorPeer->getUserSwitchCollectionInfos();
1574
1575 EXPECT_THAT(actual.size(), kTestMaxUserSwitchEvents);
1576
1577 EXPECT_THAT(actual, UserSwitchCollectionsEq(expected))
1578 << "User switch collection infos don't match after crossing limit.\nExpected:\n"
1579 << toString(expected) << "\nActual:\n"
1580 << toString(actual);
1581 }
1582
TEST_F(PerformanceProfilerTest,TestOnPeriodicCollection)1583 TEST_F(PerformanceProfilerTest, TestOnPeriodicCollection) {
1584 const auto [expectedCollectionInfo, expectedResourceStats] =
1585 setupFirstCollection(kTestPeriodicCollectionBufferSize);
1586
1587 ResourceStats actualResourceStats = {};
1588 ASSERT_RESULT_OK(mCollector->onPeriodicCollection(getNowMillis(), SystemState::NORMAL_MODE,
1589 mMockUidStatsCollector,
1590 mMockProcStatCollector,
1591 &actualResourceStats));
1592
1593 const auto actualCollectionInfo = mCollectorPeer->getPeriodicCollectionInfo();
1594
1595 EXPECT_THAT(actualCollectionInfo, CollectionInfoEq(expectedCollectionInfo))
1596 << "Periodic collection info doesn't match.\nExpected:\n"
1597 << expectedCollectionInfo.toString() << "\nActual:\n"
1598 << actualCollectionInfo.toString();
1599
1600 ASSERT_EQ(actualResourceStats, expectedResourceStats)
1601 << "Expected: " << expectedResourceStats.toString()
1602 << "\nActual: " << actualResourceStats.toString();
1603
1604 ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
1605 << "Boot-time, wake-up and user-switch collections shouldn't be reported";
1606 }
1607
TEST_F(PerformanceProfilerTest,TestOnPeriodicCollectionWithSendingUsageStatsDisabled)1608 TEST_F(PerformanceProfilerTest, TestOnPeriodicCollectionWithSendingUsageStatsDisabled) {
1609 mCollectorPeer->setSendResourceUsageStatsEnabled(false);
1610
1611 auto [expectedCollectionInfo, _] = setupFirstCollection(kTestPeriodicCollectionBufferSize);
1612
1613 ResourceStats actualResourceStats = {};
1614 ASSERT_RESULT_OK(mCollector->onPeriodicCollection(getNowMillis(), SystemState::NORMAL_MODE,
1615 mMockUidStatsCollector,
1616 mMockProcStatCollector,
1617 &actualResourceStats));
1618
1619 const auto actualCollectionInfo = mCollectorPeer->getPeriodicCollectionInfo();
1620 const ResourceStats expectedResourceStats = {};
1621
1622 EXPECT_THAT(actualCollectionInfo, CollectionInfoEq(expectedCollectionInfo))
1623 << "Periodic collection info doesn't match.\nExpected:\n"
1624 << expectedCollectionInfo.toString() << "\nActual:\n"
1625 << actualCollectionInfo.toString();
1626
1627 ASSERT_EQ(actualResourceStats, expectedResourceStats)
1628 << "Expected: " << expectedResourceStats.toString()
1629 << "\nActual: " << actualResourceStats.toString();
1630
1631 ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
1632 << "Boot-time, wake-up and user-switch collections shouldn't be reported";
1633 }
1634
TEST_F(PerformanceProfilerTest,TestOnCustomCollectionWithoutPackageFilter)1635 TEST_F(PerformanceProfilerTest, TestOnCustomCollectionWithoutPackageFilter) {
1636 auto [expectedCollectionInfo, expectedResourceStats] = setupFirstCollection();
1637
1638 ResourceStats actualResourceStats = {};
1639 ASSERT_RESULT_OK(mCollector->onCustomCollection(getNowMillis(), SystemState::NORMAL_MODE, {},
1640 mMockUidStatsCollector, mMockProcStatCollector,
1641 &actualResourceStats));
1642
1643 const auto actualCollectionInfo = mCollectorPeer->getCustomCollectionInfo();
1644
1645 EXPECT_THAT(actualCollectionInfo, CollectionInfoEq(expectedCollectionInfo))
1646 << "Custom collection info doesn't match.\nExpected:\n"
1647 << expectedCollectionInfo.toString() << "\nActual:\n"
1648 << actualCollectionInfo.toString();
1649
1650 ASSERT_EQ(actualResourceStats, expectedResourceStats)
1651 << "Expected: " << expectedResourceStats.toString()
1652 << "\nActual: " << actualResourceStats.toString();
1653
1654 ASSERT_NO_FATAL_FAILURE(checkCustomDumpContents()) << "Custom collection should be reported";
1655
1656 TemporaryFile customDump;
1657 ASSERT_RESULT_OK(mCollector->onCustomCollectionDump(customDump.fd));
1658
1659 // Should clear the cache.
1660 ASSERT_RESULT_OK(mCollector->onCustomCollectionDump(-1));
1661
1662 expectedCollectionInfo.records.clear();
1663 const CollectionInfo& emptyCollectionInfo = mCollectorPeer->getCustomCollectionInfo();
1664 EXPECT_THAT(emptyCollectionInfo, CollectionInfoEq(expectedCollectionInfo))
1665 << "Custom collection should be cleared.";
1666 }
1667
TEST_F(PerformanceProfilerTest,TestOnCustomCollectionWithPackageFilter)1668 TEST_F(PerformanceProfilerTest, TestOnCustomCollectionWithPackageFilter) {
1669 // Filter by package name should ignore this limit with package filter.
1670 mCollectorPeer->setTopNStatsPerCategory(1);
1671
1672 auto [expectedCollectionInfo, expectedResourceStats] = setupFirstCollection();
1673
1674 ResourceStats actualResourceStats = {};
1675 ASSERT_RESULT_OK(mCollector->onCustomCollection(getNowMillis(), SystemState::NORMAL_MODE,
1676 {"mount", "com.google.android.car.kitchensink"},
1677 mMockUidStatsCollector, mMockProcStatCollector,
1678 &actualResourceStats));
1679 const auto actualCollectionInfo = mCollectorPeer->getCustomCollectionInfo();
1680
1681 UserPackageSummaryStats userPackageSummaryStats{
1682 .topNCpuTimes = {{1009, "mount",
1683 UserPackageStats::ProcCpuStatsView{50,
1684 4'000,
1685 {{100, "disk I/O", 50, 4'000}}}},
1686 {1002001, "com.google.android.car.kitchensink",
1687 UserPackageStats::ProcCpuStatsView{60,
1688 10'000,
1689 {{1001, "CTS", 30, 5'000},
1690 {1000, "KitchenSinkApp", 25,
1691 4'000}}}}},
1692 .topNIoReads = {{1009, "mount", UserPackageStats::IoStatsView{{0, 14'000}, {0, 100}}},
1693 {1002001, "com.google.android.car.kitchensink",
1694 UserPackageStats::IoStatsView{{0, 3'400}, {0, 200}}}},
1695 .topNIoWrites = {{1009, "mount", UserPackageStats::IoStatsView{{0, 16'000}, {0, 100}}},
1696 {1002001, "com.google.android.car.kitchensink",
1697 UserPackageStats::IoStatsView{{0, 6'700}, {0, 200}}}},
1698 .topNIoBlocked =
1699 {{1009, "mount", UserPackageStats::ProcSingleStatsView{1, {{"disk I/O", 1}}}},
1700 {1002001, "com.google.android.car.kitchensink",
1701 UserPackageStats::ProcSingleStatsView{3,
1702 {{"CTS", 2}, {"KitchenSinkApp", 1}}}}},
1703 .topNMajorFaults = {{1009, "mount",
1704 UserPackageStats::ProcSingleStatsView{11'000,
1705 {{"disk I/O", 11'000}}}},
1706 {1002001, "com.google.android.car.kitchensink",
1707 UserPackageStats::ProcSingleStatsView{22'445,
1708 {{"KitchenSinkApp", 12'345},
1709 {"CTS", 10'100}}}}},
1710 .topNMemStats =
1711 {{1009, "mount",
1712 UserPackageStats::UidMemoryStats{{/*rssKb=*/2010, /*pssKb=*/1635,
1713 /*ussKb=*/1286, /*swapPssKb=*/600},
1714 kTestIsSmapsRollupSupported,
1715 {{"disk I/O",
1716 {/*rssKb=*/2010, /*pssKb=*/1635,
1717 /*ussKb=*/1286, /*swapPssKb=*/600}}}}},
1718 {1002001, "com.google.android.car.kitchensink",
1719 UserPackageStats::UidMemoryStats{{/*rssKb=*/2000, /*pssKb=*/1645,
1720 /*ussKb=*/1286, /*swapPssKb=*/600},
1721 kTestIsSmapsRollupSupported,
1722 {{"KitchenSinkApp",
1723 {/*rssKb=*/1000, /*pssKb=*/875,
1724 /*ussKb=*/630, /*swapPssKb=*/400}},
1725 {"CTS",
1726 {/*rssKb=*/1000, /*pssKb=*/770,
1727 /*ussKb=*/656, /*swapPssKb=*/200}}}}}},
1728 .totalIoStats = {{1000, 21'600}, {300, 28'300}, {600, 600}},
1729 .taskCountByUid = {{1009, 1}, {1002001, 5}},
1730 .totalCpuTimeMillis = 48'376,
1731 .totalCpuCycles = 64'000,
1732 .totalMajorFaults = 84'345,
1733 .totalRssKb = 5010,
1734 .totalPssKb = 4145,
1735 .majorFaultsPercentChange = 0.0,
1736 };
1737 applyFeatureFilter(&userPackageSummaryStats);
1738 expectedCollectionInfo.records[0].userPackageSummaryStats = userPackageSummaryStats;
1739
1740 EXPECT_THAT(actualCollectionInfo, CollectionInfoEq(expectedCollectionInfo))
1741 << "Custom collection info doesn't match.\nExpected:\n"
1742 << expectedCollectionInfo.toString() << "\nActual:\n"
1743 << actualCollectionInfo.toString();
1744
1745 ASSERT_EQ(actualResourceStats, expectedResourceStats)
1746 << "Expected: " << expectedResourceStats.toString()
1747 << "\nActual: " << actualResourceStats.toString();
1748
1749 ASSERT_NO_FATAL_FAILURE(checkCustomDumpContents()) << "Custom collection should be reported";
1750
1751 TemporaryFile customDump;
1752 ASSERT_RESULT_OK(mCollector->onCustomCollectionDump(customDump.fd));
1753
1754 // Should clear the cache.
1755 ASSERT_RESULT_OK(mCollector->onCustomCollectionDump(-1));
1756
1757 expectedCollectionInfo.records.clear();
1758 const CollectionInfo& emptyCollectionInfo = mCollectorPeer->getCustomCollectionInfo();
1759 EXPECT_THAT(emptyCollectionInfo, CollectionInfoEq(expectedCollectionInfo))
1760 << "Custom collection should be cleared.";
1761 }
1762
TEST_F(PerformanceProfilerTest,TestOnPeriodicCollectionWithTrimmingStatsAfterTopN)1763 TEST_F(PerformanceProfilerTest, TestOnPeriodicCollectionWithTrimmingStatsAfterTopN) {
1764 mCollectorPeer->setTopNStatsPerCategory(1);
1765 mCollectorPeer->setTopNStatsPerSubcategory(1);
1766
1767 auto [expectedCollectionInfo, expectedResourceStats] =
1768 setupFirstCollection(kTestPeriodicCollectionBufferSize);
1769
1770 // Top N stats per category/sub-category is set to 1, so remove entries in the
1771 // expected value to match this.
1772 ASSERT_FALSE(expectedResourceStats.resourceUsageStats->uidResourceUsageStats.empty());
1773 UidResourceUsageStats& kitchenSinkStats =
1774 expectedResourceStats.resourceUsageStats->uidResourceUsageStats.at(1);
1775 ASSERT_FALSE(kitchenSinkStats.processCpuUsageStats.empty());
1776 kitchenSinkStats.processCpuUsageStats.pop_back();
1777
1778 ResourceStats actualResourceStats = {};
1779 ASSERT_RESULT_OK(mCollector->onPeriodicCollection(getNowMillis(), SystemState::NORMAL_MODE,
1780 mMockUidStatsCollector,
1781 mMockProcStatCollector,
1782 &actualResourceStats));
1783
1784 const auto actualCollectionInfo = mCollectorPeer->getPeriodicCollectionInfo();
1785
1786 UserPackageSummaryStats userPackageSummaryStats{
1787 .topNCpuTimes = {{1012345, "1012345",
1788 UserPackageStats::ProcCpuStatsView{100,
1789 50'000,
1790 {{2345, "MapsApp", 100,
1791 50'000}}}}},
1792 .topNIoReads = {{1009, "mount", UserPackageStats::IoStatsView{{0, 14'000}, {0, 100}}}},
1793 .topNIoWrites = {{1009, "mount", UserPackageStats::IoStatsView{{0, 16'000}, {0, 100}}}},
1794 .topNIoBlocked = {{1002001, "com.google.android.car.kitchensink",
1795 UserPackageStats::ProcSingleStatsView{3, {{"CTS", 2}}}}},
1796 .topNMajorFaults = {{1012345, "1012345",
1797 UserPackageStats::ProcSingleStatsView{50'900,
1798 {{"MapsApp", 50'900}}}}},
1799 .topNMemStats = {{1002001, "com.google.android.car.kitchensink",
1800 UserPackageStats::UidMemoryStats{{/*rssKb=*/2000, /*pssKb=*/1645,
1801 /*ussKb=*/1286, /*swapPssKb=*/600},
1802 kTestIsSmapsRollupSupported,
1803 {{"KitchenSinkApp",
1804 {/*rssKb=*/1000, /*pssKb=*/875,
1805 /*ussKb=*/630,
1806 /*swapPssKb=*/400}}}}}},
1807 .totalIoStats = {{1000, 21'600}, {300, 28'300}, {600, 600}},
1808 .taskCountByUid = {{1009, 1}, {1002001, 5}, {1012345, 4}},
1809 .totalCpuTimeMillis = 48'376,
1810 .totalCpuCycles = 64'000,
1811 .totalMajorFaults = 84'345,
1812 .totalRssKb = 5010,
1813 .totalPssKb = 4145,
1814 .majorFaultsPercentChange = 0.0,
1815 };
1816 applyFeatureFilter(&userPackageSummaryStats);
1817 expectedCollectionInfo.records[0].userPackageSummaryStats = userPackageSummaryStats;
1818
1819 EXPECT_THAT(actualCollectionInfo, CollectionInfoEq(expectedCollectionInfo))
1820 << "Periodic collection info doesn't match.\nExpected:\n"
1821 << expectedCollectionInfo.toString() << "\nActual:\n"
1822 << actualCollectionInfo.toString();
1823
1824 ASSERT_EQ(actualResourceStats, expectedResourceStats)
1825 << "Expected: " << expectedResourceStats.toString()
1826 << "\nActual: " << actualResourceStats.toString();
1827
1828 ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
1829 << "Boot-time, wake-up and user-switch collections shouldn't be reported";
1830 }
1831
TEST_F(PerformanceProfilerTest,TestConsecutiveOnPeriodicCollection)1832 TEST_F(PerformanceProfilerTest, TestConsecutiveOnPeriodicCollection) {
1833 auto [expectedCollectionInfo, expectedResourceStats] =
1834 setupFirstCollection(kTestPeriodicCollectionBufferSize);
1835
1836 ResourceStats actualResourceStats = {};
1837 ASSERT_RESULT_OK(mCollector->onPeriodicCollection(getNowMillis(), SystemState::NORMAL_MODE,
1838 mMockUidStatsCollector,
1839 mMockProcStatCollector,
1840 &actualResourceStats));
1841
1842 for (size_t i = 1; i < kTestPeriodicCollectionBufferSize; i++) {
1843 setupNextCollection(&expectedCollectionInfo, &expectedResourceStats, /*multiplier=*/2);
1844
1845 ASSERT_RESULT_OK(mCollector->onPeriodicCollection(getNowMillis(), SystemState::NORMAL_MODE,
1846 mMockUidStatsCollector,
1847 mMockProcStatCollector,
1848 &actualResourceStats));
1849
1850 ASSERT_EQ(actualResourceStats, expectedResourceStats)
1851 << "Resource stats don't match for collection " << i
1852 << "\nExpected: " << expectedResourceStats.toString()
1853 << "\nActual: " << actualResourceStats.toString();
1854 }
1855
1856 auto actualCollectionInfo = mCollectorPeer->getPeriodicCollectionInfo();
1857
1858 EXPECT_THAT(actualCollectionInfo, CollectionInfoEq(expectedCollectionInfo))
1859 << "Periodic collection info doesn't match.\nExpected:\n"
1860 << expectedCollectionInfo.toString() << "\nActual:\n"
1861 << actualCollectionInfo.toString();
1862
1863 // Collection beyond kTestPeriodicCollectionBufferSize should evict the first collection data.
1864 setupNextCollection(&expectedCollectionInfo, &expectedResourceStats, /*multiplier=*/2);
1865 ASSERT_RESULT_OK(mCollector->onPeriodicCollection(getNowMillis(), SystemState::NORMAL_MODE,
1866 mMockUidStatsCollector,
1867 mMockProcStatCollector,
1868 &actualResourceStats));
1869
1870 expectedCollectionInfo.records.erase(expectedCollectionInfo.records.begin());
1871 actualCollectionInfo = mCollectorPeer->getPeriodicCollectionInfo();
1872
1873 EXPECT_THAT(actualCollectionInfo, CollectionInfoEq(expectedCollectionInfo))
1874 << "Periodic collection info doesn't match after exceeding cache limit.\nExpected:\n"
1875 << expectedCollectionInfo.toString() << "\nActual:\n"
1876 << actualCollectionInfo.toString();
1877
1878 ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
1879 << "Boot-time, wake-up and user-switch collection shouldn't be reported";
1880 }
1881
TEST_F(PerformanceProfilerTest,TestBoottimeCollectionCacheEvictionAfterTimeout)1882 TEST_F(PerformanceProfilerTest, TestBoottimeCollectionCacheEvictionAfterTimeout) {
1883 setupMultipleCollections();
1884
1885 ResourceStats actualResourceStats = {};
1886 ASSERT_RESULT_OK(mCollector->onBoottimeCollection(getNowMillis(), mMockUidStatsCollector,
1887 mMockProcStatCollector,
1888 &actualResourceStats));
1889
1890 auto actualCollectionInfo = mCollectorPeer->getBoottimeCollectionInfo();
1891
1892 EXPECT_THAT(actualCollectionInfo.records.size(), 1)
1893 << "Boot-time collection info missing after collection";
1894
1895 advanceTime(/*durationMillis=*/kTestSystemEventDataCacheDurationSec.count() * 1000);
1896
1897 // Call |onPeriodicCollection| 1 hour past the last boot-time collection event.
1898 ASSERT_RESULT_OK(mCollector->onPeriodicCollection(getNowMillis(), SystemState::NORMAL_MODE,
1899 mMockUidStatsCollector,
1900 mMockProcStatCollector,
1901 &actualResourceStats));
1902
1903 actualCollectionInfo = mCollectorPeer->getBoottimeCollectionInfo();
1904
1905 EXPECT_THAT(actualCollectionInfo.records.empty(), true)
1906 << "Boot-time collection info records are not empty after cache eviction period";
1907 }
1908
TEST_F(PerformanceProfilerTest,TestWakeUpCollectionCacheEvictionAfterTimeout)1909 TEST_F(PerformanceProfilerTest, TestWakeUpCollectionCacheEvictionAfterTimeout) {
1910 setupMultipleCollections();
1911
1912 ASSERT_RESULT_OK(mCollector->onWakeUpCollection(getNowMillis(), mMockUidStatsCollector,
1913 mMockProcStatCollector));
1914
1915 auto actualCollectionInfo = mCollectorPeer->getWakeUpCollectionInfo();
1916
1917 EXPECT_THAT(actualCollectionInfo.records.size(), 1)
1918 << "Wake-up collection info missing after collection";
1919
1920 advanceTime(/*durationMillis=*/kTestSystemEventDataCacheDurationSec.count() * 1000);
1921 ResourceStats actualResourceStats = {};
1922
1923 // Call |onPeriodicCollection| 1 hour past the last wake-up collection event.
1924 ASSERT_RESULT_OK(mCollector->onPeriodicCollection(getNowMillis(), SystemState::NORMAL_MODE,
1925 mMockUidStatsCollector,
1926 mMockProcStatCollector,
1927 &actualResourceStats));
1928
1929 actualCollectionInfo = mCollectorPeer->getWakeUpCollectionInfo();
1930
1931 EXPECT_THAT(actualCollectionInfo.records.empty(), true)
1932 << "Wake-up collection info records are not empty after cache eviction period";
1933 }
1934
TEST_F(PerformanceProfilerTest,TestUserSwitchCollectionCacheEvictionAfterTimeout)1935 TEST_F(PerformanceProfilerTest, TestUserSwitchCollectionCacheEvictionAfterTimeout) {
1936 userid_t userIdToTriggerEviction = kTestBaseUserId + kTestMaxUserSwitchEvents;
1937 for (userid_t userId = kTestBaseUserId; userId < userIdToTriggerEviction; ++userId) {
1938 ASSERT_RESULT_OK(mCollector->onUserSwitchCollection(getNowMillis(), userId, userId + 1,
1939 mMockUidStatsCollector,
1940 mMockProcStatCollector));
1941 advanceTime(/*advanceUptimeMillis=*/kTestSystemEventDataCacheDurationSec.count() * 1000);
1942 }
1943
1944 const auto& actual = mCollectorPeer->getUserSwitchCollectionInfos();
1945
1946 EXPECT_THAT(actual.size(), kTestMaxUserSwitchEvents);
1947
1948 ResourceStats resourceStats = {};
1949 for (int i = 1; i <= kTestMaxUserSwitchEvents; ++i) {
1950 ASSERT_RESULT_OK(mCollector->onPeriodicCollection(getNowMillis(), SystemState::NORMAL_MODE,
1951 mMockUidStatsCollector,
1952 mMockProcStatCollector, &resourceStats));
1953
1954 const auto& actual = mCollectorPeer->getUserSwitchCollectionInfos();
1955
1956 EXPECT_THAT(actual.size(), kTestMaxUserSwitchEvents - i)
1957 << "Expired user switch collection infos are still retained after " << i
1958 << "iterations";
1959
1960 advanceTime(/*durationMillis=*/kTestSystemEventDataCacheDurationSec.count() * 1000);
1961 }
1962 }
1963
TEST_F(PerformanceProfilerTest,TestOnDumpProto)1964 TEST_F(PerformanceProfilerTest, TestOnDumpProto) {
1965 auto statsInfo = getSampleStatsInfo();
1966
1967 EXPECT_CALL(*mMockUidStatsCollector, deltaStats()).WillRepeatedly(Return(statsInfo.uidStats));
1968 EXPECT_CALL(*mMockProcStatCollector, deltaStats())
1969 .WillRepeatedly(Return(statsInfo.procStatInfo));
1970
1971 DataProcessorInterface::CollectionIntervals collectionIntervals =
1972 {.mBoottimeIntervalMillis = std::chrono::milliseconds(1),
1973 .mPeriodicIntervalMillis = std::chrono::milliseconds(10),
1974 .mUserSwitchIntervalMillis = std::chrono::milliseconds(100),
1975 .mWakeUpIntervalMillis = std::chrono::milliseconds(1000),
1976 .mCustomIntervalMillis = std::chrono::milliseconds(10000)};
1977
1978 ResourceStats actualResourceStats = {};
1979
1980 ASSERT_RESULT_OK(mCollector->onPeriodicCollection(getNowMillis(), SystemState::NORMAL_MODE,
1981 mMockUidStatsCollector,
1982 mMockProcStatCollector,
1983 &actualResourceStats));
1984
1985 ASSERT_RESULT_OK(mCollector->onBoottimeCollection(getNowMillis(), mMockUidStatsCollector,
1986 mMockProcStatCollector,
1987 &actualResourceStats));
1988
1989 ASSERT_RESULT_OK(mCollector->onWakeUpCollection(getNowMillis(), mMockUidStatsCollector,
1990 mMockProcStatCollector));
1991
1992 ASSERT_RESULT_OK(mCollector->onCustomCollection(getNowMillis(), SystemState::NORMAL_MODE, {},
1993 mMockUidStatsCollector, mMockProcStatCollector,
1994 &actualResourceStats));
1995
1996 ASSERT_RESULT_OK(mCollector->onUserSwitchCollection(getNowMillis(), kTestBaseUserId,
1997 kTestBaseUserId + 1, mMockUidStatsCollector,
1998 mMockProcStatCollector));
1999
2000 util::ProtoOutputStream proto;
2001 mCollector->onDumpProto(collectionIntervals, proto);
2002
2003 PerformanceProfilerDump performanceProfilerDump;
2004 ASSERT_TRUE(performanceProfilerDump.ParseFromString(toString(&proto)));
2005
2006 PerformanceStats performanceStats = performanceProfilerDump.performance_stats();
2007 auto bootTimeStats = performanceStats.boot_time_stats();
2008 EXPECT_EQ(bootTimeStats.collection_interval_millis(), 1);
2009 for (auto& record : bootTimeStats.records()) {
2010 EXPECT_THAT(record,
2011 StatsRecordProtoEq(statsInfo.userPackageSummaryStats,
2012 statsInfo.systemSummaryStats, getNowMillis()));
2013 }
2014
2015 for (const auto& userSwitchStat : performanceStats.user_switch_stats()) {
2016 EXPECT_EQ(userSwitchStat.to_user_id(), kTestBaseUserId + 1);
2017 EXPECT_EQ(userSwitchStat.from_user_id(), kTestBaseUserId);
2018 auto userSwitchCollection = userSwitchStat.user_switch_collection();
2019 EXPECT_EQ(userSwitchCollection.collection_interval_millis(), 100);
2020 for (const auto& record : userSwitchCollection.records()) {
2021 EXPECT_THAT(record,
2022 StatsRecordProtoEq(statsInfo.userPackageSummaryStats,
2023 statsInfo.systemSummaryStats, getNowMillis()));
2024 }
2025 }
2026
2027 auto wakeUpStats = performanceStats.wake_up_stats();
2028 EXPECT_EQ(wakeUpStats.collection_interval_millis(), 1000);
2029 for (auto& record : wakeUpStats.records()) {
2030 EXPECT_THAT(record,
2031 StatsRecordProtoEq(statsInfo.userPackageSummaryStats,
2032 statsInfo.systemSummaryStats, getNowMillis()));
2033 }
2034
2035 auto lastNMinutesStats = performanceStats.last_n_minutes_stats();
2036 EXPECT_EQ(lastNMinutesStats.collection_interval_millis(), 10);
2037 for (auto& record : lastNMinutesStats.records()) {
2038 EXPECT_THAT(record,
2039 StatsRecordProtoEq(statsInfo.userPackageSummaryStats,
2040 statsInfo.systemSummaryStats, getNowMillis()));
2041 }
2042
2043 auto customCollectionStats = performanceStats.custom_collection_stats();
2044 EXPECT_EQ(customCollectionStats.collection_interval_millis(), 10000);
2045 for (auto& record : customCollectionStats.records()) {
2046 EXPECT_THAT(record,
2047 StatsRecordProtoEq(statsInfo.userPackageSummaryStats,
2048 statsInfo.systemSummaryStats, getNowMillis()));
2049 }
2050 }
2051
TEST_F(PerformanceProfilerTest,TestOnPeriodicCollectionWithSmapsRollupSupportInverted)2052 TEST_F(PerformanceProfilerTest, TestOnPeriodicCollectionWithSmapsRollupSupportInverted) {
2053 mCollectorPeer->setSmapsRollupSupportedEnabled(!kTestIsSmapsRollupSupported);
2054 auto [expectedCollectionInfo, expectedResourceStats] =
2055 setupFirstCollection(kTestPeriodicCollectionBufferSize, !kTestIsSmapsRollupSupported);
2056
2057 ResourceStats actualResourceStats = {};
2058 ASSERT_RESULT_OK(mCollector->onPeriodicCollection(getNowMillis(), SystemState::NORMAL_MODE,
2059 mMockUidStatsCollector,
2060 mMockProcStatCollector,
2061 &actualResourceStats));
2062
2063 const auto actualCollectionInfo = mCollectorPeer->getPeriodicCollectionInfo();
2064
2065 EXPECT_THAT(actualCollectionInfo, CollectionInfoEq(expectedCollectionInfo))
2066 << "When smaps rollup is not supported, periodic collection info doesn't match."
2067 << "\nExpected:\n"
2068 << expectedCollectionInfo.toString() << "\nActual:\n"
2069 << actualCollectionInfo.toString();
2070
2071 ASSERT_EQ(actualResourceStats, expectedResourceStats)
2072 << "Expected: " << expectedResourceStats.toString()
2073 << "\nActual: " << actualResourceStats.toString();
2074
2075 ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
2076 << "Boot-time, wake-up and user-switch collections shouldn't be reported";
2077 }
2078
2079 } // namespace watchdog
2080 } // namespace automotive
2081 } // namespace android
2082