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