1 /**
2 * Copyright (c) 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 #define LOG_TAG "carwatchdogd"
18
19 #include "PerformanceProfiler.h"
20
21 #include "ServiceManager.h"
22
23 #include <WatchdogProperties.sysprop.h>
24 #include <android-base/file.h>
25 #include <android-base/stringprintf.h>
26 #include <android/util/ProtoOutputStream.h>
27 #include <log/log.h>
28 #include <meminfo/androidprocheaps.h>
29
30 #include <inttypes.h>
31
32 #include <iomanip>
33 #include <limits>
34 #include <string>
35 #include <unordered_map>
36 #include <unordered_set>
37 #include <vector>
38
39 #include <packages/services/Car/service/proto/android/car/watchdog/carwatchdog_daemon_dump.proto.h>
40 #include <packages/services/Car/service/proto/android/car/watchdog/performance_stats.proto.h>
41
42 namespace android {
43 namespace automotive {
44 namespace watchdog {
45
46 namespace {
47
48 using ::aidl::android::automotive::watchdog::PerStateBytes;
49 using ::aidl::android::automotive::watchdog::internal::PackageIdentifier;
50 using ::aidl::android::automotive::watchdog::internal::ProcessCpuUsageStats;
51 using ::aidl::android::automotive::watchdog::internal::ResourceStats;
52 using ::aidl::android::automotive::watchdog::internal::ResourceUsageStats;
53 using ::aidl::android::automotive::watchdog::internal::SystemSummaryUsageStats;
54 using ::aidl::android::automotive::watchdog::internal::UidIoUsageStats;
55 using ::aidl::android::automotive::watchdog::internal::UidResourceUsageStats;
56 using ::android::wp;
57 using ::android::base::Error;
58 using ::android::base::Result;
59 using ::android::base::StringAppendF;
60 using ::android::base::StringPrintf;
61 using ::android::base::WriteStringToFd;
62 using ::android::util::ProtoOutputStream;
63
64 using PressureLevelDurationMap =
65 std::unordered_map<PressureMonitorInterface::PressureLevel, std::chrono::milliseconds>;
66
67 constexpr int32_t kDefaultTopNStatsPerCategory = 10;
68 constexpr int32_t kDefaultTopNStatsPerSubcategory = 5;
69 constexpr int32_t kDefaultMaxUserSwitchEvents = 5;
70 constexpr std::chrono::seconds kSystemEventDataCacheDurationSec = 1h;
71 constexpr const char kBootTimeCollectionTitle[] = "\n%s\nBoot-time performance report:\n%s\n";
72 constexpr const char kPeriodicCollectionTitle[] = "%s\nLast N minutes performance report:\n%s\n";
73 constexpr const char kUserSwitchCollectionTitle[] =
74 "%s\nUser-switch events performance report:\n%s\n";
75 constexpr const char kUserSwitchCollectionSubtitle[] = "Number of user switch events: %zu\n";
76 constexpr const char kWakeUpCollectionTitle[] = "%s\nWake-up performance report:\n%s\n";
77 constexpr const char kCustomCollectionTitle[] = "%s\nCustom performance data report:\n%s\n";
78 constexpr const char kUserSwitchEventTitle[] = "\nEvent %zu: From: %d To: %d\n%s\n";
79 constexpr const char kCollectionTitle[] =
80 "Collection duration: %.f seconds\nMaximum cache size: %zu\nNumber of collections: %zu\n";
81 constexpr const char kRecordTitle[] = "\nCollection %zu: <%s>\n%s\n%s";
82 constexpr const char kCpuTimeTitle[] = "\nTop N CPU times:\n%s\n";
83 constexpr const char kCpuTimeHeader[] = "Android User ID, Package Name, CPU Time (ms), Percentage "
84 "of total CPU time, CPU Cycles\n\tCommand, CPU Time (ms), "
85 "Percentage of UID's CPU Time, CPU Cycles\n";
86 constexpr const char kIoReadsTitle[] = "\nTop N storage I/O reads:\n%s\n";
87 constexpr const char kIoWritesTitle[] = "\nTop N storage I/O writes:\n%s\n";
88 constexpr const char kIoStatsHeader[] =
89 "Android User ID, Package Name, Foreground Bytes, Foreground Bytes %%, Foreground Fsync, "
90 "Foreground Fsync %%, Background Bytes, Background Bytes %%, Background Fsync, "
91 "Background Fsync %%\n";
92 constexpr const char kIoBlockedTitle[] = "\nTop N I/O waiting UIDs:\n%s\n";
93 constexpr const char kIoBlockedHeader[] =
94 "Android User ID, Package Name, Number of owned tasks waiting for I/O, Percentage of owned "
95 "tasks waiting for I/O\n\tCommand, Number of I/O waiting tasks, Percentage of UID's tasks "
96 "waiting for I/O\n";
97 constexpr const char kMajorPageFaultsTitle[] = "\nTop N major page faults:\n%s\n";
98 constexpr const char kMajorFaultsHeader[] =
99 "Android User ID, Package Name, Number of major page faults, Percentage of total major "
100 "page faults\n\tCommand, Number of major page faults, Percentage of UID's major page "
101 "faults\n";
102 constexpr const char kMajorFaultsSummary[] =
103 "Number of major page faults since last collection: %" PRIu64 "\n"
104 "Percentage of change in major page faults since last collection: %.2f%%\n";
105 constexpr const char kMemStatsTitle[] = "\nTop N memory stats:\n%s\n";
106 constexpr const char kMemStatsHeader[] =
107 "Android User ID, Package Name, RSS (kb), RSS %%, PSS (kb), PSS %%, USS (kb), Swap PSS (kb)"
108 "\n\tCommand, RSS (kb), PSS (kb), USS (kb), Swap PSS (kb)\n";
109 constexpr const char kMemStatsSummary[] = "Total RSS (kb): %" PRIu64 "\n"
110 "Total PSS (kb): %" PRIu64 "\n";
111
percentage(uint64_t numer,uint64_t denom)112 double percentage(uint64_t numer, uint64_t denom) {
113 return denom == 0 ? 0.0 : (static_cast<double>(numer) / static_cast<double>(denom)) * 100.0;
114 }
115
addUidIoStats(const int64_t entry[][UID_STATES],int64_t total[][UID_STATES])116 void addUidIoStats(const int64_t entry[][UID_STATES], int64_t total[][UID_STATES]) {
117 const auto sum = [](int64_t lhs, int64_t rhs) -> int64_t {
118 return std::numeric_limits<int64_t>::max() - lhs > rhs
119 ? lhs + rhs
120 : std::numeric_limits<int64_t>::max();
121 };
122 total[READ_BYTES][FOREGROUND] =
123 sum(total[READ_BYTES][FOREGROUND], entry[READ_BYTES][FOREGROUND]);
124 total[READ_BYTES][BACKGROUND] =
125 sum(total[READ_BYTES][BACKGROUND], entry[READ_BYTES][BACKGROUND]);
126 total[WRITE_BYTES][FOREGROUND] =
127 sum(total[WRITE_BYTES][FOREGROUND], entry[WRITE_BYTES][FOREGROUND]);
128 total[WRITE_BYTES][BACKGROUND] =
129 sum(total[WRITE_BYTES][BACKGROUND], entry[WRITE_BYTES][BACKGROUND]);
130 total[FSYNC_COUNT][FOREGROUND] =
131 sum(total[FSYNC_COUNT][FOREGROUND], entry[FSYNC_COUNT][FOREGROUND]);
132 total[FSYNC_COUNT][BACKGROUND] =
133 sum(total[FSYNC_COUNT][BACKGROUND], entry[FSYNC_COUNT][BACKGROUND]);
134 return;
135 }
136
cacheTopNStats(const UserPackageStats & curUserPackageStats,std::vector<UserPackageStats> * topNStats)137 bool cacheTopNStats(const UserPackageStats& curUserPackageStats,
138 std::vector<UserPackageStats>* topNStats) {
139 uint64_t curValue = curUserPackageStats.getValue();
140 if (curValue == 0) {
141 return false;
142 }
143 for (auto it = topNStats->begin(); it != topNStats->end(); ++it) {
144 if (curValue > it->getValue()) {
145 topNStats->insert(it, curUserPackageStats);
146 topNStats->pop_back();
147 return true;
148 }
149 }
150 return false;
151 }
152
checkDataCollectors(const sp<UidStatsCollectorInterface> & uidStatsCollector,const sp<ProcStatCollectorInterface> & procStatCollector)153 Result<void> checkDataCollectors(const sp<UidStatsCollectorInterface>& uidStatsCollector,
154 const sp<ProcStatCollectorInterface>& procStatCollector) {
155 if (uidStatsCollector != nullptr && procStatCollector != nullptr) {
156 return {};
157 }
158 std::string error;
159 if (uidStatsCollector == nullptr) {
160 error = "Per-UID stats collector must not be null";
161 }
162 if (procStatCollector == nullptr) {
163 StringAppendF(&error, "%s%s", error.empty() ? "" : ", ",
164 "Proc stats collector must not be null");
165 }
166 return Error() << "Invalid data collectors: " << error;
167 }
168
169 // Calculates the milliseconds since the UID started.
calculateUidUptimeMillis(int64_t elapsedTimeSinceBootMillis,const UidProcStats & procStats)170 int64_t calculateUidUptimeMillis(int64_t elapsedTimeSinceBootMillis,
171 const UidProcStats& procStats) {
172 int64_t earliestProcStartTimeMillis = std::numeric_limits<int64_t>::max();
173 for (auto [_, processStats] : procStats.processStatsByPid) {
174 if (processStats.startTimeMillis < earliestProcStartTimeMillis) {
175 earliestProcStartTimeMillis = processStats.startTimeMillis;
176 }
177 }
178 return elapsedTimeSinceBootMillis - earliestProcStartTimeMillis;
179 }
180
constructUidResourceUsageStats(PackageIdentifier packageIdentifier,int64_t uidUptimeMillis,int64_t totalCpuTimeMillis,bool isGarageModeActive,const UserPackageStats::UidCpuStats & uidCpuStats,const UserPackageStats::UidIoSingleOpStats & uidIoReadsStats,const UserPackageStats::UidIoSingleOpStats & uidIoWritesStats)181 UidResourceUsageStats constructUidResourceUsageStats(
182 PackageIdentifier packageIdentifier, int64_t uidUptimeMillis, int64_t totalCpuTimeMillis,
183 bool isGarageModeActive, const UserPackageStats::UidCpuStats& uidCpuStats,
184 const UserPackageStats::UidIoSingleOpStats& uidIoReadsStats,
185 const UserPackageStats::UidIoSingleOpStats& uidIoWritesStats) {
186 std::vector<ProcessCpuUsageStats> processCpuUsageStats;
187 processCpuUsageStats.reserve(uidCpuStats.topNProcesses.size());
188 for (const auto& processCpuStats : uidCpuStats.topNProcesses) {
189 processCpuUsageStats.push_back({
190 .pid = processCpuStats.pid,
191 .name = processCpuStats.comm,
192 .cpuTimeMillis = processCpuStats.cpuTimeMillis,
193 .cpuCycles = processCpuStats.cpuCycles,
194 });
195 }
196
197 UidIoUsageStats ioUsageStats = {};
198 if (isGarageModeActive) {
199 ioUsageStats.readBytes.garageModeBytes = uidIoReadsStats.totalBytes();
200 ioUsageStats.writtenBytes.garageModeBytes = uidIoWritesStats.totalBytes();
201 } else {
202 ioUsageStats.readBytes.foregroundBytes = uidIoReadsStats.bytes[UidState::FOREGROUND];
203 ioUsageStats.readBytes.backgroundBytes = uidIoReadsStats.bytes[UidState::BACKGROUND];
204 ioUsageStats.writtenBytes.foregroundBytes =
205 uidIoWritesStats.bytes[UidState::FOREGROUND];
206 ioUsageStats.writtenBytes.backgroundBytes =
207 uidIoWritesStats.bytes[UidState::BACKGROUND];
208 }
209
210 // clang-format off
211 return UidResourceUsageStats{
212 .packageIdentifier = std::move(packageIdentifier),
213 .uidUptimeMillis = uidUptimeMillis,
214 .cpuUsageStats = {
215 .cpuTimeMillis = uidCpuStats.cpuTimeMillis,
216 .cpuCycles = uidCpuStats.cpuCycles,
217 .cpuTimePercentage
218 = percentage(uidCpuStats.cpuTimeMillis, totalCpuTimeMillis),
219 },
220 .processCpuUsageStats = std::move(processCpuUsageStats),
221 .ioUsageStats = ioUsageStats,
222 };
223 // clang-format on
224 }
225
constructSystemSummaryUsageStats(bool isGarageModeActive,const SystemSummaryStats & systemStats,const UserPackageSummaryStats & userPackageStats)226 SystemSummaryUsageStats constructSystemSummaryUsageStats(
227 bool isGarageModeActive, const SystemSummaryStats& systemStats,
228 const UserPackageSummaryStats& userPackageStats) {
229 const auto sum = [](int64_t lhs, int64_t rhs) -> int64_t {
230 return std::numeric_limits<int64_t>::max() - lhs > rhs
231 ? lhs + rhs
232 : std::numeric_limits<int64_t>::max();
233 };
234
235 PerStateBytes totalIoReads = {};
236 PerStateBytes totalIoWrites = {};
237 if (isGarageModeActive) {
238 totalIoReads.garageModeBytes =
239 sum(userPackageStats.totalIoStats[MetricType::READ_BYTES][UidState::FOREGROUND],
240 userPackageStats.totalIoStats[MetricType::READ_BYTES][UidState::BACKGROUND]);
241 totalIoWrites.garageModeBytes =
242 sum(userPackageStats.totalIoStats[MetricType::WRITE_BYTES][UidState::FOREGROUND],
243 userPackageStats.totalIoStats[MetricType::WRITE_BYTES][UidState::BACKGROUND]);
244 } else {
245 totalIoReads.foregroundBytes =
246 userPackageStats.totalIoStats[MetricType::READ_BYTES][UidState::FOREGROUND];
247 totalIoReads.backgroundBytes =
248 userPackageStats.totalIoStats[MetricType::READ_BYTES][UidState::BACKGROUND];
249 totalIoWrites.foregroundBytes =
250 userPackageStats.totalIoStats[MetricType::WRITE_BYTES][UidState::FOREGROUND];
251 totalIoWrites.backgroundBytes =
252 userPackageStats.totalIoStats[MetricType::WRITE_BYTES][UidState::BACKGROUND];
253 }
254
255 return SystemSummaryUsageStats{
256 // Currently total CPU cycles derive from thread level CPU stats,
257 // hence they don't include idle information.
258 .cpuNonIdleCycles = static_cast<int64_t>(systemStats.totalCpuCycles),
259 .cpuNonIdleTimeMillis = systemStats.totalCpuTimeMillis - systemStats.cpuIdleTimeMillis,
260 .cpuIdleTimeMillis = systemStats.cpuIdleTimeMillis,
261 .contextSwitchesCount = static_cast<int64_t>(systemStats.contextSwitchesCount),
262 .ioBlockedProcessCount = static_cast<int32_t>(systemStats.ioBlockedProcessCount),
263 .totalProcessCount = static_cast<int32_t>(systemStats.totalProcessCount),
264 .totalMajorPageFaults = static_cast<int32_t>(userPackageStats.totalMajorFaults),
265 .totalIoReads = totalIoReads,
266 .totalIoWrites = totalIoWrites,
267 };
268 }
269
pressureLevelDurationMapToString(const PressureLevelDurationMap & pressureLevelDurations)270 std::string pressureLevelDurationMapToString(
271 const PressureLevelDurationMap& pressureLevelDurations) {
272 std::string buffer;
273 StringAppendF(&buffer, "Duration spent in various memory pressure levels:\n");
274 // The keys stored in PressureLevelDurationMap are unordered, so the pressure level ordering is
275 // inconsistent across different runs. In order to print values in a consistent order, iterate
276 // through the PressureLevel enum instead.
277 for (int i = PressureMonitorInterface::PRESSURE_LEVEL_NONE;
278 i < PressureMonitorInterface::PRESSURE_LEVEL_COUNT; ++i) {
279 PressureMonitorInterface::PressureLevel pressureLevel =
280 static_cast<PressureMonitorInterface::PressureLevel>(i);
281 if (const auto& it = pressureLevelDurations.find(pressureLevel);
282 it != pressureLevelDurations.end()) {
283 StringAppendF(&buffer, "\tPressure level: %s, Duration: %lld ms\n",
284 PressureMonitorInterface::PressureLevelToString(pressureLevel).c_str(),
285 it->second.count());
286 }
287 }
288 return buffer;
289 }
290
291 } // namespace
292
UserPackageStats(MetricType metricType,const UidStats & uidStats)293 UserPackageStats::UserPackageStats(MetricType metricType, const UidStats& uidStats) {
294 const UidIoStats& ioStats = uidStats.ioStats;
295 uid = uidStats.uid();
296 genericPackageName = uidStats.genericPackageName();
297 statsVariant = UserPackageStats::
298 UidIoSingleOpStats{.bytes = {ioStats.metrics[metricType][UidState::FOREGROUND],
299 ioStats.metrics[metricType][UidState::BACKGROUND]},
300 .fsync = {ioStats.metrics[MetricType::FSYNC_COUNT][UidState::FOREGROUND],
301 ioStats.metrics[MetricType::FSYNC_COUNT][UidState::BACKGROUND]}};
302 }
303
UserPackageStats(ProcStatType procStatType,const UidStats & uidStats,int topNProcessCount,bool isSmapsRollupSupported=false)304 UserPackageStats::UserPackageStats(ProcStatType procStatType, const UidStats& uidStats,
305 int topNProcessCount, bool isSmapsRollupSupported = false) {
306 uid = uidStats.uid();
307 genericPackageName = uidStats.genericPackageName();
308 switch (procStatType) {
309 case CPU_TIME: {
310 statsVariant = UserPackageStats::UidCpuStats{.cpuTimeMillis = static_cast<int64_t>(
311 uidStats.cpuTimeMillis),
312 .cpuCycles = static_cast<int64_t>(
313 uidStats.procStats.cpuCycles)};
314 auto& uidCpuStats = std::get<UserPackageStats::UidCpuStats>(statsVariant);
315 uidCpuStats.topNProcesses.resize(topNProcessCount);
316 cacheTopNProcessCpuStats(uidStats,
317 topNProcessCount,
318 &uidCpuStats.topNProcesses);
319 break;
320 }
321 case MEMORY_STATS: {
322 uint64_t totalUssKb = 0;
323 uint64_t totalSwapPssKb = 0;
324 // TODO(b/333212872): Move totalUssKb, totalSwapPssKb calculation logic to
325 // UidProcStatsCollector
326 for (auto [_, processStats] : uidStats.procStats.processStatsByPid) {
327 totalUssKb += processStats.ussKb;
328 totalSwapPssKb += processStats.swapPssKb;
329 }
330 statsVariant = UserPackageStats::UidMemoryStats{.memoryStats.rssKb =
331 uidStats.procStats.totalRssKb,
332 .memoryStats.pssKb =
333 uidStats.procStats.totalPssKb,
334 .memoryStats.ussKb = totalUssKb,
335 .memoryStats.swapPssKb = totalSwapPssKb,
336 .isSmapsRollupSupported =
337 isSmapsRollupSupported};
338 auto& uidMemoryStats = std::get<UserPackageStats::UidMemoryStats>(statsVariant);
339 uidMemoryStats.topNProcesses.resize(topNProcessCount);
340 cacheTopNProcessMemStats(uidStats, topNProcessCount,
341 uidMemoryStats.isSmapsRollupSupported,
342 &uidMemoryStats.topNProcesses);
343 break;
344 }
345 case IO_BLOCKED_TASKS_COUNT:
346 case MAJOR_FAULTS: {
347 uint64_t value = procStatType == IO_BLOCKED_TASKS_COUNT
348 ? uidStats.procStats.ioBlockedTasksCount
349 : uidStats.procStats.totalMajorFaults;
350 statsVariant = UserPackageStats::UidSingleStats{.value = value};
351 auto& uidSingleStats = std::get<UserPackageStats::UidSingleStats>(statsVariant);
352 uidSingleStats.topNProcesses.resize(topNProcessCount);
353 cacheTopNProcessSingleStats(procStatType, uidStats, topNProcessCount,
354 &uidSingleStats.topNProcesses);
355 break;
356 }
357 default: {
358 ALOGE("Invalid process stat type: %u", procStatType);
359 break;
360 }
361 }
362 }
363
getValue() const364 uint64_t UserPackageStats::getValue() const {
365 return std::visit(
366 [](auto&& arg) -> uint64_t {
367 using T = std::decay_t<decltype(arg)>;
368 if constexpr (std::is_same_v<T, UserPackageStats::UidIoSingleOpStats>) {
369 return arg.totalBytes();
370 }
371 if constexpr (std::is_same_v<T, UserPackageStats::UidSingleStats>) {
372 return arg.value;
373 }
374 if constexpr (std::is_same_v<T, UserPackageStats::UidCpuStats>) {
375 return arg.cpuTimeMillis;
376 }
377 if constexpr (std::is_same_v<T, UserPackageStats::UidMemoryStats>) {
378 return arg.isSmapsRollupSupported ? arg.memoryStats.pssKb
379 : arg.memoryStats.rssKb;
380 }
381 // Unknown uid stats
382 return 0;
383 },
384 statsVariant);
385 }
386
toString(MetricType metricsType,const int64_t totalIoStats[][UID_STATES]) const387 std::string UserPackageStats::toString(MetricType metricsType,
388 const int64_t totalIoStats[][UID_STATES]) const {
389 std::string buffer;
390 StringAppendF(&buffer, "%" PRIu32 ", %s", multiuser_get_user_id(uid),
391 genericPackageName.c_str());
392 const auto& uidIoSingleOpStats = std::get<UserPackageStats::UidIoSingleOpStats>(statsVariant);
393 for (int i = 0; i < UID_STATES; ++i) {
394 StringAppendF(&buffer, ", %" PRIi64 ", %.2f%%, %" PRIi64 ", %.2f%%",
395 uidIoSingleOpStats.bytes[i],
396 percentage(uidIoSingleOpStats.bytes[i],
397 totalIoStats[metricsType][i]),
398 uidIoSingleOpStats.fsync[i],
399 percentage(uidIoSingleOpStats.fsync[i],
400 totalIoStats[FSYNC_COUNT][i]));
401 }
402 StringAppendF(&buffer, "\n");
403 return buffer;
404 }
405
toString(int64_t totalValue) const406 std::string UserPackageStats::toString(int64_t totalValue) const {
407 std::string buffer;
408 int64_t totalProcessTimeMillis = 0;
409 auto uidCpuStats = std::get_if<UserPackageStats::UidCpuStats>(&statsVariant);
410 if (uidCpuStats != nullptr) {
411 // Sometimes, the CPU time used by a specific process (reported in /proc/<pid>/stat) is
412 // higher than the total CPU time used by all processes belonging to the same UID (reported
413 // in /proc/uid_cputime/show_uid_stat). This can happen if the UID only has one process
414 // running. The reason is likely a difference in how the kernel calculates and reports CPU
415 // usage in these two places. To ensure accuracy, use the higher of the two reported total
416 // CPU times when calculating percentage.
417 for (const auto& processCpuStats : uidCpuStats->topNProcesses) {
418 totalProcessTimeMillis += processCpuStats.cpuTimeMillis;
419 }
420 totalProcessTimeMillis = std::max(totalProcessTimeMillis,
421 uidCpuStats->cpuTimeMillis);
422 StringAppendF(&buffer, "%" PRIu32 ", %s, %" PRIu64 ", %.2f%%, %" PRIu64 "\n",
423 multiuser_get_user_id(uid), genericPackageName.c_str(),
424 totalProcessTimeMillis,
425 percentage(totalProcessTimeMillis, totalValue),
426 uidCpuStats->cpuCycles);
427 for (const auto& processCpuStats : uidCpuStats->topNProcesses) {
428 StringAppendF(&buffer, "\t%s, %" PRIu64 ", %.2f%%, %" PRIu64 "\n",
429 processCpuStats.comm.c_str(), processCpuStats.cpuTimeMillis,
430 percentage(processCpuStats.cpuTimeMillis,
431 totalProcessTimeMillis),
432 processCpuStats.cpuCycles);
433 }
434 return buffer;
435 }
436 const auto& uidSingleStats = std::get<UserPackageStats::UidSingleStats>(statsVariant);
437 StringAppendF(&buffer, "%" PRIu32 ", %s, %" PRIu64 ", %.2f%%\n", multiuser_get_user_id(uid),
438 genericPackageName.c_str(), uidSingleStats.value,
439 percentage(uidSingleStats.value, totalValue));
440 for (const auto& processSingleStats : uidSingleStats.topNProcesses) {
441 StringAppendF(&buffer, "\t%s, %" PRIu64 ", %.2f%%\n", processSingleStats.comm.c_str(),
442 processSingleStats.value,
443 percentage(processSingleStats.value,
444 uidSingleStats.value));
445 }
446 return buffer;
447 }
448
toString(int64_t totalRssKb,int64_t totalPssKb) const449 std::string UserPackageStats::toString(int64_t totalRssKb, int64_t totalPssKb) const {
450 std::string buffer;
451 const auto* uidMemoryStats = std::get_if<UserPackageStats::UidMemoryStats>(&statsVariant);
452 if (uidMemoryStats == nullptr) {
453 return buffer;
454 }
455 StringAppendF(&buffer,
456 "%" PRIu32 ", %s, %" PRIu64 ", %.2f%%, %" PRIu64 ", %.2f%%, %" PRIu64 ", %" PRIu64
457 "\n",
458 multiuser_get_user_id(uid), genericPackageName.c_str(),
459 uidMemoryStats->memoryStats.rssKb,
460 percentage(uidMemoryStats->memoryStats.rssKb, totalRssKb),
461 uidMemoryStats->memoryStats.pssKb,
462 percentage(uidMemoryStats->memoryStats.pssKb, totalPssKb),
463 uidMemoryStats->memoryStats.ussKb, uidMemoryStats->memoryStats.swapPssKb);
464 for (const auto& processMemoryStats : uidMemoryStats->topNProcesses) {
465 StringAppendF(&buffer, "\t%s, %" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 "\n",
466 processMemoryStats.comm.c_str(), processMemoryStats.memoryStats.rssKb,
467 processMemoryStats.memoryStats.pssKb, processMemoryStats.memoryStats.ussKb,
468 processMemoryStats.memoryStats.swapPssKb);
469 }
470 return buffer;
471 }
472
cacheTopNProcessSingleStats(ProcStatType procStatType,const UidStats & uidStats,int topNProcessCount,std::vector<UserPackageStats::UidSingleStats::ProcessSingleStats> * topNProcesses)473 void UserPackageStats::cacheTopNProcessSingleStats(
474 ProcStatType procStatType, const UidStats& uidStats, int topNProcessCount,
475 std::vector<UserPackageStats::UidSingleStats::ProcessSingleStats>* topNProcesses) {
476 int cachedProcessCount = 0;
477 for (const auto& [_, processStats] : uidStats.procStats.processStatsByPid) {
478 uint64_t value = procStatType == IO_BLOCKED_TASKS_COUNT ? processStats.ioBlockedTasksCount
479 : processStats.totalMajorFaults;
480 if (value == 0) {
481 continue;
482 }
483 for (auto it = topNProcesses->begin(); it != topNProcesses->end(); ++it) {
484 if (value > it->value) {
485 topNProcesses->insert(it,
486 UserPackageStats::UidSingleStats::ProcessSingleStats{
487 .comm = processStats.comm,
488 .value = value,
489 });
490 topNProcesses->pop_back();
491 ++cachedProcessCount;
492 break;
493 }
494 }
495 }
496 if (cachedProcessCount < topNProcessCount) {
497 topNProcesses->erase(topNProcesses->begin() + cachedProcessCount, topNProcesses->end());
498 }
499 }
500
cacheTopNProcessCpuStats(const UidStats & uidStats,int topNProcessCount,std::vector<UserPackageStats::UidCpuStats::ProcessCpuStats> * topNProcesses)501 void UserPackageStats::cacheTopNProcessCpuStats(
502 const UidStats& uidStats, int topNProcessCount,
503 std::vector<UserPackageStats::UidCpuStats::ProcessCpuStats>* topNProcesses) {
504 int cachedProcessCount = 0;
505 for (const auto& [pid, processStats] : uidStats.procStats.processStatsByPid) {
506 int64_t cpuTimeMillis = processStats.cpuTimeMillis;
507 if (cpuTimeMillis == 0) {
508 continue;
509 }
510 for (auto it = topNProcesses->begin(); it != topNProcesses->end(); ++it) {
511 if (cpuTimeMillis > it->cpuTimeMillis) {
512 topNProcesses->insert(it,
513 UserPackageStats::UidCpuStats::ProcessCpuStats{
514 .pid = pid,
515 .comm = processStats.comm,
516 .cpuTimeMillis = cpuTimeMillis,
517 .cpuCycles = static_cast<int64_t>(
518 processStats.totalCpuCycles),
519 });
520 topNProcesses->pop_back();
521 ++cachedProcessCount;
522 break;
523 }
524 }
525 }
526 if (cachedProcessCount < topNProcessCount) {
527 topNProcesses->erase(topNProcesses->begin() + cachedProcessCount, topNProcesses->end());
528 }
529 }
530
cacheTopNProcessMemStats(const UidStats & uidStats,int topNProcessCount,bool isSmapsRollupSupported,std::vector<UserPackageStats::UidMemoryStats::ProcessMemoryStats> * topNProcesses)531 void UserPackageStats::cacheTopNProcessMemStats(
532 const UidStats& uidStats, int topNProcessCount, bool isSmapsRollupSupported,
533 std::vector<UserPackageStats::UidMemoryStats::ProcessMemoryStats>* topNProcesses) {
534 int cachedProcessCount = 0;
535 for (const auto& [pid, processStats] : uidStats.procStats.processStatsByPid) {
536 uint64_t pssKb = processStats.pssKb;
537 uint64_t rssKb = processStats.rssKb;
538 if ((isSmapsRollupSupported ? pssKb : rssKb) == 0) {
539 continue;
540 }
541 for (auto it = topNProcesses->begin(); it != topNProcesses->end(); ++it) {
542 if (isSmapsRollupSupported ? pssKb > it->memoryStats.pssKb
543 : rssKb > it->memoryStats.rssKb) {
544 topNProcesses->insert(it,
545 UserPackageStats::UidMemoryStats::ProcessMemoryStats{
546 .comm = processStats.comm,
547 .memoryStats.rssKb = rssKb,
548 .memoryStats.pssKb = pssKb,
549 .memoryStats.ussKb = processStats.ussKb,
550 .memoryStats.swapPssKb = processStats.swapPssKb,
551 });
552 topNProcesses->pop_back();
553 ++cachedProcessCount;
554 break;
555 }
556 }
557 }
558 if (cachedProcessCount < topNProcessCount) {
559 topNProcesses->erase(topNProcesses->begin() + cachedProcessCount, topNProcesses->end());
560 }
561 }
562
toString() const563 std::string UserPackageSummaryStats::toString() const {
564 std::string buffer;
565 if (!topNCpuTimes.empty()) {
566 StringAppendF(&buffer, kCpuTimeTitle, std::string(16, '-').c_str());
567 StringAppendF(&buffer, kCpuTimeHeader);
568 for (const auto& stats : topNCpuTimes) {
569 StringAppendF(&buffer, "%s", stats.toString(totalCpuTimeMillis).c_str());
570 }
571 }
572 if (!topNIoReads.empty()) {
573 StringAppendF(&buffer, kIoReadsTitle, std::string(24, '-').c_str());
574 StringAppendF(&buffer, kIoStatsHeader);
575 for (const auto& stats : topNIoReads) {
576 StringAppendF(&buffer, "%s",
577 stats.toString(MetricType::READ_BYTES, totalIoStats).c_str());
578 }
579 }
580 if (!topNIoWrites.empty()) {
581 StringAppendF(&buffer, kIoWritesTitle, std::string(25, '-').c_str());
582 StringAppendF(&buffer, kIoStatsHeader);
583 for (const auto& stats : topNIoWrites) {
584 StringAppendF(&buffer, "%s",
585 stats.toString(MetricType::WRITE_BYTES, totalIoStats).c_str());
586 }
587 }
588 if (!topNIoBlocked.empty()) {
589 StringAppendF(&buffer, kIoBlockedTitle, std::string(23, '-').c_str());
590 StringAppendF(&buffer, kIoBlockedHeader);
591 for (const auto& stats : topNIoBlocked) {
592 const auto it = taskCountByUid.find(stats.uid);
593 if (it == taskCountByUid.end()) {
594 continue;
595 }
596 StringAppendF(&buffer, "%s", stats.toString(it->second).c_str());
597 }
598 }
599 if (!topNMajorFaults.empty()) {
600 StringAppendF(&buffer, kMajorPageFaultsTitle, std::string(24, '-').c_str());
601 StringAppendF(&buffer, kMajorFaultsHeader);
602 for (const auto& stats : topNMajorFaults) {
603 StringAppendF(&buffer, "%s", stats.toString(totalMajorFaults).c_str());
604 }
605 StringAppendF(&buffer, kMajorFaultsSummary, totalMajorFaults, majorFaultsPercentChange);
606 }
607 if (!topNMemStats.empty()) {
608 StringAppendF(&buffer, kMemStatsTitle, std::string(19, '-').c_str());
609 StringAppendF(&buffer, kMemStatsHeader);
610 for (const auto& stats : topNMemStats) {
611 StringAppendF(&buffer, "%s", stats.toString(totalRssKb, totalPssKb).c_str());
612 }
613 StringAppendF(&buffer, kMemStatsSummary, totalRssKb, totalPssKb);
614 }
615 return buffer;
616 }
617
toString() const618 std::string SystemSummaryStats::toString() const {
619 std::string buffer;
620 StringAppendF(&buffer, "System summary stats:\n");
621 StringAppendF(&buffer, "\tTotal CPU time (ms): %" PRIu64 "\n", totalCpuTimeMillis);
622 StringAppendF(&buffer, "\tTotal CPU cycles: %" PRIu64 "\n", totalCpuCycles);
623 StringAppendF(&buffer, "\tTotal idle CPU time (ms)/percent: %" PRIu64 " / %.2f%%\n",
624 cpuIdleTimeMillis, percentage(cpuIdleTimeMillis, totalCpuTimeMillis));
625 StringAppendF(&buffer, "\tCPU I/O wait time (ms)/percent: %" PRIu64 " / %.2f%%\n",
626 cpuIoWaitTimeMillis, percentage(cpuIoWaitTimeMillis, totalCpuTimeMillis));
627 StringAppendF(&buffer, "\tNumber of context switches: %" PRIu64 "\n", contextSwitchesCount);
628 StringAppendF(&buffer, "\tNumber of I/O blocked processes/percent: %" PRIu32 " / %.2f%%\n",
629 ioBlockedProcessCount, percentage(ioBlockedProcessCount, totalProcessCount));
630 // TODO(b/337115923): Report `totalMajorFaults`, `totalRssKb`, `totalPssKb`, and
631 // `majorFaultsPercentChange` here.
632 return buffer;
633 }
634
toString() const635 std::string PerfStatsRecord::toString() const {
636 std::string buffer;
637 StringAppendF(&buffer, "%s\n%s\n%s",
638 pressureLevelDurationMapToString(memoryPressureLevelDurations).c_str(),
639 systemSummaryStats.toString().c_str(),
640 userPackageSummaryStats.toString().c_str());
641 return buffer;
642 }
643
toString() const644 std::string CollectionInfo::toString() const {
645 if (records.empty()) {
646 return kEmptyCollectionMessage;
647 }
648 std::string buffer;
649 double duration =
650 difftime(std::chrono::system_clock::to_time_t(records.back().collectionTimeMillis),
651 std::chrono::system_clock::to_time_t(records.front().collectionTimeMillis));
652 StringAppendF(&buffer, kCollectionTitle, duration, maxCacheSize, records.size());
653 for (size_t i = 0; i < records.size(); ++i) {
654 const auto& record = records[i];
655 std::stringstream timestamp;
656 auto timeInSeconds = std::chrono::system_clock::to_time_t(record.collectionTimeMillis);
657 timestamp << std::put_time(std::localtime(&timeInSeconds), "%c %Z");
658 StringAppendF(&buffer, kRecordTitle, i, timestamp.str().c_str(),
659 std::string(45, '=').c_str(), record.toString().c_str());
660 }
661 return buffer;
662 }
663
init()664 Result<void> PerformanceProfiler::init() {
665 Mutex::Autolock lock(mMutex);
666 if (mTopNStatsPerCategory != 0 || mTopNStatsPerSubcategory != 0) {
667 return Error() << "Cannot initialize " << name() << " more than once";
668 }
669 mTopNStatsPerCategory = static_cast<int>(
670 sysprop::topNStatsPerCategory().value_or(kDefaultTopNStatsPerCategory));
671 mTopNStatsPerSubcategory = static_cast<int>(
672 sysprop::topNStatsPerSubcategory().value_or(kDefaultTopNStatsPerSubcategory));
673 mMaxUserSwitchEvents = static_cast<size_t>(
674 sysprop::maxUserSwitchEvents().value_or(kDefaultMaxUserSwitchEvents));
675 mSystemEventDataCacheDurationSec =
676 std::chrono::seconds(sysprop::systemEventDataCacheDuration().value_or(
677 kSystemEventDataCacheDurationSec.count()));
678 size_t periodicCollectionBufferSize = static_cast<size_t>(
679 sysprop::periodicCollectionBufferSize().value_or(kDefaultPeriodicCollectionBufferSize));
680 mBoottimeCollection = {
681 .maxCacheSize = std::numeric_limits<std::size_t>::max(),
682 .records = {},
683 };
684 mPeriodicCollection = {
685 .maxCacheSize = periodicCollectionBufferSize,
686 .records = {},
687 };
688 mWakeUpCollection = {
689 .maxCacheSize = std::numeric_limits<std::size_t>::max(),
690 .records = {},
691 };
692 mCustomCollection = {
693 .maxCacheSize = std::numeric_limits<std::size_t>::max(),
694 .records = {},
695 };
696 if (!mIsMemoryProfilingEnabled || !kPressureMonitor->isEnabled()) {
697 return {};
698 }
699 if (auto result = kPressureMonitor->registerPressureChangeCallback(
700 sp<PerformanceProfiler>::fromExisting(this));
701 !result.ok()) {
702 ALOGE("Failed to register pressure change callback for '%s'. Error: %s", name().c_str(),
703 result.error().message().c_str());
704 }
705 return {};
706 }
707
terminate()708 void PerformanceProfiler::terminate() {
709 Mutex::Autolock lock(mMutex);
710 ALOGW("Terminating %s", name().c_str());
711
712 if (mIsMemoryProfilingEnabled && kPressureMonitor->isEnabled()) {
713 kPressureMonitor->unregisterPressureChangeCallback(
714 sp<PerformanceProfiler>::fromExisting(this));
715 }
716
717 mBoottimeCollection.records.clear();
718 mBoottimeCollection = {};
719
720 mPeriodicCollection.records.clear();
721 mPeriodicCollection = {};
722
723 mUserSwitchCollections.clear();
724
725 mCustomCollection.records.clear();
726 mCustomCollection = {};
727 }
728
onDump(int fd) const729 Result<void> PerformanceProfiler::onDump(int fd) const {
730 Mutex::Autolock lock(mMutex);
731 if (!WriteStringToFd(StringPrintf("/proc/<pid>/smaps_rollup is %s\n",
732 mIsSmapsRollupSupported
733 ? "supported. So, using PSS to rank top memory "
734 "consuming processes."
735 : "not supported. So, using RSS to rank top memory "
736 "consuming processes."),
737 fd) ||
738 !WriteStringToFd(StringPrintf(kBootTimeCollectionTitle, std::string(75, '-').c_str(),
739 std::string(33, '=').c_str()),
740 fd) ||
741 !WriteStringToFd(mBoottimeCollection.toString(), fd)) {
742 return Error(FAILED_TRANSACTION) << "Failed to dump the boot-time collection report.";
743 }
744 if (!WriteStringToFd(StringPrintf(kWakeUpCollectionTitle, std::string(75, '-').c_str(),
745 std::string(27, '=').c_str()),
746 fd) ||
747 !WriteStringToFd(mWakeUpCollection.toString(), fd)) {
748 return Error(FAILED_TRANSACTION) << "Failed to dump the boot-time collection report.";
749 }
750 if (const auto& result = onUserSwitchCollectionDump(fd); !result.ok()) {
751 return result.error();
752 }
753 if (!WriteStringToFd(StringPrintf(kPeriodicCollectionTitle, std::string(75, '-').c_str(),
754 std::string(38, '=').c_str()),
755 fd) ||
756 !WriteStringToFd(mPeriodicCollection.toString(), fd)) {
757 return Error(FAILED_TRANSACTION) << "Failed to dump the periodic collection report.";
758 }
759 return {};
760 }
761
onDumpProto(const CollectionIntervals & collectionIntervals,ProtoOutputStream & outProto) const762 Result<void> PerformanceProfiler::onDumpProto(const CollectionIntervals& collectionIntervals,
763 ProtoOutputStream& outProto) const {
764 Mutex::Autolock lock(mMutex);
765
766 uint64_t performanceStatsToken = outProto.start(PerformanceProfilerDump::PERFORMANCE_STATS);
767
768 uint64_t bootTimeStatsToken = outProto.start(PerformanceStats::BOOT_TIME_STATS);
769 outProto.write(StatsCollection::COLLECTION_INTERVAL_MILLIS,
770 collectionIntervals.mBoottimeIntervalMillis.count());
771 dumpStatsRecordsProto(mBoottimeCollection, outProto);
772 outProto.end(bootTimeStatsToken);
773
774 uint64_t wakeUpStatsToken = outProto.start(PerformanceStats::WAKE_UP_STATS);
775 outProto.write(StatsCollection::COLLECTION_INTERVAL_MILLIS,
776 collectionIntervals.mWakeUpIntervalMillis.count());
777 dumpStatsRecordsProto(mWakeUpCollection, outProto);
778 outProto.end(wakeUpStatsToken);
779
780 for (const auto& userSwitchCollection : mUserSwitchCollections) {
781 uint64_t userSwitchStatsToken = outProto.start(PerformanceStats::USER_SWITCH_STATS);
782 outProto.write(UserSwitchStatsCollection::TO_USER_ID,
783 static_cast<int>(userSwitchCollection.to));
784 outProto.write(UserSwitchStatsCollection::FROM_USER_ID,
785 static_cast<int>(userSwitchCollection.from));
786 uint64_t userSwitchCollectionToken =
787 outProto.start(UserSwitchStatsCollection::USER_SWITCH_COLLECTION);
788 outProto.write(StatsCollection::COLLECTION_INTERVAL_MILLIS,
789 collectionIntervals.mUserSwitchIntervalMillis.count());
790 dumpStatsRecordsProto(userSwitchCollection, outProto);
791 outProto.end(userSwitchCollectionToken);
792 outProto.end(userSwitchStatsToken);
793 }
794
795 uint64_t lastNMinutesStatsToken = outProto.start(PerformanceStats::LAST_N_MINUTES_STATS);
796 outProto.write(StatsCollection::COLLECTION_INTERVAL_MILLIS,
797 collectionIntervals.mPeriodicIntervalMillis.count());
798 dumpStatsRecordsProto(mPeriodicCollection, outProto);
799 outProto.end(lastNMinutesStatsToken);
800
801 uint64_t customCollectionStatsToken = outProto.start(PerformanceStats::CUSTOM_COLLECTION_STATS);
802 outProto.write(StatsCollection::COLLECTION_INTERVAL_MILLIS,
803 collectionIntervals.mCustomIntervalMillis.count());
804 dumpStatsRecordsProto(mCustomCollection, outProto);
805 outProto.end(customCollectionStatsToken);
806
807 outProto.end(performanceStatsToken);
808
809 return {};
810 }
811
dumpStatsRecordsProto(const CollectionInfo & collection,ProtoOutputStream & outProto) const812 void PerformanceProfiler::dumpStatsRecordsProto(const CollectionInfo& collection,
813 ProtoOutputStream& outProto) const {
814 int id = 0;
815 for (const auto& record : collection.records) {
816 uint64_t statsRecordToken = outProto.start(StatsCollection::RECORDS);
817
818 outProto.write(StatsRecord::ID, id++);
819 struct tm timeinfo;
820 memset(&timeinfo, 0, sizeof(timeinfo));
821 auto dateTime = std::chrono::system_clock::to_time_t(record.collectionTimeMillis);
822 if (!localtime_r(&dateTime, &timeinfo)) {
823 ALOGE("Failed to obtain localtime: %s", strerror(errno));
824 return;
825 }
826
827 auto collectionTimeMillis = std::chrono::duration_cast<std::chrono::milliseconds>(
828 record.collectionTimeMillis - std::chrono::system_clock::from_time_t(dateTime));
829
830 uint64_t dateToken = outProto.start(StatsRecord::DATE);
831 outProto.write(Date::YEAR, timeinfo.tm_year + 1900);
832 outProto.write(Date::MONTH, timeinfo.tm_mon);
833 outProto.write(Date::DAY, timeinfo.tm_mday);
834 outProto.end(dateToken);
835
836 uint64_t timeOfDayToken = outProto.start(StatsRecord::TIME);
837 outProto.write(TimeOfDay::HOURS, timeinfo.tm_hour);
838 outProto.write(TimeOfDay::MINUTES, timeinfo.tm_min);
839 outProto.write(TimeOfDay::SECONDS, timeinfo.tm_sec);
840 outProto.write(TimeOfDay::MILLIS, collectionTimeMillis.count());
841 outProto.end(timeOfDayToken);
842
843 uint64_t systemWideStatsToken = outProto.start(StatsRecord::SYSTEM_WIDE_STATS);
844 outProto.write(SystemWideStats::IO_WAIT_TIME_MILLIS,
845 record.systemSummaryStats.cpuIoWaitTimeMillis);
846 outProto.write(SystemWideStats::IDLE_CPU_TIME_MILLIS,
847 record.systemSummaryStats.cpuIdleTimeMillis);
848 outProto.write(SystemWideStats::TOTAL_CPU_TIME_MILLIS,
849 record.systemSummaryStats.totalCpuTimeMillis);
850 outProto.write(SystemWideStats::TOTAL_CPU_CYCLES,
851 static_cast<int>(record.systemSummaryStats.totalCpuCycles));
852 outProto.write(SystemWideStats::TOTAL_CONTEXT_SWITCHES,
853 static_cast<int>(record.systemSummaryStats.contextSwitchesCount));
854 outProto.write(SystemWideStats::TOTAL_IO_BLOCKED_PROCESSES,
855 static_cast<int>(record.systemSummaryStats.ioBlockedProcessCount));
856 outProto.write(SystemWideStats::TOTAL_MAJOR_PAGE_FAULTS,
857 static_cast<int>(record.userPackageSummaryStats.totalMajorFaults));
858
859 uint64_t totalStorageIoStatsToken = outProto.start(SystemWideStats::TOTAL_STORAGE_IO_STATS);
860 outProto.write(StorageIoStats::FG_BYTES,
861 record.userPackageSummaryStats.totalIoStats[WRITE_BYTES][FOREGROUND]);
862 outProto.write(StorageIoStats::FG_FSYNC,
863 record.userPackageSummaryStats.totalIoStats[FSYNC_COUNT][FOREGROUND]);
864 outProto.write(StorageIoStats::BG_BYTES,
865 record.userPackageSummaryStats.totalIoStats[WRITE_BYTES][BACKGROUND]);
866 outProto.write(StorageIoStats::BG_FSYNC,
867 record.userPackageSummaryStats.totalIoStats[FSYNC_COUNT][BACKGROUND]);
868 outProto.end(totalStorageIoStatsToken);
869
870 outProto.end(systemWideStatsToken);
871
872 dumpPackageCpuStatsProto(record.userPackageSummaryStats.topNCpuTimes, outProto);
873
874 dumpPackageStorageIoStatsProto(record.userPackageSummaryStats.topNIoReads,
875 StatsRecord::PACKAGE_STORAGE_IO_READ_STATS, outProto);
876
877 dumpPackageStorageIoStatsProto(record.userPackageSummaryStats.topNIoWrites,
878 StatsRecord::PACKAGE_STORAGE_IO_WRITE_STATS, outProto);
879
880 dumpPackageTaskStateStatsProto(record.userPackageSummaryStats.topNIoBlocked,
881 record.userPackageSummaryStats.taskCountByUid, outProto);
882
883 dumpPackageMajorPageFaultsProto(record.userPackageSummaryStats.topNMajorFaults, outProto);
884
885 outProto.end(statsRecordToken);
886 }
887 }
888
dumpPackageCpuStatsProto(const std::vector<UserPackageStats> & topNCpuTimes,ProtoOutputStream & outProto) const889 void PerformanceProfiler::dumpPackageCpuStatsProto(
890 const std::vector<UserPackageStats>& topNCpuTimes, ProtoOutputStream& outProto) const {
891 for (const auto& userPackageStats : topNCpuTimes) {
892 uint64_t packageCpuStatsToken = outProto.start(StatsRecord::PACKAGE_CPU_STATS);
893 const auto& uidCpuStats =
894 std::get_if<UserPackageStats::UidCpuStats>(&userPackageStats.statsVariant);
895
896 uint64_t userPackageInfoToken = outProto.start(PackageCpuStats::USER_PACKAGE_INFO);
897 outProto.write(UserPackageInfo::USER_ID,
898 static_cast<int>(multiuser_get_user_id(userPackageStats.uid)));
899 outProto.write(UserPackageInfo::PACKAGE_NAME, userPackageStats.genericPackageName);
900 outProto.end(userPackageInfoToken);
901
902 uint64_t cpuStatsToken = outProto.start(PackageCpuStats::CPU_STATS);
903 outProto.write(PackageCpuStats::CpuStats::CPU_TIME_MILLIS,
904 static_cast<int>(uidCpuStats->cpuTimeMillis));
905 outProto.write(PackageCpuStats::CpuStats::CPU_CYCLES,
906 static_cast<int>(uidCpuStats->cpuCycles));
907 outProto.end(cpuStatsToken);
908
909 for (const auto& processCpuStat : uidCpuStats->topNProcesses) {
910 uint64_t processCpuStatToken = outProto.start(PackageCpuStats::PROCESS_CPU_STATS);
911 outProto.write(PackageCpuStats::ProcessCpuStats::COMMAND, processCpuStat.comm);
912
913 uint64_t processCpuValueToken =
914 outProto.start(PackageCpuStats::ProcessCpuStats::CPU_STATS);
915 outProto.write(PackageCpuStats::CpuStats::CPU_TIME_MILLIS,
916 static_cast<int>(processCpuStat.cpuTimeMillis));
917 outProto.write(PackageCpuStats::CpuStats::CPU_CYCLES,
918 static_cast<int>(processCpuStat.cpuCycles));
919 outProto.end(processCpuValueToken);
920
921 outProto.end(processCpuStatToken);
922 }
923 outProto.end(packageCpuStatsToken);
924 }
925 }
926
dumpPackageStorageIoStatsProto(const std::vector<UserPackageStats> & userPackageStats,const uint64_t storageStatsFieldId,ProtoOutputStream & outProto) const927 void PerformanceProfiler::dumpPackageStorageIoStatsProto(
928 const std::vector<UserPackageStats>& userPackageStats, const uint64_t storageStatsFieldId,
929 ProtoOutputStream& outProto) const {
930 for (const auto& userPackageStats : userPackageStats) {
931 uint64_t token = outProto.start(storageStatsFieldId);
932 const auto& uidIoSingleOpStats =
933 std::get_if<UserPackageStats::UidIoSingleOpStats>(&userPackageStats.statsVariant);
934
935 uint64_t userPackageInfoToken = outProto.start(PackageStorageIoStats::USER_PACKAGE_INFO);
936 outProto.write(UserPackageInfo::USER_ID,
937 static_cast<int>(multiuser_get_user_id(userPackageStats.uid)));
938 outProto.write(UserPackageInfo::PACKAGE_NAME, userPackageStats.genericPackageName);
939 outProto.end(userPackageInfoToken);
940
941 uint64_t storageIoStatsToken = outProto.start(PackageStorageIoStats::STORAGE_IO_STATS);
942 outProto.write(StorageIoStats::FG_BYTES,
943 static_cast<int>(uidIoSingleOpStats->bytes[FOREGROUND]));
944 outProto.write(StorageIoStats::FG_FSYNC,
945 static_cast<int>(uidIoSingleOpStats->fsync[FOREGROUND]));
946 outProto.write(StorageIoStats::BG_BYTES,
947 static_cast<int>(uidIoSingleOpStats->bytes[BACKGROUND]));
948 outProto.write(StorageIoStats::BG_FSYNC,
949 static_cast<int>(uidIoSingleOpStats->fsync[BACKGROUND]));
950 outProto.end(storageIoStatsToken);
951
952 outProto.end(token);
953 }
954 }
955
dumpPackageTaskStateStatsProto(const std::vector<UserPackageStats> & topNIoBlocked,const std::unordered_map<uid_t,uint64_t> & taskCountByUid,ProtoOutputStream & outProto) const956 void PerformanceProfiler::dumpPackageTaskStateStatsProto(
957 const std::vector<UserPackageStats>& topNIoBlocked,
958 const std::unordered_map<uid_t, uint64_t>& taskCountByUid,
959 ProtoOutputStream& outProto) const {
960 for (const auto& userPackageStats : topNIoBlocked) {
961 const auto taskCount = taskCountByUid.find(userPackageStats.uid);
962 if (taskCount == taskCountByUid.end()) {
963 continue;
964 }
965
966 uint64_t packageTaskStateStatsToken = outProto.start(StatsRecord::PACKAGE_TASK_STATE_STATS);
967 const auto& uidSingleStats =
968 std::get_if<UserPackageStats::UidSingleStats>(&userPackageStats.statsVariant);
969
970 uint64_t userPackageInfoToken = outProto.start(PackageTaskStateStats::USER_PACKAGE_INFO);
971 outProto.write(UserPackageInfo::USER_ID,
972 static_cast<int>(multiuser_get_user_id(userPackageStats.uid)));
973 outProto.write(UserPackageInfo::PACKAGE_NAME, userPackageStats.genericPackageName);
974 outProto.end(userPackageInfoToken);
975
976 outProto.write(PackageTaskStateStats::IO_BLOCKED_TASK_COUNT,
977 static_cast<int>(uidSingleStats->value));
978 outProto.write(PackageTaskStateStats::TOTAL_TASK_COUNT,
979 static_cast<int>(taskCount->second));
980
981 for (const auto& processSingleStats : uidSingleStats->topNProcesses) {
982 uint64_t processTaskStateStatsToken =
983 outProto.start(PackageTaskStateStats::PROCESS_TASK_STATE_STATS);
984 outProto.write(PackageTaskStateStats::ProcessTaskStateStats::COMMAND,
985 processSingleStats.comm);
986 outProto.write(PackageTaskStateStats::ProcessTaskStateStats::IO_BLOCKED_TASK_COUNT,
987 static_cast<int>(processSingleStats.value));
988 outProto.end(processTaskStateStatsToken);
989 }
990
991 outProto.end(packageTaskStateStatsToken);
992 }
993 }
994
dumpPackageMajorPageFaultsProto(const std::vector<UserPackageStats> & topNMajorFaults,ProtoOutputStream & outProto) const995 void PerformanceProfiler::dumpPackageMajorPageFaultsProto(
996 const std::vector<UserPackageStats>& topNMajorFaults, ProtoOutputStream& outProto) const {
997 for (const auto& userPackageStats : topNMajorFaults) {
998 uint64_t packageMajorPageFaultsToken =
999 outProto.start(StatsRecord::PACKAGE_MAJOR_PAGE_FAULTS);
1000 const auto& uidSingleStats =
1001 std::get_if<UserPackageStats::UidSingleStats>(&userPackageStats.statsVariant);
1002
1003 uint64_t userPackageInfoToken = outProto.start(PackageMajorPageFaults::USER_PACKAGE_INFO);
1004 outProto.write(UserPackageInfo::USER_ID,
1005 static_cast<int>(multiuser_get_user_id(userPackageStats.uid)));
1006 outProto.write(UserPackageInfo::PACKAGE_NAME, userPackageStats.genericPackageName);
1007 outProto.end(userPackageInfoToken);
1008
1009 outProto.write(PackageMajorPageFaults::MAJOR_PAGE_FAULTS_COUNT,
1010 static_cast<int>(uidSingleStats->value));
1011
1012 outProto.end(packageMajorPageFaultsToken);
1013 }
1014 }
1015
onCustomCollectionDump(int fd)1016 Result<void> PerformanceProfiler::onCustomCollectionDump(int fd) {
1017 if (fd == -1) {
1018 // Custom collection ends so clear the cache.
1019 mCustomCollection.records.clear();
1020 mCustomCollection = {
1021 .maxCacheSize = std::numeric_limits<std::size_t>::max(),
1022 .records = {},
1023 };
1024 return {};
1025 }
1026
1027 if (!WriteStringToFd(StringPrintf(kCustomCollectionTitle, std::string(75, '-').c_str(),
1028 std::string(75, '-').c_str()),
1029 fd) ||
1030 !WriteStringToFd(mCustomCollection.toString(), fd)) {
1031 return Error(FAILED_TRANSACTION) << "Failed to write custom I/O collection report.";
1032 }
1033
1034 return {};
1035 }
1036
onSystemStartup()1037 Result<void> PerformanceProfiler::onSystemStartup() {
1038 Mutex::Autolock lock(mMutex);
1039 mBoottimeCollection.records.clear();
1040 mWakeUpCollection.records.clear();
1041 return {};
1042 }
1043
onCarWatchdogServiceRegistered()1044 void PerformanceProfiler::onCarWatchdogServiceRegistered() {
1045 Mutex::Autolock lock(mMutex);
1046 mDoSendResourceUsageStats =
1047 sysprop::syncResourceUsageStatsWithCarServiceEnabled().value_or(false);
1048 }
1049
onBoottimeCollection(time_point_millis time,const wp<UidStatsCollectorInterface> & uidStatsCollector,const wp<ProcStatCollectorInterface> & procStatCollector,ResourceStats * resourceStats)1050 Result<void> PerformanceProfiler::onBoottimeCollection(
1051 time_point_millis time, const wp<UidStatsCollectorInterface>& uidStatsCollector,
1052 const wp<ProcStatCollectorInterface>& procStatCollector, ResourceStats* resourceStats) {
1053 const sp<UidStatsCollectorInterface> uidStatsCollectorSp = uidStatsCollector.promote();
1054 const sp<ProcStatCollectorInterface> procStatCollectorSp = procStatCollector.promote();
1055 auto result = checkDataCollectors(uidStatsCollectorSp, procStatCollectorSp);
1056 if (!result.ok()) {
1057 return result;
1058 }
1059 Mutex::Autolock lock(mMutex);
1060 return processLocked(time, SystemState::NORMAL_MODE, std::unordered_set<std::string>(),
1061 uidStatsCollectorSp, procStatCollectorSp, &mBoottimeCollection,
1062 resourceStats);
1063 }
1064
onPeriodicCollection(time_point_millis time,SystemState systemState,const wp<UidStatsCollectorInterface> & uidStatsCollector,const wp<ProcStatCollectorInterface> & procStatCollector,ResourceStats * resourceStats)1065 Result<void> PerformanceProfiler::onPeriodicCollection(
1066 time_point_millis time, SystemState systemState,
1067 const wp<UidStatsCollectorInterface>& uidStatsCollector,
1068 const wp<ProcStatCollectorInterface>& procStatCollector, ResourceStats* resourceStats) {
1069 const sp<UidStatsCollectorInterface> uidStatsCollectorSp = uidStatsCollector.promote();
1070 const sp<ProcStatCollectorInterface> procStatCollectorSp = procStatCollector.promote();
1071 clearExpiredSystemEventCollections(time);
1072 auto result = checkDataCollectors(uidStatsCollectorSp, procStatCollectorSp);
1073 if (!result.ok()) {
1074 return result;
1075 }
1076 Mutex::Autolock lock(mMutex);
1077 return processLocked(time, systemState, std::unordered_set<std::string>(), uidStatsCollectorSp,
1078 procStatCollectorSp, &mPeriodicCollection, resourceStats);
1079 }
1080
onUserSwitchCollection(time_point_millis time,userid_t from,userid_t to,const android::wp<UidStatsCollectorInterface> & uidStatsCollector,const android::wp<ProcStatCollectorInterface> & procStatCollector)1081 Result<void> PerformanceProfiler::onUserSwitchCollection(
1082 time_point_millis time, userid_t from, userid_t to,
1083 const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
1084 const android::wp<ProcStatCollectorInterface>& procStatCollector) {
1085 const sp<UidStatsCollectorInterface> uidStatsCollectorSp = uidStatsCollector.promote();
1086 const sp<ProcStatCollectorInterface> procStatCollectorSp = procStatCollector.promote();
1087 auto result = checkDataCollectors(uidStatsCollectorSp, procStatCollectorSp);
1088 if (!result.ok()) {
1089 return result;
1090 }
1091 Mutex::Autolock lock(mMutex);
1092 if (mUserSwitchCollections.empty() || mUserSwitchCollections.back().from != from ||
1093 mUserSwitchCollections.back().to != to) {
1094 UserSwitchCollectionInfo userSwitchCollection = {
1095 {
1096 .maxCacheSize = std::numeric_limits<std::size_t>::max(),
1097 .records = {},
1098 },
1099 .from = from,
1100 .to = to,
1101 };
1102 mUserSwitchCollections.push_back(userSwitchCollection);
1103 }
1104 if (mUserSwitchCollections.size() > mMaxUserSwitchEvents) {
1105 mUserSwitchCollections.erase(mUserSwitchCollections.begin());
1106 }
1107 return processLocked(time, SystemState::NORMAL_MODE, std::unordered_set<std::string>(),
1108 uidStatsCollectorSp, procStatCollectorSp, &mUserSwitchCollections.back(),
1109 /*resourceStats=*/nullptr);
1110 }
1111
onWakeUpCollection(time_point_millis time,const android::wp<UidStatsCollectorInterface> & uidStatsCollector,const android::wp<ProcStatCollectorInterface> & procStatCollector)1112 Result<void> PerformanceProfiler::onWakeUpCollection(
1113 time_point_millis time, const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
1114 const android::wp<ProcStatCollectorInterface>& procStatCollector) {
1115 const sp<UidStatsCollectorInterface> uidStatsCollectorSp = uidStatsCollector.promote();
1116 const sp<ProcStatCollectorInterface> procStatCollectorSp = procStatCollector.promote();
1117 auto result = checkDataCollectors(uidStatsCollectorSp, procStatCollectorSp);
1118 if (!result.ok()) {
1119 return result;
1120 }
1121 Mutex::Autolock lock(mMutex);
1122 return processLocked(time, SystemState::NORMAL_MODE, std::unordered_set<std::string>(),
1123 uidStatsCollectorSp, procStatCollectorSp, &mWakeUpCollection,
1124 /*resourceStats=*/nullptr);
1125 }
1126
onCustomCollection(time_point_millis time,SystemState systemState,const std::unordered_set<std::string> & filterPackages,const wp<UidStatsCollectorInterface> & uidStatsCollector,const wp<ProcStatCollectorInterface> & procStatCollector,ResourceStats * resourceStats)1127 Result<void> PerformanceProfiler::onCustomCollection(
1128 time_point_millis time, SystemState systemState,
1129 const std::unordered_set<std::string>& filterPackages,
1130 const wp<UidStatsCollectorInterface>& uidStatsCollector,
1131 const wp<ProcStatCollectorInterface>& procStatCollector, ResourceStats* resourceStats) {
1132 const sp<UidStatsCollectorInterface> uidStatsCollectorSp = uidStatsCollector.promote();
1133 const sp<ProcStatCollectorInterface> procStatCollectorSp = procStatCollector.promote();
1134 auto result = checkDataCollectors(uidStatsCollectorSp, procStatCollectorSp);
1135 if (!result.ok()) {
1136 return result;
1137 }
1138 Mutex::Autolock lock(mMutex);
1139 return processLocked(time, systemState, filterPackages, uidStatsCollectorSp,
1140 procStatCollectorSp, &mCustomCollection, resourceStats);
1141 }
1142
processLocked(time_point_millis time,SystemState systemState,const std::unordered_set<std::string> & filterPackages,const sp<UidStatsCollectorInterface> & uidStatsCollector,const sp<ProcStatCollectorInterface> & procStatCollector,CollectionInfo * collectionInfo,ResourceStats * resourceStats)1143 Result<void> PerformanceProfiler::processLocked(
1144 time_point_millis time, SystemState systemState,
1145 const std::unordered_set<std::string>& filterPackages,
1146 const sp<UidStatsCollectorInterface>& uidStatsCollector,
1147 const sp<ProcStatCollectorInterface>& procStatCollector, CollectionInfo* collectionInfo,
1148 ResourceStats* resourceStats) {
1149 if (collectionInfo->maxCacheSize == 0) {
1150 return Error() << "Maximum cache size cannot be 0";
1151 }
1152 PerfStatsRecord record{
1153 .collectionTimeMillis = time,
1154 };
1155 if (mIsMemoryProfilingEnabled) {
1156 record.memoryPressureLevelDurations = mMemoryPressureLevelDeltaInfo.onCollectionLocked();
1157 }
1158 bool isGarageModeActive = systemState == SystemState::GARAGE_MODE;
1159 bool shouldSendResourceUsageStats = mDoSendResourceUsageStats && (resourceStats != nullptr);
1160 std::vector<UidResourceUsageStats>* uidResourceUsageStats =
1161 shouldSendResourceUsageStats ? new std::vector<UidResourceUsageStats>() : nullptr;
1162 processProcStatLocked(procStatCollector, &record.systemSummaryStats);
1163 // The system-wide CPU time should be the same as CPU time aggregated here across all UID, so
1164 // reuse the total CPU time from SystemSummaryStat
1165 int64_t totalCpuTimeMillis = record.systemSummaryStats.totalCpuTimeMillis;
1166 record.userPackageSummaryStats.totalCpuTimeMillis = totalCpuTimeMillis;
1167 processUidStatsLocked(isGarageModeActive, totalCpuTimeMillis, filterPackages, uidStatsCollector,
1168 uidResourceUsageStats, &record.userPackageSummaryStats);
1169 // The system-wide CPU cycles are the aggregate of all the UID's CPU cycles collected during
1170 // each poll.
1171 record.systemSummaryStats.totalCpuCycles = record.userPackageSummaryStats.totalCpuCycles;
1172 if (collectionInfo->records.size() >= collectionInfo->maxCacheSize) {
1173 collectionInfo->records.erase(collectionInfo->records.begin()); // Erase the oldest record.
1174 }
1175 collectionInfo->records.push_back(record);
1176
1177 if (!shouldSendResourceUsageStats) {
1178 return {};
1179 }
1180
1181 // The durationInMillis field is set in WatchdogPerfService, which tracks the last
1182 // collection time.
1183 ResourceUsageStats resourceUsageStats = {
1184 .startTimeEpochMillis = time.time_since_epoch().count(),
1185 };
1186 resourceUsageStats.systemSummaryUsageStats =
1187 constructSystemSummaryUsageStats(isGarageModeActive, record.systemSummaryStats,
1188 record.userPackageSummaryStats);
1189 resourceUsageStats.uidResourceUsageStats = *uidResourceUsageStats;
1190
1191 resourceStats->resourceUsageStats = std::make_optional(resourceUsageStats);
1192
1193 return {};
1194 }
1195
processUidStatsLocked(bool isGarageModeActive,int64_t totalCpuTimeMillis,const std::unordered_set<std::string> & filterPackages,const sp<UidStatsCollectorInterface> & uidStatsCollector,std::vector<UidResourceUsageStats> * uidResourceUsageStats,UserPackageSummaryStats * userPackageSummaryStats)1196 void PerformanceProfiler::processUidStatsLocked(
1197 bool isGarageModeActive, int64_t totalCpuTimeMillis,
1198 const std::unordered_set<std::string>& filterPackages,
1199 const sp<UidStatsCollectorInterface>& uidStatsCollector,
1200 std::vector<UidResourceUsageStats>* uidResourceUsageStats,
1201 UserPackageSummaryStats* userPackageSummaryStats) {
1202 const std::vector<UidStats>& uidStats = uidStatsCollector->deltaStats();
1203 if (uidStats.empty()) {
1204 return;
1205 }
1206
1207 if (filterPackages.empty()) {
1208 userPackageSummaryStats->topNCpuTimes.resize(mTopNStatsPerCategory);
1209 userPackageSummaryStats->topNIoReads.resize(mTopNStatsPerCategory);
1210 userPackageSummaryStats->topNIoWrites.resize(mTopNStatsPerCategory);
1211 userPackageSummaryStats->topNIoBlocked.resize(mTopNStatsPerCategory);
1212 userPackageSummaryStats->topNMajorFaults.resize(mTopNStatsPerCategory);
1213 userPackageSummaryStats->topNMemStats.resize(mTopNStatsPerCategory);
1214 }
1215 int64_t elapsedTimeSinceBootMs = kGetElapsedTimeSinceBootMillisFunc();
1216 for (const auto& curUidStats : uidStats) {
1217 // Set the overall stats.
1218 userPackageSummaryStats->totalCpuCycles += curUidStats.procStats.cpuCycles;
1219 addUidIoStats(curUidStats.ioStats.metrics, userPackageSummaryStats->totalIoStats);
1220 userPackageSummaryStats->totalMajorFaults += curUidStats.procStats.totalMajorFaults;
1221 if (mIsMemoryProfilingEnabled) {
1222 userPackageSummaryStats->totalRssKb += curUidStats.procStats.totalRssKb;
1223 userPackageSummaryStats->totalPssKb += curUidStats.procStats.totalPssKb;
1224 }
1225
1226 // Transform |UidStats| to |UserPackageStats| for each stats variant.
1227 auto ioReadsPackageStats = UserPackageStats(MetricType::READ_BYTES, curUidStats);
1228 auto ioWritesPackageStats = UserPackageStats(MetricType::WRITE_BYTES, curUidStats);
1229 auto cpuTimePackageStats =
1230 UserPackageStats(CPU_TIME, curUidStats, mTopNStatsPerSubcategory);
1231 auto ioBlockedPackageStats =
1232 UserPackageStats(IO_BLOCKED_TASKS_COUNT, curUidStats, mTopNStatsPerSubcategory);
1233 auto majorFaultsPackageStats =
1234 UserPackageStats(MAJOR_FAULTS, curUidStats, mTopNStatsPerSubcategory);
1235 UserPackageStats memoryPackageStats;
1236 if (mIsMemoryProfilingEnabled) {
1237 memoryPackageStats =
1238 UserPackageStats(MEMORY_STATS, curUidStats, mTopNStatsPerSubcategory,
1239 mIsSmapsRollupSupported);
1240 }
1241
1242 if (filterPackages.empty()) {
1243 cacheTopNStats(ioReadsPackageStats, &userPackageSummaryStats->topNIoReads);
1244 cacheTopNStats(ioWritesPackageStats, &userPackageSummaryStats->topNIoWrites);
1245 cacheTopNStats(cpuTimePackageStats, &userPackageSummaryStats->topNCpuTimes);
1246 if (cacheTopNStats(ioBlockedPackageStats, &userPackageSummaryStats->topNIoBlocked)) {
1247 userPackageSummaryStats->taskCountByUid[ioBlockedPackageStats.uid] =
1248 curUidStats.procStats.totalTasksCount;
1249 }
1250 cacheTopNStats(majorFaultsPackageStats, &userPackageSummaryStats->topNMajorFaults);
1251 if (mIsMemoryProfilingEnabled) {
1252 cacheTopNStats(memoryPackageStats, &userPackageSummaryStats->topNMemStats);
1253 }
1254 } else if (filterPackages.count(curUidStats.genericPackageName()) != 0) {
1255 userPackageSummaryStats->topNIoReads.push_back(ioReadsPackageStats);
1256 userPackageSummaryStats->topNIoWrites.push_back(ioWritesPackageStats);
1257 userPackageSummaryStats->topNCpuTimes.push_back(cpuTimePackageStats);
1258 userPackageSummaryStats->topNIoBlocked.push_back(ioBlockedPackageStats);
1259 userPackageSummaryStats->topNMajorFaults.push_back(majorFaultsPackageStats);
1260 userPackageSummaryStats->taskCountByUid[ioBlockedPackageStats.uid] =
1261 curUidStats.procStats.totalTasksCount;
1262 if (mIsMemoryProfilingEnabled) {
1263 userPackageSummaryStats->topNMemStats.push_back(memoryPackageStats);
1264 }
1265 }
1266
1267 // A null value in uidResourceUsageStats indicates that uid resource usage stats
1268 // will not be sent to CarService. Hence, there is no need to populate it.
1269 if (uidResourceUsageStats == nullptr) {
1270 continue;
1271 }
1272
1273 PackageIdentifier packageIdentifier = {
1274 .name = curUidStats.genericPackageName(),
1275 .uid = static_cast<int32_t>(curUidStats.uid()),
1276 };
1277 int64_t uidUptimeMillis =
1278 calculateUidUptimeMillis(elapsedTimeSinceBootMs, curUidStats.procStats);
1279
1280 const auto& uidCpuStats =
1281 std::get<UserPackageStats::UidCpuStats>(cpuTimePackageStats.statsVariant);
1282 const auto& uidIoReadsStats =
1283 std::get<UserPackageStats::UidIoSingleOpStats>(ioReadsPackageStats.statsVariant);
1284 const auto& uidIoWritesStats =
1285 std::get<UserPackageStats::UidIoSingleOpStats>(ioWritesPackageStats.statsVariant);
1286
1287 UidResourceUsageStats usageStats =
1288 constructUidResourceUsageStats(std::move(packageIdentifier), uidUptimeMillis,
1289 totalCpuTimeMillis, isGarageModeActive,
1290 uidCpuStats, uidIoReadsStats,
1291 uidIoWritesStats);
1292 uidResourceUsageStats->push_back(std::move(usageStats));
1293 }
1294 if (mLastMajorFaults != 0) {
1295 int64_t increase = userPackageSummaryStats->totalMajorFaults - mLastMajorFaults;
1296 userPackageSummaryStats->majorFaultsPercentChange =
1297 (static_cast<double>(increase) / static_cast<double>(mLastMajorFaults)) * 100.0;
1298 }
1299 mLastMajorFaults = userPackageSummaryStats->totalMajorFaults;
1300
1301 const auto removeEmptyStats = [](std::vector<UserPackageStats>& userPackageStats) {
1302 for (auto it = userPackageStats.begin(); it != userPackageStats.end(); ++it) {
1303 /* std::monostate is the first alternative in the variant. When the variant is
1304 * uninitialized, the index points to this alternative.
1305 */
1306 if (it->statsVariant.index() == 0) {
1307 userPackageStats.erase(it, userPackageStats.end());
1308 break;
1309 }
1310 }
1311 };
1312 removeEmptyStats(userPackageSummaryStats->topNCpuTimes);
1313 removeEmptyStats(userPackageSummaryStats->topNIoReads);
1314 removeEmptyStats(userPackageSummaryStats->topNIoWrites);
1315 removeEmptyStats(userPackageSummaryStats->topNIoBlocked);
1316 removeEmptyStats(userPackageSummaryStats->topNMajorFaults);
1317 removeEmptyStats(userPackageSummaryStats->topNMemStats);
1318 }
1319
processProcStatLocked(const sp<ProcStatCollectorInterface> & procStatCollector,SystemSummaryStats * systemSummaryStats) const1320 void PerformanceProfiler::processProcStatLocked(
1321 const sp<ProcStatCollectorInterface>& procStatCollector,
1322 SystemSummaryStats* systemSummaryStats) const {
1323 const ProcStatInfo& procStatInfo = procStatCollector->deltaStats();
1324 systemSummaryStats->cpuIoWaitTimeMillis = procStatInfo.cpuStats.ioWaitTimeMillis;
1325 systemSummaryStats->cpuIdleTimeMillis = procStatInfo.cpuStats.idleTimeMillis;
1326 systemSummaryStats->totalCpuTimeMillis = procStatInfo.totalCpuTimeMillis();
1327 systemSummaryStats->contextSwitchesCount = procStatInfo.contextSwitchesCount;
1328 systemSummaryStats->ioBlockedProcessCount = procStatInfo.ioBlockedProcessCount;
1329 systemSummaryStats->totalProcessCount = procStatInfo.totalProcessCount();
1330 }
1331
onUserSwitchCollectionDump(int fd) const1332 Result<void> PerformanceProfiler::onUserSwitchCollectionDump(int fd) const {
1333 if (!WriteStringToFd(StringPrintf(kUserSwitchCollectionTitle, std::string(75, '-').c_str(),
1334 std::string(38, '=').c_str()),
1335 fd)) {
1336 return Error(FAILED_TRANSACTION) << "Failed to dump the user-switch collection report.";
1337 }
1338 if (!mUserSwitchCollections.empty() &&
1339 !WriteStringToFd(StringPrintf(kUserSwitchCollectionSubtitle, mUserSwitchCollections.size()),
1340 fd)) {
1341 return Error(FAILED_TRANSACTION) << "Failed to dump the user-switch collection report.";
1342 }
1343 if (mUserSwitchCollections.empty() && !WriteStringToFd(kEmptyCollectionMessage, fd)) {
1344 return Error(FAILED_TRANSACTION) << "Failed to dump the user-switch collection report.";
1345 }
1346 for (size_t i = 0; i < mUserSwitchCollections.size(); ++i) {
1347 const auto& userSwitchCollection = mUserSwitchCollections[i];
1348 if (!WriteStringToFd(StringPrintf(kUserSwitchEventTitle, i, userSwitchCollection.from,
1349 userSwitchCollection.to, std::string(26, '=').c_str()),
1350 fd) ||
1351 !WriteStringToFd(userSwitchCollection.toString(), fd)) {
1352 return Error(FAILED_TRANSACTION) << "Failed to dump the user-switch collection report.";
1353 }
1354 }
1355 return {};
1356 }
1357
setLatestPressureLevelLocked(PressureMonitorInterface::PressureLevel pressureLevel)1358 void PerformanceProfiler::PressureLevelDeltaInfo::setLatestPressureLevelLocked(
1359 PressureMonitorInterface::PressureLevel pressureLevel) {
1360 auto now = kGetElapsedTimeSinceBootMillisFunc();
1361 auto duration = now - mLatestPressureLevelElapsedRealtimeMillis;
1362 if (mPressureLevelDurations.find(pressureLevel) == mPressureLevelDurations.end()) {
1363 mPressureLevelDurations[pressureLevel] = 0ms;
1364 }
1365 mPressureLevelDurations[pressureLevel] += std::chrono::milliseconds(duration);
1366 mLatestPressureLevelElapsedRealtimeMillis = now;
1367 mLatestPressureLevel = pressureLevel;
1368 }
1369
onCollectionLocked()1370 PressureLevelDurationMap PerformanceProfiler::PressureLevelDeltaInfo::onCollectionLocked() {
1371 // Reset pressure level to trigger accounting and flushing the latest timing info to
1372 // mPressureLevelDurations.
1373 setLatestPressureLevelLocked(mLatestPressureLevel);
1374 auto durationsMap = mPressureLevelDurations;
1375 mPressureLevelDurations.clear();
1376 return durationsMap;
1377 }
1378
onPressureChanged(PressureMonitorInterface::PressureLevel pressureLevel)1379 void PerformanceProfiler::onPressureChanged(PressureMonitorInterface::PressureLevel pressureLevel) {
1380 if (!mIsMemoryProfilingEnabled) {
1381 return;
1382 }
1383 Mutex::Autolock lock(mMutex);
1384 mMemoryPressureLevelDeltaInfo.setLatestPressureLevelLocked(pressureLevel);
1385 }
1386
clearExpiredSystemEventCollections(time_point_millis now)1387 void PerformanceProfiler::clearExpiredSystemEventCollections(time_point_millis now) {
1388 Mutex::Autolock lock(mMutex);
1389 auto clearExpiredSystemEvent = [&](CollectionInfo* info) -> bool {
1390 if (info->records.empty() ||
1391 now - info->records.back().collectionTimeMillis < mSystemEventDataCacheDurationSec) {
1392 return false;
1393 }
1394 info->records.clear();
1395 return true;
1396 };
1397 if (clearExpiredSystemEvent(&mBoottimeCollection)) {
1398 ALOGI("Cleared boot-time collection stats");
1399 }
1400 if (clearExpiredSystemEvent(&mWakeUpCollection)) {
1401 ALOGI("Cleared wake-up collection stats");
1402 }
1403 if (!mUserSwitchCollections.empty() &&
1404 clearExpiredSystemEvent(&mUserSwitchCollections.front())) {
1405 mUserSwitchCollections.erase(mUserSwitchCollections.begin());
1406 ALOGI("Cleared the oldest user-switch event collection stats");
1407 }
1408 }
1409
1410 } // namespace watchdog
1411 } // namespace automotive
1412 } // namespace android
1413