• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef CPP_WATCHDOG_SERVER_SRC_PERFORMANCEPROFILER_H_
18 #define CPP_WATCHDOG_SERVER_SRC_PERFORMANCEPROFILER_H_
19 
20 #include "ProcDiskStatsCollector.h"
21 #include "ProcStatCollector.h"
22 #include "UidStatsCollector.h"
23 #include "WatchdogPerfService.h"
24 
25 #include <android-base/chrono_utils.h>
26 #include <android-base/result.h>
27 #include <cutils/multiuser.h>
28 #include <gtest/gtest_prod.h>
29 #include <utils/Errors.h>
30 #include <utils/Mutex.h>
31 #include <utils/RefBase.h>
32 
33 #include <ctime>
34 #include <string>
35 #include <unordered_set>
36 #include <variant>
37 #include <vector>
38 
39 namespace android {
40 namespace automotive {
41 namespace watchdog {
42 
43 // Number of periodic collection records to cache in memory.
44 constexpr int32_t kDefaultPeriodicCollectionBufferSize = 180;
45 constexpr const char kEmptyCollectionMessage[] = "No collection recorded\n";
46 
47 // Forward declaration for testing use only.
48 namespace internal {
49 
50 class PerformanceProfilerPeer;
51 
52 }  // namespace internal
53 
54 // Below classes, structs and enums should be used only by the implementation and unit tests.
55 enum ProcStatType {
56     IO_BLOCKED_TASKS_COUNT = 0,
57     MAJOR_FAULTS,
58     CPU_TIME,
59     PROC_STAT_TYPES,
60 };
61 
62 // UserPackageStats represents the user package performance stats.
63 class UserPackageStats {
64 public:
65     struct IoStatsView {
66         int64_t bytes[UID_STATES] = {0};
67         int64_t fsync[UID_STATES] = {0};
68 
totalBytesIoStatsView69         int64_t totalBytes() const {
70             return std::numeric_limits<int64_t>::max() - bytes[UidState::FOREGROUND] >
71                             bytes[UidState::BACKGROUND]
72                     ? bytes[UidState::FOREGROUND] + bytes[UidState::BACKGROUND]
73                     : std::numeric_limits<int64_t>::max();
74         }
75     };
76     struct ProcSingleStatsView {
77         uint64_t value = 0;
78         struct ProcessValue {
79             std::string comm = "";
80             uint64_t value = 0;
81         };
82         std::vector<ProcessValue> topNProcesses = {};
83     };
84     struct ProcCpuStatsView {
85         uint64_t cpuTime = 0;
86         uint64_t cpuCycles = 0;
87         struct ProcessCpuValue {
88             std::string comm = "";
89             uint64_t cpuTime = 0;
90             uint64_t cpuCycles = 0;
91         };
92         std::vector<ProcessCpuValue> topNProcesses = {};
93     };
94 
95     UserPackageStats(MetricType metricType, const UidStats& uidStats);
96     UserPackageStats(ProcStatType procStatType, const UidStats& uidStats, int topNProcessCount);
97 
98     // Class must be DefaultInsertable for std::vector<T>::resize to work
UserPackageStats()99     UserPackageStats() : uid(0), genericPackageName("") {}
100     // For unit test case only
UserPackageStats(uid_t uid,std::string genericPackageName,std::variant<std::monostate,IoStatsView,ProcSingleStatsView,ProcCpuStatsView> statsView)101     UserPackageStats(
102             uid_t uid, std::string genericPackageName,
103             std::variant<std::monostate, IoStatsView, ProcSingleStatsView, ProcCpuStatsView>
104                     statsView) :
105           uid(uid),
106           genericPackageName(std::move(genericPackageName)),
107           statsView(std::move(statsView)) {}
108 
109     // Returns the primary value of the current StatsView. If the variant has value
110     // |std::monostate|, returns 0.
111     //
112     // This value should be used to sort the StatsViews.
113     uint64_t getValue() const;
114     std::string toString(MetricType metricsType, const int64_t totalIoStats[][UID_STATES]) const;
115     std::string toString(int64_t totalValue) const;
116 
117     uid_t uid;
118     std::string genericPackageName;
119     std::variant<std::monostate, IoStatsView, ProcSingleStatsView, ProcCpuStatsView> statsView;
120 
121 private:
122     void cacheTopNProcessSingleStats(
123             ProcStatType procStatType, const UidStats& uidStats, int topNProcessCount,
124             std::vector<UserPackageStats::ProcSingleStatsView::ProcessValue>* topNProcesses);
125     void cacheTopNProcessCpuStats(
126             const UidStats& uidStats, int topNProcessCount,
127             std::vector<UserPackageStats::ProcCpuStatsView::ProcessCpuValue>* topNProcesses);
128 };
129 
130 /**
131  * User package summary performance stats collected from the `/proc/uid_io/stats`,
132  * `/proc/[pid]/stat`, `/proc/[pid]/task/[tid]/stat`, and /proc/[pid]/status` files.
133  */
134 struct UserPackageSummaryStats {
135     std::vector<UserPackageStats> topNCpuTimes = {};
136     std::vector<UserPackageStats> topNIoReads = {};
137     std::vector<UserPackageStats> topNIoWrites = {};
138     std::vector<UserPackageStats> topNIoBlocked = {};
139     std::vector<UserPackageStats> topNMajorFaults = {};
140     int64_t totalIoStats[METRIC_TYPES][UID_STATES] = {{0}};
141     std::unordered_map<uid_t, uint64_t> taskCountByUid = {};
142     int64_t totalCpuTimeMillis = 0;
143     uint64_t totalCpuCycles = 0;
144     uint64_t totalMajorFaults = 0;
145     // Percentage of increase/decrease in the major page faults since last collection.
146     double majorFaultsPercentChange = 0.0;
147     std::string toString() const;
148 };
149 
150 // TODO(b/268402964): Calculate the total CPU cycles using the per-UID BPF tool.
151 // System performance stats collected from the `/proc/stats` file.
152 struct SystemSummaryStats {
153     int64_t cpuIoWaitTimeMillis = 0;
154     int64_t cpuIdleTimeMillis = 0;
155     int64_t totalCpuTimeMillis = 0;
156     uint64_t totalCpuCycles = 0;
157     uint64_t contextSwitchesCount = 0;
158     uint32_t ioBlockedProcessCount = 0;
159     uint32_t totalProcessCount = 0;
160     std::string toString() const;
161 };
162 
163 // Performance record collected during a sampling/collection period.
164 struct PerfStatsRecord {
165     time_t time;  // Collection time.
166     SystemSummaryStats systemSummaryStats;
167     UserPackageSummaryStats userPackageSummaryStats;
168     std::string toString() const;
169 };
170 
171 // Group of performance records collected for a collection event.
172 struct CollectionInfo {
173     size_t maxCacheSize = 0;               // Maximum cache size for the collection.
174     std::vector<PerfStatsRecord> records;  // Cache of collected performance records.
175     std::string toString() const;
176 };
177 
178 // Group of performance records collected for a user switch collection event.
179 struct UserSwitchCollectionInfo : CollectionInfo {
180     userid_t from = 0;
181     userid_t to = 0;
182 };
183 
184 // PerformanceProfiler implements the I/O performance data collection module.
185 class PerformanceProfiler final : public DataProcessorInterface {
186 public:
PerformanceProfiler()187     PerformanceProfiler() :
188           mTopNStatsPerCategory(0),
189           mTopNStatsPerSubcategory(0),
190           mMaxUserSwitchEvents(0),
191           mSystemEventDataCacheDurationSec(0),
192           mBoottimeCollection({}),
193           mPeriodicCollection({}),
194           mUserSwitchCollections({}),
195           mWakeUpCollection({}),
196           mCustomCollection({}),
197           mLastMajorFaults(0),
198           mDoSendResourceUsageStats(false) {}
199 
~PerformanceProfiler()200     ~PerformanceProfiler() { terminate(); }
201 
name()202     std::string name() const override { return "PerformanceProfiler"; }
203 
204     // Implements DataProcessorInterface.
205     android::base::Result<void> onSystemStartup() override;
206 
207     void onCarWatchdogServiceRegistered() override;
208 
209     android::base::Result<void> onBoottimeCollection(
210             time_t time, const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
211             const android::wp<ProcStatCollectorInterface>& procStatCollector,
212             aidl::android::automotive::watchdog::internal::ResourceStats* resourceStats) override;
213 
214     android::base::Result<void> onWakeUpCollection(
215             time_t time, const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
216             const android::wp<ProcStatCollectorInterface>& procStatCollector) override;
217 
218     android::base::Result<void> onPeriodicCollection(
219             time_t time, SystemState systemState,
220             const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
221             const android::wp<ProcStatCollectorInterface>& procStatCollector,
222             aidl::android::automotive::watchdog::internal::ResourceStats* resourceStats) override;
223 
224     android::base::Result<void> onUserSwitchCollection(
225             time_t time, userid_t from, userid_t to,
226             const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
227             const android::wp<ProcStatCollectorInterface>& procStatCollector) override;
228 
229     android::base::Result<void> onCustomCollection(
230             time_t time, SystemState systemState,
231             const std::unordered_set<std::string>& filterPackages,
232             const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
233             const android::wp<ProcStatCollectorInterface>& procStatCollector,
234             aidl::android::automotive::watchdog::internal::ResourceStats* resourceStats) override;
235 
onPeriodicMonitor(time_t time,const android::wp<ProcDiskStatsCollectorInterface> & procDiskStatsCollector,const std::function<void ()> & alertHandler)236     android::base::Result<void> onPeriodicMonitor(
237             [[maybe_unused]] time_t time,
238             [[maybe_unused]] const android::wp<ProcDiskStatsCollectorInterface>&
239                     procDiskStatsCollector,
240             [[maybe_unused]] const std::function<void()>& alertHandler) override {
241         // No monitoring done here as this DataProcessor only collects I/O performance records.
242         return {};
243     }
244 
245     android::base::Result<void> onDump(int fd) const override;
246 
247     android::base::Result<void> onCustomCollectionDump(int fd) override;
248 
249 protected:
250     android::base::Result<void> init();
251 
252     // Clears in-memory cache.
253     void terminate();
254 
255 private:
256     // Processes the collected data.
257     android::base::Result<void> processLocked(
258             time_t time, SystemState systemState,
259             const std::unordered_set<std::string>& filterPackages,
260             const android::sp<UidStatsCollectorInterface>& uidStatsCollector,
261             const android::sp<ProcStatCollectorInterface>& procStatCollector,
262             CollectionInfo* collectionInfo,
263             aidl::android::automotive::watchdog::internal::ResourceStats* resourceStats);
264 
265     // Processes per-UID performance data.
266     void processUidStatsLocked(const std::unordered_set<std::string>& filterPackages,
267                                const android::sp<UidStatsCollectorInterface>& uidStatsCollector,
268                                UserPackageSummaryStats* userPackageSummaryStats);
269 
270     // Processes system performance data from the `/proc/stats` file.
271     void processProcStatLocked(const android::sp<ProcStatCollectorInterface>& procStatCollector,
272                                SystemSummaryStats* systemSummaryStats) const;
273 
274     // Dump the user switch collection
275     android::base::Result<void> onUserSwitchCollectionDump(int fd) const;
276 
277     void clearExpiredSystemEventCollections(time_t now);
278 
279     // Top N per-UID stats per category.
280     int mTopNStatsPerCategory;
281 
282     // Top N per-process stats per subcategory.
283     int mTopNStatsPerSubcategory;
284 
285     // Max amount of user switch events cached in |mUserSwitchCollections|.
286     size_t mMaxUserSwitchEvents;
287 
288     // Amount of seconds before a system event's cache is cleared.
289     std::chrono::seconds mSystemEventDataCacheDurationSec;
290 
291     // Makes sure only one collection is running at any given time.
292     mutable Mutex mMutex;
293 
294     // Info for the boot-time collection event. The cache is persisted until system shutdown/reboot
295     // or a wake-up collection occurs.
296     CollectionInfo mBoottimeCollection GUARDED_BY(mMutex);
297 
298     // Info for the periodic collection event. The cache size is limited by
299     // |ro.carwatchdog.periodic_collection_buffer_size|.
300     CollectionInfo mPeriodicCollection GUARDED_BY(mMutex);
301 
302     // Cache for user switch collection events. Events are cached from oldest to newest.
303     std::vector<UserSwitchCollectionInfo> mUserSwitchCollections GUARDED_BY(mMutex);
304 
305     // Info for the wake-up collection event. Only the latest wake-up collection is cached.
306     CollectionInfo mWakeUpCollection GUARDED_BY(mMutex);
307 
308     // Info for the custom collection event. The info is cleared at the end of every custom
309     // collection.
310     CollectionInfo mCustomCollection GUARDED_BY(mMutex);
311 
312     // Major faults delta from last collection. Useful when calculating the percentage change in
313     // major faults since last collection.
314     uint64_t mLastMajorFaults GUARDED_BY(mMutex);
315 
316     // Enables the sending of resource usage stats to CarService.
317     bool mDoSendResourceUsageStats GUARDED_BY(mMutex);
318 
319     friend class WatchdogPerfService;
320 
321     // For unit tests.
322     friend class internal::PerformanceProfilerPeer;
323 };
324 
325 }  // namespace watchdog
326 }  // namespace automotive
327 }  // namespace android
328 
329 #endif  //  CPP_WATCHDOG_SERVER_SRC_PERFORMANCEPROFILER_H_
330