1 /* 2 * Copyright (C) 2021 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 HARDWARE_GOOGLE_PIXEL_PIXELSTATS_MMMETRICSREPORTER_H 18 #define HARDWARE_GOOGLE_PIXEL_PIXELSTATS_MMMETRICSREPORTER_H 19 20 #include <map> 21 #include <string> 22 23 #include <aidl/android/frameworks/stats/IStats.h> 24 #include <hardware/google/pixel/pixelstats/pixelatoms.pb.h> 25 26 namespace android { 27 namespace hardware { 28 namespace google { 29 namespace pixel { 30 31 using aidl::android::frameworks::stats::IStats; 32 using aidl::android::frameworks::stats::VendorAtomValue; 33 34 /** 35 * A class to upload Pixel MM health metrics 36 */ 37 class MmMetricsReporter { 38 public: 39 // Define the enum based on the group range names 40 enum OomScoreAdjGroup : int32_t { 41 OOMR_950 = 0, 42 OOMR_900, 43 OOMR_850, 44 OOMR_800, 45 OOMR_750, 46 OOMR_700, 47 OOMR_650, 48 OOMR_600, 49 OOMR_550, 50 OOMR_500, 51 OOMR_450, 52 OOMR_400, 53 OOMR_350, 54 OOMR_300, 55 OOMR_250, 56 OOMR_200, 57 OOMS_200, 58 OOMR_150, 59 OOMR_100, 60 OOMR_050, 61 OOMR_000, 62 OOMS_000, 63 OOMR_NEGATIVE, 64 OOM_NUM_OF_GROUPS, 65 }; 66 67 struct OomGroupMemUsage { 68 OomScoreAdjGroup oom_group; // the diemsion field 69 int64_t nr_task; 70 int64_t file_rss_kb; 71 int64_t anon_rss_kb; 72 int64_t pgtable_kb; 73 int64_t swap_ents_kb; 74 int64_t shmem_rss_kb; 75 }; 76 77 MmMetricsReporter(); 78 void aggregatePixelMmMetricsPer5Min(); 79 void logPixelMmMetricsPerHour(const std::shared_ptr<IStats> &stats_client); 80 void logPixelMmMetricsPerDay(const std::shared_ptr<IStats> &stats_client); 81 void logGcmaPerDay(const std::shared_ptr<IStats> &stats_client); 82 void logGcmaPerHour(const std::shared_ptr<IStats> &stats_client); 83 void logMmProcessUsageByOomGroupSnapshot(const std::shared_ptr<IStats> &stats_client); 84 void logCmaStatus(const std::shared_ptr<IStats> &stats_client); 85 std::vector<VendorAtomValue> genPixelMmMetricsPerHour(); 86 std::vector<VendorAtomValue> genPixelMmMetricsPerDay(); 87 bool readMmProcessUsageByOomGroup(std::vector<OomGroupMemUsage> *ogusage); 88 std::vector<VendorAtomValue> genMmProcessUsageByOomGroupSnapshotAtom( 89 const OomGroupMemUsage &data); 90 std::vector<VendorAtomValue> readAndGenGcmaPerHour(); 91 std::vector<VendorAtomValue> readAndGenGcmaPerDay(); ~MmMetricsReporter()92 virtual ~MmMetricsReporter() {} 93 94 private: 95 struct MmMetricsInfo { 96 std::string name; 97 int atom_key; 98 bool update_diff; 99 }; 100 101 /* 102 * Similar to MmMetricsInfo, but /proc/stat output is an array rather 103 * than one single value. So we need an offset to get the specific value 104 * in the array. 105 * special: offset = -1 means to get the sum of the elements in the array. 106 */ 107 struct ProcStatMetricsInfo { 108 std::string name; 109 int offset; 110 int atom_key; 111 bool update_diff; 112 }; 113 114 enum CmaType { 115 FARAWIMG = 0, 116 FAIMG = 1, 117 FATPU = 2, 118 FAPREV = 3, 119 VFRAME = 4, 120 VSTREAM = 5, 121 }; 122 123 static const std::vector<MmMetricsInfo> kMmMetricsPerHourInfo; 124 static const std::vector<MmMetricsInfo> kMeminfoInfo; 125 static const std::vector<MmMetricsInfo> kMmMetricsPerDayInfo; 126 static const std::vector<ProcStatMetricsInfo> kProcStatInfo; 127 static const std::vector<MmMetricsInfo> kCmaStatusInfo; 128 static const std::vector<MmMetricsInfo> kCmaStatusExtInfo; 129 130 // raw PSI 131 static constexpr const char *kPsiBasePath = "/proc/pressure"; 132 static constexpr const char *kPsiTypes[3] = {"cpu", "io", "memory"}; 133 static constexpr const char *kPsiCategories[2] = {"full", "some"}; 134 static constexpr const char *kPsiMetricNames[4] = {"avg10", "avg60", "avg300", "total"}; 135 static constexpr int kPsiNumFiles = sizeof(kPsiTypes) / sizeof(kPsiTypes[0]); 136 static constexpr int kPsiNumCategories = sizeof(kPsiCategories) / sizeof(kPsiCategories[0]); 137 // number of statistics metric names (one total and several timed averages, per category) 138 static constexpr int kPsiNumNames = sizeof(kPsiMetricNames) / sizeof(kPsiMetricNames[0]); 139 140 // Though cpu has no 'full' category, here we assume it has 141 // So, all file will contain 2 lines x 4 metrics per line = 8 metrics total. 142 static constexpr int kPsiMetricsPerFile = kPsiNumCategories * kPsiNumNames; 143 144 // we have 1 'total' and all others 'averages' per category 145 // "total" metrics are already accumulative and thus no aggregation is needed. 146 // raw values are used. 147 static constexpr int kPsiNumTotals = 1; 148 static constexpr int kPsiNumAvgs = kPsiNumNames - kPsiNumTotals; 149 150 // -1 since "cpu" type has no "full" category 151 static constexpr int kPsiNumAllCategories = kPsiNumFiles * kPsiNumCategories - 1; 152 153 // number of raw metrics: total and avgs, and the combined all: added together. 154 static constexpr int kPsiNumAllTotals = kPsiNumAllCategories * kPsiNumTotals; 155 static constexpr int kPsiNumAllAvgs = kPsiNumAllCategories * kPsiNumAvgs; 156 static constexpr int kPsiNumAllMetrics = kPsiNumAllTotals + kPsiNumAllAvgs; 157 158 // aggregated into (1) min, (2) max, (3) average (internally the sum is kept than the average) 159 static constexpr int kPsiNumOfAggregatedType = 3; 160 161 // # of upload metrics will have a aggregation factor on all 'average' type raw metrics. 162 static constexpr int kPsiNumAllUploadAvgMetrics = kPsiNumAllAvgs * kPsiNumOfAggregatedType; 163 static constexpr int kPsiNumAllUploadTotalMetrics = kPsiNumAllTotals; 164 static constexpr int kPsiNumAllUploadMetrics = 165 kPsiNumAllUploadTotalMetrics + kPsiNumAllUploadAvgMetrics; 166 167 bool checkKernelMMMetricSupport(); 168 bool checkKernelOomUsageSupport(); 169 bool checkKernelGcmaSupport(); 170 MmMetricsSupported()171 bool MmMetricsSupported() { return ker_mm_metrics_support_; } OomUsageSupoorted()172 bool OomUsageSupoorted() { return ker_oom_usage_support_; } GcmaSupported()173 bool GcmaSupported() { return ker_gcma_support_; } 174 175 bool ReadFileToUint(const std::string &path, uint64_t *val); 176 bool reportVendorAtom(const std::shared_ptr<IStats> &stats_client, int atom_id, 177 const std::vector<VendorAtomValue> &values, const std::string &atom_name); 178 void readCompactionDurationStat(std::vector<long> *store); 179 void fillCompactionDurationStatAtom(const std::vector<long> &store, 180 std::vector<VendorAtomValue> *values); 181 void readDirectReclaimStat(std::vector<long> *store); 182 void fillDirectReclaimStatAtom(const std::vector<long> &store, 183 std::vector<VendorAtomValue> *values); 184 void readPressureStall(const std::string &basePath, std::vector<long> *store); 185 bool parsePressureStallFileContent(bool is_cpu, const std::string &lines, 186 std::vector<long> *store, int file_save_idx); 187 bool parsePressureStallWords(const std::vector<std::string> &words, std::vector<long> *store, 188 int line_save_idx); 189 bool savePressureMetrics(const std::string &name, const std::string &value, 190 std::vector<long> *store, int base_save_idx); 191 void fillPressureStallAtom(std::vector<VendorAtomValue> *values); 192 void aggregatePressureStall(); 193 std::map<std::string, uint64_t> readSysfsNameValue(const std::string &path); 194 std::map<std::string, std::vector<uint64_t>> readProcStat(const std::string &path); 195 uint64_t getIonTotalPools(); 196 uint64_t getGpuMemory(); 197 bool fillAtomValues(const std::vector<MmMetricsInfo> &metrics_info, 198 const std::map<std::string, uint64_t> &mm_metrics, 199 std::map<std::string, uint64_t> *prev_mm_metrics, 200 std::vector<VendorAtomValue> *atom_values); 201 bool getValueFromParsedProcStat(const std::map<std::string, std::vector<uint64_t>> pstat, 202 const std::string &name, int offset, uint64_t *output); 203 bool fillProcStat(const std::vector<ProcStatMetricsInfo> &metrics_info, 204 const std::map<std::string, std::vector<uint64_t>> &cur_pstat, 205 std::map<std::string, std::vector<uint64_t>> *prev_pstat, 206 std::vector<VendorAtomValue> *atom_values); 207 virtual std::string getProcessStatPath(const std::string &name, int *prev_pid); 208 bool isValidProcessInfoPath(const std::string &path, const char *name); 209 int findPidByProcessName(const std::string &name); 210 int64_t getStimeByPathAndVerifyName(const std::string &path, const std::string &name); 211 void fillProcessStime(int atom_key, const std::string &name, int *pid, uint64_t *prev_stime, 212 std::vector<VendorAtomValue> *atom_values); 213 std::map<std::string, uint64_t> readCmaStat(const std::string &cma_type, 214 const std::vector<MmMetricsInfo> &metrics_info); 215 void reportCmaStatusAtom( 216 const std::shared_ptr<IStats> &stats_client, int atom_id, const std::string &cma_type, 217 int cma_name_offset, const std::vector<MmMetricsInfo> &metrics_info, 218 std::map<std::string, std::map<std::string, uint64_t>> *all_prev_cma_stat); 219 220 std::optional<OomGroupMemUsage> parseMmProcessUsageByOomGroupLine(const std::string &line); 221 bool readMmProcessUsageByOomGroupFile(const std::string &path, 222 std::vector<OomGroupMemUsage> *ogusage, int32_t *m_uid); 223 224 // test code could override this to inject test data 225 // though named 'Sysfs', it can be applied to proc fs getSysfsPath(const std::string & path)226 virtual std::string getSysfsPath(const std::string &path) { return path; } 227 228 const char *const kVmstatPath; 229 const char *const kIonTotalPoolsPath; 230 const char *const kIonTotalPoolsPathForLegacy; 231 const char *const kGpuTotalPages; 232 const char *const kCompactDuration; 233 const char *const kDirectReclaimBasePath; 234 const char *const kPixelStatMm; 235 const char *const kMeminfoPath; 236 const char *const kProcStatPath; 237 const char *const kProcVendorMmUsageByOom; 238 const char *const kGcmaBasePath; 239 240 // GCMA hourly metrics 241 const char *const kGcmaCached = "cached"; 242 243 // GCMA hourly 1/2 244 const char *const kGcmaHourlySimpleKnobs[4] = { 245 "discarded", 246 "evicted", 247 "loaded", 248 "stored", 249 }; 250 251 // GCMA hourly 2/2 252 const char *const kGcmaHourlyHistogramKnobs[4] = { 253 "latency_low", 254 "latency_mid", 255 "latency_high", 256 "latency_extreme_high", 257 }; 258 259 // Proto messages are 1-indexed and VendorAtom field numbers start at 2, so 260 // store everything in the values array at the index of the field number 261 // -2. 262 static constexpr int kVendorAtomOffset = 2; 263 static constexpr int kNumCompactionDurationPrevMetrics = 6; 264 static constexpr int kNumDirectReclaimPrevMetrics = 20; 265 266 std::vector<long> prev_compaction_duration_; 267 std::vector<long> prev_direct_reclaim_; 268 long prev_psi_total_[kPsiNumAllTotals]; 269 long psi_total_[kPsiNumAllTotals]; 270 long psi_aggregated_[kPsiNumAllUploadAvgMetrics]; // min, max and avg of original avgXXX 271 int psi_data_set_count_ = 0; 272 std::map<std::string, uint64_t> prev_hour_vmstat_; 273 std::map<std::string, uint64_t> prev_day_vmstat_; 274 std::map<std::string, uint64_t> prev_day_pixel_vmstat_; 275 std::map<std::string, std::vector<uint64_t>> prev_procstat_; 276 std::map<std::string, std::map<std::string, uint64_t>> prev_cma_stat_; 277 std::map<std::string, std::map<std::string, uint64_t>> prev_cma_stat_ext_; 278 int prev_kswapd_pid_ = -1; 279 int prev_kcompactd_pid_ = -1; 280 uint64_t prev_kswapd_stime_ = 0; 281 uint64_t prev_kcompactd_stime_ = 0; 282 int32_t oom_usage_uid_ = 0; 283 bool ker_mm_metrics_support_; 284 bool ker_oom_usage_support_; 285 bool ker_gcma_support_; 286 }; 287 288 } // namespace pixel 289 } // namespace google 290 } // namespace hardware 291 } // namespace android 292 293 #endif // HARDWARE_GOOGLE_PIXEL_PIXELSTATS_MMMETRICSREPORTER_H 294