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_PROCSTATCOLLECTOR_H_ 18 #define CPP_WATCHDOG_SERVER_SRC_PROCSTATCOLLECTOR_H_ 19 20 #include <android-base/result.h> 21 #include <utils/Mutex.h> 22 #include <utils/RefBase.h> 23 24 #include <stdint.h> 25 26 namespace android { 27 namespace automotive { 28 namespace watchdog { 29 30 constexpr const char* kProcStatPath = "/proc/stat"; 31 32 struct CpuStats { 33 int64_t userTimeMillis = 0; // Time spent in user mode. 34 int64_t niceTimeMillis = 0; // Time spent in user mode with low priority (nice). 35 int64_t sysTimeMillis = 0; // Time spent in system mode. 36 int64_t idleTimeMillis = 0; // Time spent in the idle task. 37 int64_t ioWaitTimeMillis = 0; // Time spent on context switching/waiting due to I/O operations. 38 int64_t irqTimeMillis = 0; // Time servicing interrupts. 39 int64_t softIrqTimeMillis = 0; // Time servicing soft interrupts. 40 int64_t stealTimeMillis = 0; // Stolen time (Time spent in other OS in a virtualized env). 41 int64_t guestTimeMillis = 0; // Time spent running a virtual CPU for guest OS. 42 int64_t guestNiceTimeMillis = 0; // Time spent running a niced virtual CPU for guest OS. 43 44 CpuStats& operator-=(const CpuStats& rhs) { 45 userTimeMillis -= rhs.userTimeMillis; 46 niceTimeMillis -= rhs.niceTimeMillis; 47 sysTimeMillis -= rhs.sysTimeMillis; 48 idleTimeMillis -= rhs.idleTimeMillis; 49 ioWaitTimeMillis -= rhs.ioWaitTimeMillis; 50 irqTimeMillis -= rhs.irqTimeMillis; 51 softIrqTimeMillis -= rhs.softIrqTimeMillis; 52 stealTimeMillis -= rhs.stealTimeMillis; 53 guestTimeMillis -= rhs.guestTimeMillis; 54 guestNiceTimeMillis -= rhs.guestNiceTimeMillis; 55 return *this; 56 } 57 }; 58 59 class ProcStatInfo { 60 public: ProcStatInfo()61 ProcStatInfo() : 62 cpuStats({}), 63 contextSwitchesCount(0), 64 runnableProcessCount(0), 65 ioBlockedProcessCount(0) {} ProcStatInfo(CpuStats stats,uint64_t ctxtSwitches,uint32_t runnableCnt,uint32_t ioBlockedCnt)66 ProcStatInfo(CpuStats stats, uint64_t ctxtSwitches, uint32_t runnableCnt, 67 uint32_t ioBlockedCnt) : 68 cpuStats(stats), 69 contextSwitchesCount(ctxtSwitches), 70 runnableProcessCount(runnableCnt), 71 ioBlockedProcessCount(ioBlockedCnt) {} 72 CpuStats cpuStats; 73 uint64_t contextSwitchesCount; 74 uint32_t runnableProcessCount; 75 uint32_t ioBlockedProcessCount; 76 totalCpuTimeMillis()77 int64_t totalCpuTimeMillis() const { 78 return cpuStats.userTimeMillis + cpuStats.niceTimeMillis + cpuStats.sysTimeMillis + 79 cpuStats.idleTimeMillis + cpuStats.ioWaitTimeMillis + cpuStats.irqTimeMillis + 80 cpuStats.softIrqTimeMillis + cpuStats.stealTimeMillis + cpuStats.guestTimeMillis + 81 cpuStats.guestNiceTimeMillis; 82 } totalProcessCount()83 uint32_t totalProcessCount() const { return runnableProcessCount + ioBlockedProcessCount; } 84 bool operator==(const ProcStatInfo& info) const { 85 return memcmp(&cpuStats, &info.cpuStats, sizeof(cpuStats)) == 0 && 86 runnableProcessCount == info.runnableProcessCount && 87 ioBlockedProcessCount == info.ioBlockedProcessCount; 88 } 89 ProcStatInfo& operator-=(const ProcStatInfo& rhs) { 90 cpuStats -= rhs.cpuStats; 91 /* Don't diff *ProcessCount as they are real-time values unlike |cpuStats|, which are 92 * aggregated values since system startup. 93 */ 94 return *this; 95 } 96 }; 97 98 class ProcStatCollectorInterface : public RefBase { 99 public: 100 // Initializes the collector. 101 virtual void init() = 0; 102 103 // Collects proc stat delta since the last collection. 104 virtual android::base::Result<void> collect() = 0; 105 106 /* Returns true when the proc stat file is accessible. Otherwise, returns false. 107 * Called by WatchdogPerfService and tests. 108 */ 109 virtual bool enabled() = 0; 110 111 virtual std::string filePath() = 0; 112 113 // Returns the latest stats. 114 virtual const ProcStatInfo latestStats() const = 0; 115 116 // Returns the delta of stats from the latest collection. 117 virtual const ProcStatInfo deltaStats() const = 0; 118 }; 119 120 // Collector/parser for `/proc/stat` file. 121 class ProcStatCollector final : public ProcStatCollectorInterface { 122 public: 123 explicit ProcStatCollector(const std::string& path = kProcStatPath) : kPath(path)124 kPath(path), mMillisPerClockTick(1000 / sysconf(_SC_CLK_TCK)), mLatestStats({}) {} 125 ~ProcStatCollector()126 ~ProcStatCollector() {} 127 init()128 void init() { 129 Mutex::Autolock lock(mMutex); 130 // Note: Verify proc file access outside the constructor. Otherwise, the unittests of 131 // dependent classes would call the constructor before mocking and get killed due to 132 // sepolicy violation. 133 mEnabled = access(kPath.c_str(), R_OK) == 0; 134 } 135 136 android::base::Result<void> collect(); 137 enabled()138 bool enabled() { 139 Mutex::Autolock lock(mMutex); 140 return mEnabled; 141 } 142 filePath()143 std::string filePath() { return kProcStatPath; } 144 latestStats()145 const ProcStatInfo latestStats() const { 146 Mutex::Autolock lock(mMutex); 147 return mLatestStats; 148 } 149 deltaStats()150 const ProcStatInfo deltaStats() const { 151 Mutex::Autolock lock(mMutex); 152 return mDeltaStats; 153 } 154 155 private: 156 // Reads the contents of |kPath|. 157 android::base::Result<ProcStatInfo> getProcStatLocked() const; 158 159 // Path to proc stat file. Default path is |kProcStatPath|. 160 const std::string kPath; 161 162 // Number of milliseconds per clock cycle. 163 int32_t mMillisPerClockTick; 164 165 // Makes sure only one collection is running at any given time. 166 mutable Mutex mMutex; 167 168 // True if |kPath| is accessible. 169 bool mEnabled GUARDED_BY(mMutex); 170 171 // Latest dump of CPU stats from the file at |kPath|. 172 ProcStatInfo mLatestStats GUARDED_BY(mMutex); 173 174 // Delta of CPU stats from the latest collection. 175 ProcStatInfo mDeltaStats GUARDED_BY(mMutex); 176 }; 177 178 } // namespace watchdog 179 } // namespace automotive 180 } // namespace android 181 182 #endif // CPP_WATCHDOG_SERVER_SRC_PROCSTATCOLLECTOR_H_ 183