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_IOPERFCOLLECTION_H_
18 #define CPP_WATCHDOG_SERVER_SRC_IOPERFCOLLECTION_H_
19 
20 #include "ProcDiskStats.h"
21 #include "ProcStat.h"
22 #include "UidStatsCollector.h"
23 #include "WatchdogPerfService.h"
24 
25 #include <android-base/result.h>
26 #include <cutils/multiuser.h>
27 #include <gtest/gtest_prod.h>
28 #include <utils/Errors.h>
29 #include <utils/Mutex.h>
30 #include <utils/RefBase.h>
31 
32 #include <ctime>
33 #include <string>
34 #include <unordered_set>
35 #include <variant>
36 #include <vector>
37 
38 namespace android {
39 namespace automotive {
40 namespace watchdog {
41 
42 // Number of periodic collection records to cache in memory.
43 constexpr int32_t kDefaultPeriodicCollectionBufferSize = 180;
44 constexpr const char kEmptyCollectionMessage[] = "No collection recorded\n";
45 
46 // Forward declaration for testing use only.
47 namespace internal {
48 
49 class IoPerfCollectionPeer;
50 
51 }  // namespace internal
52 
53 // Below structs should be used only by the implementation and unit tests.
54 /**
55  * Struct to represent user package performance stats.
56  */
57 struct UserPackageStats {
58     struct IoStats {
59         int64_t bytes[UID_STATES] = {0};
60         int64_t fsync[UID_STATES] = {0};
61 
totalBytesUserPackageStats::IoStats62         int64_t totalBytes() const {
63             return std::numeric_limits<int64_t>::max() - bytes[UidState::FOREGROUND] >
64                             bytes[UidState::BACKGROUND]
65                     ? bytes[UidState::FOREGROUND] + bytes[UidState::BACKGROUND]
66                     : std::numeric_limits<int64_t>::max();
67         }
68     };
69     struct ProcStats {
70         uint64_t count = 0;
71         struct ProcessCount {
72             std::string comm = "";
73             uint64_t count = 0;
74         };
75         std::vector<ProcessCount> topNProcesses = {};
76     };
77     uid_t uid = 0;
78     std::string genericPackageName = "";
79     std::variant<std::monostate, IoStats, ProcStats> stats;
80     std::string toString(MetricType metricsType, const int64_t totalIoStats[][UID_STATES]) const;
81     std::string toString(int64_t count) const;
82 };
83 
84 /**
85  * User package summary performance stats collected from the `/proc/uid_io/stats`,
86  * `/proc/[pid]/stat`, `/proc/[pid]/task/[tid]/stat`, and /proc/[pid]/status` files.
87  */
88 struct UserPackageSummaryStats {
89     std::vector<UserPackageStats> topNIoReads = {};
90     std::vector<UserPackageStats> topNIoWrites = {};
91     std::vector<UserPackageStats> topNIoBlocked = {};
92     std::vector<UserPackageStats> topNMajorFaults = {};
93     int64_t totalIoStats[METRIC_TYPES][UID_STATES] = {{0}};
94     std::unordered_map<uid_t, uint64_t> taskCountByUid = {};
95     uint64_t totalMajorFaults = 0;
96     // Percentage of increase/decrease in the major page faults since last collection.
97     double majorFaultsPercentChange = 0.0;
98     std::string toString() const;
99 };
100 
101 // System performance stats collected from the `/proc/stats` file.
102 struct SystemSummaryStats {
103     uint64_t cpuIoWaitTime = 0;
104     uint64_t totalCpuTime = 0;
105     uint32_t ioBlockedProcessCount = 0;
106     uint32_t totalProcessCount = 0;
107     std::string toString() const;
108 };
109 
110 // Performance record collected during a sampling/collection period.
111 struct PerfStatsRecord {
112     time_t time;  // Collection time.
113     SystemSummaryStats systemSummaryStats;
114     UserPackageSummaryStats userPackageSummaryStats;
115     std::string toString() const;
116 };
117 
118 // Group of performance records collected for a collection event.
119 struct CollectionInfo {
120     size_t maxCacheSize = 0;               // Maximum cache size for the collection.
121     std::vector<PerfStatsRecord> records;  // Cache of collected performance records.
122     std::string toString() const;
123 };
124 
125 // IoPerfCollection implements the I/O performance data collection module.
126 class IoPerfCollection : public IDataProcessorInterface {
127 public:
IoPerfCollection()128     IoPerfCollection() :
129           mTopNStatsPerCategory(0),
130           mTopNStatsPerSubcategory(0),
131           mBoottimeCollection({}),
132           mPeriodicCollection({}),
133           mCustomCollection({}),
134           mLastMajorFaults(0) {}
135 
~IoPerfCollection()136     ~IoPerfCollection() { terminate(); }
137 
name()138     std::string name() const override { return "IoPerfCollection"; }
139 
140     // Implements IDataProcessorInterface.
141     android::base::Result<void> onBoottimeCollection(
142             time_t time, const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
143             const android::wp<ProcStat>& procStat) override;
144 
145     android::base::Result<void> onPeriodicCollection(
146             time_t time, SystemState systemState,
147             const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
148             const android::wp<ProcStat>& procStat) override;
149 
150     android::base::Result<void> onCustomCollection(
151             time_t time, SystemState systemState,
152             const std::unordered_set<std::string>& filterPackages,
153             const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
154             const android::wp<ProcStat>& procStat) override;
155 
156     android::base::Result<void> onPeriodicMonitor(
157             [[maybe_unused]] time_t time,
158             [[maybe_unused]] const android::wp<IProcDiskStatsInterface>& procDiskStats,
159             [[maybe_unused]] const std::function<void()>& alertHandler) override {
160         // No monitoring done here as this DataProcessor only collects I/O performance records.
161         return {};
162     }
163 
164     android::base::Result<void> onDump(int fd) const override;
165 
166     android::base::Result<void> onCustomCollectionDump(int fd) override;
167 
168 protected:
169     android::base::Result<void> init();
170 
171     // Clears in-memory cache.
172     void terminate();
173 
174 private:
175     // Processes the collected data.
176     android::base::Result<void> processLocked(
177             time_t time, const std::unordered_set<std::string>& filterPackages,
178             const android::sp<UidStatsCollectorInterface>& uidStatsCollector,
179             const android::sp<ProcStat>& procStat, CollectionInfo* collectionInfo);
180 
181     // Processes per-UID performance data.
182     void processUidStatsLocked(const std::unordered_set<std::string>& filterPackages,
183                                const android::sp<UidStatsCollectorInterface>& uidStatsCollector,
184                                UserPackageSummaryStats* userPackageSummaryStats);
185 
186     // Processes system performance data from the `/proc/stats` file.
187     void processProcStatLocked(const android::sp<ProcStat>& procStat,
188                                SystemSummaryStats* systemSummaryStats) const;
189 
190     // Top N per-UID stats per category.
191     int mTopNStatsPerCategory;
192 
193     // Top N per-process stats per subcategory.
194     int mTopNStatsPerSubcategory;
195 
196     // Makes sure only one collection is running at any given time.
197     mutable Mutex mMutex;
198 
199     // Info for the boot-time collection event. The cache is persisted until system shutdown/reboot.
200     CollectionInfo mBoottimeCollection GUARDED_BY(mMutex);
201 
202     /**
203      * Info for the periodic collection event. The cache size is limited by
204      * |ro.carwatchdog.periodic_collection_buffer_size|.
205      */
206     CollectionInfo mPeriodicCollection GUARDED_BY(mMutex);
207 
208     /**
209      * Info for the custom collection event. The info is cleared at the end of every custom
210      * collection.
211      */
212     CollectionInfo mCustomCollection GUARDED_BY(mMutex);
213 
214     /**
215      * Major faults delta from last collection. Useful when calculating the percentage change in
216      * major faults since last collection.
217      */
218     uint64_t mLastMajorFaults GUARDED_BY(mMutex);
219 
220     friend class WatchdogPerfService;
221 
222     // For unit tests.
223     friend class internal::IoPerfCollectionPeer;
224 };
225 
226 }  // namespace watchdog
227 }  // namespace automotive
228 }  // namespace android
229 
230 #endif  //  CPP_WATCHDOG_SERVER_SRC_IOPERFCOLLECTION_H_
231