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