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