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