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 #pragma once 18 19 #include <android-base/result.h> 20 #include <android-base/stringprintf.h> 21 #include <gtest/gtest_prod.h> 22 #include <meminfo/procmeminfo.h> 23 #include <utils/Mutex.h> 24 #include <utils/RefBase.h> 25 26 #include <android_car_feature.h> 27 #include <inttypes.h> 28 #include <stdint.h> 29 #include <unistd.h> 30 31 #include <string> 32 #include <unordered_map> 33 #include <vector> 34 35 namespace android { 36 namespace automotive { 37 namespace watchdog { 38 39 using ::android::base::StringPrintf; 40 41 #define PID_FOR_INIT 1 42 43 constexpr const char kProcDirPath[] = "/proc"; 44 constexpr const char kStatFileFormat[] = "/%" PRIu32 "/stat"; 45 constexpr const char kTaskDirFormat[] = "/%" PRIu32 "/task"; 46 constexpr const char kStatusFileFormat[] = "/%" PRIu32 "/status"; 47 constexpr const char kSmapsRollupFileFormat[] = "/%" PRIu32 "/smaps_rollup"; 48 constexpr const char kStatmFileFormat[] = "/%" PRIu32 "/statm"; 49 constexpr const char kTimeInStateFileFormat[] = "/%" PRIu32 "/time_in_state"; 50 51 /** 52 * Per-pid/tid stats. 53 * 54 * The int64_t type is used due to AIDL limitations representing long field values. 55 */ 56 struct PidStat { 57 std::string comm = ""; 58 std::string state = ""; 59 int64_t startTimeMillis = 0; 60 int64_t cpuTimeMillis = 0; 61 uint64_t majorFaults = 0; 62 }; 63 64 // Per-process stats. 65 struct ProcessStats { 66 std::string comm = ""; 67 int64_t startTimeMillis = 0; // Useful when identifying PID reuse 68 int64_t cpuTimeMillis = 0; 69 // Stats in below fields are aggregated across all threads 70 uint64_t totalCpuCycles = 0; 71 uint64_t totalMajorFaults = 0; 72 int totalTasksCount = 0; 73 int ioBlockedTasksCount = 0; 74 std::unordered_map<pid_t, uint64_t> cpuCyclesByTid = {}; 75 uint64_t rssKb = 0; 76 /** 77 * PSS/SwapPss will be missing when the smaps_rollup file is not supported or missing for 78 * a process. In such cases, use RSS to rank the processes by memory usage. 79 */ 80 uint64_t pssKb = 0; 81 /** 82 * Unique set size is the portion of memory unique (private) to the process. Unshared memory 83 * is reported as USS. 84 * 85 * PSS - USS = Proportional portion of memory shared with one or more process. 86 * RSS - USS = Total portion of memory shared with one or more process. 87 */ 88 uint64_t ussKb = 0; 89 uint64_t swapPssKb = 0; 90 std::string toString() const; 91 }; 92 93 // Per-UID stats. 94 struct UidProcStats { 95 int64_t cpuTimeMillis = 0; 96 uint64_t cpuCycles = 0; 97 uint64_t totalMajorFaults = 0; 98 int totalTasksCount = 0; 99 int ioBlockedTasksCount = 0; 100 /** 101 * When smaps_rollup is supported by the Kernel, totalPssKb will be populated. When this 102 * feature is not supported, use totalRssKb to rank the UIDs. 103 * 104 * totalRssKb counts total shared memory from each of the processes. Thus leading to counting 105 * the same portion of memory more than once: 106 * 107 * For example, if N processes share X amount of memory and a subset of the processes (say M) 108 * belong to same UID, then 109 * 1. totalRssKb across all UIDs += Unique memory for N processes + (N * X). 110 * 2. totalRssKb for the UID += Unique memory for M processes + (M * X). 111 */ 112 uint64_t totalRssKb = 0; 113 uint64_t totalPssKb = 0; 114 // TODO(b/333212872): Handles totalUssKb, totalSwapPssKb calculation logic here. 115 std::unordered_map<pid_t, ProcessStats> processStatsByPid = {}; 116 std::string toString() const; 117 }; 118 119 /** 120 * Collector/parser for `/proc/[pid]/stat`, `/proc/[pid]/task/[tid]/stat` and /proc/[pid]/status` 121 * files. 122 */ 123 class UidProcStatsCollectorInterface : public RefBase { 124 public: 125 // Initializes the collector. 126 virtual void init() = 0; 127 // Collects the per-uid stats from /proc directory. 128 virtual android::base::Result<void> collect() = 0; 129 // Returns the latest per-uid process stats. 130 virtual const std::unordered_map<uid_t, UidProcStats> latestStats() const = 0; 131 // Returns the delta of per-uid process stats since the last before collection. 132 virtual const std::unordered_map<uid_t, UidProcStats> deltaStats() const = 0; 133 // Returns true only when the /proc files for the init process are accessible. 134 virtual bool enabled() const = 0; 135 // Returns the /proc files common ancestor directory path. 136 virtual const std::string dirPath() const = 0; 137 }; 138 139 class UidProcStatsCollector final : public UidProcStatsCollectorInterface { 140 public: 141 // TODO(b/333722043): Once carwatchdogd has sys_ptrace capability, set mIsSmapsRollupSupported 142 // field from `android::meminfo::IsSmapsRollupSupported()`. 143 // Disabling smaps_rollup support because this file cannot be read without sys_ptrace 144 // capability. UidProcStatsCollector()145 UidProcStatsCollector() : 146 UidProcStatsCollector(kProcDirPath, /*isSmapsRollupSupported=*/false) {} 147 // Used by tests. 148 UidProcStatsCollector(const std::string& path, bool isSmapsRollupSupported); 149 ~UidProcStatsCollector()150 ~UidProcStatsCollector() {} 151 152 void init() override; 153 154 android::base::Result<void> collect() override; 155 latestStats()156 const std::unordered_map<uid_t, UidProcStats> latestStats() const { 157 Mutex::Autolock lock(mMutex); 158 return mLatestStats; 159 } 160 deltaStats()161 const std::unordered_map<uid_t, UidProcStats> deltaStats() const { 162 Mutex::Autolock lock(mMutex); 163 return mDeltaStats; 164 } 165 enabled()166 bool enabled() const { 167 Mutex::Autolock lock(mMutex); 168 return mIsEnabled; 169 } 170 dirPath()171 const std::string dirPath() const { return mPath; } 172 173 static android::base::Result<PidStat> readStatFileForPid(pid_t pid); 174 175 static android::base::Result<std::tuple<uid_t, pid_t>> readPidStatusFileForPid(pid_t pid); 176 177 private: 178 android::base::Result<std::unordered_map<uid_t, UidProcStats>> readUidProcStatsLocked() const; 179 180 /** 181 * Reads the contents of the below files: 182 * 1. Pid stat file at |mPath| + |kStatFileFormat| 183 * 2. Aggregated per-process status at |mPath| + |kStatusFileFormat| 184 * 3. Tid stat file at |mPath| + |kTaskDirFormat| + |kStatFileFormat| 185 */ 186 android::base::Result<std::tuple<uid_t, ProcessStats>> readProcessStatsLocked(pid_t pid) const; 187 188 /** 189 * Reads the smaps rollup file and populates the ProcessStats pointer with info for the given 190 * pid. 191 * Returns true and updates the out pointer only when the read is successful. 192 * Returns false when either the smaps_rollup file is not supported or not available for 193 * the process. When the process terminates while reading, the file won't be available. 194 */ 195 bool readSmapsRollup(pid_t pid, ProcessStats* processStatsOut) const; 196 197 size_t mPageSizeKb; 198 199 // Tracks memory profiling feature flag. 200 bool mIsMemoryProfilingEnabled; 201 202 // Tracks smaps rollup support in the Kernel. 203 bool mIsSmapsRollupSupported; 204 205 // Number of milliseconds per clock cycle. 206 int32_t mMillisPerClockTick; 207 208 /** 209 * Proc directory path. Default value is |kProcDirPath|. 210 * 211 * Updated by tests to point to a different location when needed. 212 */ 213 std::string mPath; 214 215 // Makes sure only one collection is running at any given time. 216 mutable Mutex mMutex; 217 218 /** 219 * True if the below files are accessible: 220 * 1. Pid stat file at |mPath| + |kStatFileFormat| 221 * 2. Tid stat file at |mPath| + |kTaskDirFormat| + |kStatFileFormat| 222 * 3. Pid status file at |mPath| + |kStatusFileFormat| 223 * 4. Pid statm file at |mPath| + |kStatmFileFormat| 224 * 225 * Otherwise, set to false. 226 */ 227 bool mIsEnabled GUARDED_BY(mMutex); 228 229 /** 230 * True if the tid time_in_state file at |mPath| + |kTaskDirFormat| + |kTimeInStateFileFormat| 231 * is available. 232 */ 233 bool mIsTimeInStateEnabled GUARDED_BY(mMutex); 234 235 // Latest dump of per-UID stats. 236 std::unordered_map<uid_t, UidProcStats> mLatestStats GUARDED_BY(mMutex); 237 238 // Latest delta of per-uid stat 239 std::unordered_map<uid_t, UidProcStats> mDeltaStats GUARDED_BY(mMutex); 240 241 FRIEND_TEST(PerformanceProfilerTest, TestValidProcPidContents); 242 FRIEND_TEST(UidProcStatsCollectorTest, TestValidStatFiles); 243 FRIEND_TEST(UidProcStatsCollectorTest, TestHandlesProcessTerminationBetweenScanningAndParsing); 244 FRIEND_TEST(UidProcStatsCollectorTest, TestHandlesPidTidReuse); 245 }; 246 247 } // namespace watchdog 248 } // namespace automotive 249 } // namespace android 250