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