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