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_UIDIOSTATS_H_ 18 #define CPP_WATCHDOG_SERVER_SRC_UIDIOSTATS_H_ 19 20 #include <android-base/result.h> 21 #include <android-base/stringprintf.h> 22 #include <utils/Mutex.h> 23 #include <utils/RefBase.h> 24 25 #include <stdint.h> 26 27 #include <string> 28 #include <unordered_map> 29 30 namespace android { 31 namespace automotive { 32 namespace watchdog { 33 34 constexpr const char* kUidIoStatsPath = "/proc/uid_io/stats"; 35 36 enum UidState { 37 FOREGROUND = 0, 38 BACKGROUND, 39 UID_STATES, 40 }; 41 42 enum MetricType { 43 READ_BYTES = 0, // bytes read (from storage layer) 44 WRITE_BYTES, // bytes written (to storage layer) 45 FSYNC_COUNT, // number of fsync syscalls 46 METRIC_TYPES, 47 }; 48 49 class IoUsage { 50 public: IoUsage()51 IoUsage() : metrics{{0}} {}; IoUsage(int64_t fgRdBytes,int64_t bgRdBytes,int64_t fgWrBytes,int64_t bgWrBytes,int64_t fgFsync,int64_t bgFsync)52 IoUsage(int64_t fgRdBytes, int64_t bgRdBytes, int64_t fgWrBytes, int64_t bgWrBytes, 53 int64_t fgFsync, int64_t bgFsync) { 54 metrics[READ_BYTES][FOREGROUND] = fgRdBytes; 55 metrics[READ_BYTES][BACKGROUND] = bgRdBytes; 56 metrics[WRITE_BYTES][FOREGROUND] = fgWrBytes; 57 metrics[WRITE_BYTES][BACKGROUND] = bgWrBytes; 58 metrics[FSYNC_COUNT][FOREGROUND] = fgFsync; 59 metrics[FSYNC_COUNT][BACKGROUND] = bgFsync; 60 } 61 IoUsage& operator-=(const IoUsage& rhs); 62 bool operator==(const IoUsage& usage) const { 63 return memcmp(&metrics, &usage.metrics, sizeof(metrics)) == 0; 64 } sumReadBytes()65 int64_t sumReadBytes() const { 66 const auto& [fgBytes, bgBytes] = 67 std::tuple(metrics[READ_BYTES][FOREGROUND], metrics[READ_BYTES][BACKGROUND]); 68 return (std::numeric_limits<int64_t>::max() - fgBytes) > bgBytes 69 ? (fgBytes + bgBytes) 70 : std::numeric_limits<int64_t>::max(); 71 } sumWriteBytes()72 int64_t sumWriteBytes() const { 73 const auto& [fgBytes, bgBytes] = 74 std::tuple(metrics[WRITE_BYTES][FOREGROUND], metrics[WRITE_BYTES][BACKGROUND]); 75 return (std::numeric_limits<int64_t>::max() - fgBytes) > bgBytes 76 ? (fgBytes + bgBytes) 77 : std::numeric_limits<int64_t>::max(); 78 } 79 bool isZero() const; 80 std::string toString() const; 81 int64_t metrics[METRIC_TYPES][UID_STATES]; 82 }; 83 84 struct UidIoUsage { 85 uid_t uid = 0; // Linux user id. 86 IoUsage ios = {}; 87 UidIoUsage& operator-=(const UidIoUsage& rhs) { 88 ios -= rhs.ios; 89 return *this; 90 } 91 bool operator==(const UidIoUsage& rhs) const { return uid == rhs.uid && ios == rhs.ios; } toStringUidIoUsage92 std::string toString() const { 93 return android::base::StringPrintf("Uid: %d, Usage: {%s}", uid, ios.toString().c_str()); 94 } 95 }; 96 97 class UidIoStats : public RefBase { 98 public: 99 explicit UidIoStats(const std::string& path = kUidIoStatsPath) : 100 kEnabled(!access(path.c_str(), R_OK)), kPath(path) {} 101 ~UidIoStats()102 virtual ~UidIoStats() {} 103 104 // Collects the per-UID I/O usage. 105 virtual android::base::Result<void> collect(); 106 latestStats()107 virtual const std::unordered_map<uid_t, UidIoUsage> latestStats() const { 108 Mutex::Autolock lock(mMutex); 109 return mLatestUidIoUsages; 110 } 111 deltaStats()112 virtual const std::unordered_map<uid_t, UidIoUsage> deltaStats() const { 113 Mutex::Autolock lock(mMutex); 114 return mDeltaUidIoUsages; 115 } 116 117 // Returns true when the uid_io stats file is accessible. Otherwise, returns false. 118 // Called by IoPerfCollection and tests. enabled()119 virtual bool enabled() { return kEnabled; } 120 filePath()121 virtual std::string filePath() { return kPath; } 122 123 private: 124 // Reads the contents of |kPath|. 125 android::base::Result<std::unordered_map<uid_t, UidIoUsage>> getUidIoUsagesLocked() const; 126 127 // Makes sure only one collection is running at any given time. 128 mutable Mutex mMutex; 129 130 // Latest dump from the file at |kPath|. 131 std::unordered_map<uid_t, UidIoUsage> mLatestUidIoUsages GUARDED_BY(mMutex); 132 133 // Delta of per-UID I/O usage since last before collection. 134 std::unordered_map<uid_t, UidIoUsage> mDeltaUidIoUsages GUARDED_BY(mMutex); 135 136 // True if kPath is accessible. 137 const bool kEnabled; 138 139 // Path to uid_io stats file. Default path is |kUidIoStatsPath|. 140 const std::string kPath; 141 }; 142 143 } // namespace watchdog 144 } // namespace automotive 145 } // namespace android 146 147 #endif // CPP_WATCHDOG_SERVER_SRC_UIDIOSTATS_H_ 148