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 MmMetricsReporter(); 40 void aggregatePixelMmMetricsPer5Min(); 41 void logPixelMmMetricsPerHour(const std::shared_ptr<IStats> &stats_client); 42 void logPixelMmMetricsPerDay(const std::shared_ptr<IStats> &stats_client); 43 void logCmaStatus(const std::shared_ptr<IStats> &stats_client); 44 std::vector<VendorAtomValue> genPixelMmMetricsPerHour(); 45 std::vector<VendorAtomValue> genPixelMmMetricsPerDay(); ~MmMetricsReporter()46 virtual ~MmMetricsReporter() {} 47 48 private: 49 struct MmMetricsInfo { 50 std::string name; 51 int atom_key; 52 bool update_diff; 53 }; 54 55 /* 56 * Similar to MmMetricsInfo, but /proc/stat output is an array rather 57 * than one single value. So we need an offset to get the specific value 58 * in the array. 59 * special: offset = -1 means to get the sum of the elements in the array. 60 */ 61 struct ProcStatMetricsInfo { 62 std::string name; 63 int offset; 64 int atom_key; 65 bool update_diff; 66 }; 67 68 enum CmaType { 69 FARAWIMG = 0, 70 FAIMG = 1, 71 FATPU = 2, 72 FAPREV = 3, 73 VFRAME = 4, 74 VSTREAM = 5, 75 }; 76 77 static const std::vector<MmMetricsInfo> kMmMetricsPerHourInfo; 78 static const std::vector<MmMetricsInfo> kMeminfoInfo; 79 static const std::vector<MmMetricsInfo> kMmMetricsPerDayInfo; 80 static const std::vector<ProcStatMetricsInfo> kProcStatInfo; 81 static const std::vector<MmMetricsInfo> kCmaStatusInfo; 82 static const std::vector<MmMetricsInfo> kCmaStatusExtInfo; 83 84 // raw PSI 85 static constexpr const char *kPsiBasePath = "/proc/pressure"; 86 static constexpr const char *kPsiTypes[3] = {"cpu", "io", "memory"}; 87 static constexpr const char *kPsiCategories[2] = {"full", "some"}; 88 static constexpr const char *kPsiMetricNames[4] = {"avg10", "avg60", "avg300", "total"}; 89 static constexpr int kPsiNumFiles = sizeof(kPsiTypes) / sizeof(kPsiTypes[0]); 90 static constexpr int kPsiNumCategories = sizeof(kPsiCategories) / sizeof(kPsiCategories[0]); 91 // number of statistics metric names (one total and several timed averages, per category) 92 static constexpr int kPsiNumNames = sizeof(kPsiMetricNames) / sizeof(kPsiMetricNames[0]); 93 94 // Though cpu has no 'full' category, here we assume it has 95 // So, all file will contain 2 lines x 4 metrics per line = 8 metrics total. 96 static constexpr int kPsiMetricsPerFile = kPsiNumCategories * kPsiNumNames; 97 98 // we have 1 'total' and all others 'averages' per category 99 // "total" metrics are already accumulative and thus no aggregation is needed. 100 // raw values are used. 101 static constexpr int kPsiNumTotals = 1; 102 static constexpr int kPsiNumAvgs = kPsiNumNames - kPsiNumTotals; 103 104 // -1 since "cpu" type has no "full" category 105 static constexpr int kPsiNumAllCategories = kPsiNumFiles * kPsiNumCategories - 1; 106 107 // number of raw metrics: total and avgs, and the combined all: added together. 108 static constexpr int kPsiNumAllTotals = kPsiNumAllCategories * kPsiNumTotals; 109 static constexpr int kPsiNumAllAvgs = kPsiNumAllCategories * kPsiNumAvgs; 110 static constexpr int kPsiNumAllMetrics = kPsiNumAllTotals + kPsiNumAllAvgs; 111 112 // aggregated into (1) min, (2) max, (3) average (internally the sum is kept than the average) 113 static constexpr int kPsiNumOfAggregatedType = 3; 114 115 // # of upload metrics will have a aggregation factor on all 'average' type raw metrics. 116 static constexpr int kPsiNumAllUploadAvgMetrics = kPsiNumAllAvgs * kPsiNumOfAggregatedType; 117 static constexpr int kPsiNumAllUploadTotalMetrics = kPsiNumAllTotals; 118 static constexpr int kPsiNumAllUploadMetrics = 119 kPsiNumAllUploadTotalMetrics + kPsiNumAllUploadAvgMetrics; 120 121 bool checkKernelMMMetricSupport(); 122 MmMetricsSupported()123 bool MmMetricsSupported() { return ker_mm_metrics_support_; } 124 125 bool ReadFileToUint(const std::string &path, uint64_t *val); 126 bool reportVendorAtom(const std::shared_ptr<IStats> &stats_client, int atom_id, 127 const std::vector<VendorAtomValue> &values, const std::string &atom_name); 128 void readCompactionDurationStat(std::vector<long> *store); 129 void fillCompactionDurationStatAtom(const std::vector<long> &store, 130 std::vector<VendorAtomValue> *values); 131 void readDirectReclaimStat(std::vector<long> *store); 132 void fillDirectReclaimStatAtom(const std::vector<long> &store, 133 std::vector<VendorAtomValue> *values); 134 void readPressureStall(const std::string &basePath, std::vector<long> *store); 135 bool parsePressureStallFileContent(bool is_cpu, const std::string &lines, 136 std::vector<long> *store, int file_save_idx); 137 bool parsePressureStallWords(const std::vector<std::string> &words, std::vector<long> *store, 138 int line_save_idx); 139 bool savePressureMetrics(const std::string &name, const std::string &value, 140 std::vector<long> *store, int base_save_idx); 141 void fillPressureStallAtom(std::vector<VendorAtomValue> *values); 142 void aggregatePressureStall(); 143 std::map<std::string, uint64_t> readSysfsNameValue(const std::string &path); 144 std::map<std::string, std::vector<uint64_t>> readProcStat(const std::string &path); 145 uint64_t getIonTotalPools(); 146 uint64_t getGpuMemory(); 147 bool fillAtomValues(const std::vector<MmMetricsInfo> &metrics_info, 148 const std::map<std::string, uint64_t> &mm_metrics, 149 std::map<std::string, uint64_t> *prev_mm_metrics, 150 std::vector<VendorAtomValue> *atom_values); 151 bool getValueFromParsedProcStat(const std::map<std::string, std::vector<uint64_t>> pstat, 152 const std::string &name, int offset, uint64_t *output); 153 bool fillProcStat(const std::vector<ProcStatMetricsInfo> &metrics_info, 154 const std::map<std::string, std::vector<uint64_t>> &cur_pstat, 155 std::map<std::string, std::vector<uint64_t>> *prev_pstat, 156 std::vector<VendorAtomValue> *atom_values); 157 virtual std::string getProcessStatPath(const std::string &name, int *prev_pid); 158 bool isValidProcessInfoPath(const std::string &path, const char *name); 159 int findPidByProcessName(const std::string &name); 160 int64_t getStimeByPathAndVerifyName(const std::string &path, const std::string &name); 161 void fillProcessStime(int atom_key, const std::string &name, int *pid, uint64_t *prev_stime, 162 std::vector<VendorAtomValue> *atom_values); 163 std::map<std::string, uint64_t> readCmaStat(const std::string &cma_type, 164 const std::vector<MmMetricsInfo> &metrics_info); 165 void reportCmaStatusAtom( 166 const std::shared_ptr<IStats> &stats_client, int atom_id, const std::string &cma_type, 167 int cma_name_offset, const std::vector<MmMetricsInfo> &metrics_info, 168 std::map<std::string, std::map<std::string, uint64_t>> *all_prev_cma_stat); 169 170 // test code could override this to inject test data getSysfsPath(const std::string & path)171 virtual std::string getSysfsPath(const std::string &path) { return path; } 172 173 const char *const kVmstatPath; 174 const char *const kIonTotalPoolsPath; 175 const char *const kIonTotalPoolsPathForLegacy; 176 const char *const kGpuTotalPages; 177 const char *const kCompactDuration; 178 const char *const kDirectReclaimBasePath; 179 const char *const kPixelStatMm; 180 const char *const kMeminfoPath; 181 const char *const kProcStatPath; 182 // Proto messages are 1-indexed and VendorAtom field numbers start at 2, so 183 // store everything in the values array at the index of the field number 184 // -2. 185 static constexpr int kVendorAtomOffset = 2; 186 static constexpr int kNumCompactionDurationPrevMetrics = 6; 187 static constexpr int kNumDirectReclaimPrevMetrics = 20; 188 189 std::vector<long> prev_compaction_duration_; 190 std::vector<long> prev_direct_reclaim_; 191 long prev_psi_total_[kPsiNumAllTotals]; 192 long psi_total_[kPsiNumAllTotals]; 193 long psi_aggregated_[kPsiNumAllUploadAvgMetrics]; // min, max and avg of original avgXXX 194 int psi_data_set_count_ = 0; 195 std::map<std::string, uint64_t> prev_hour_vmstat_; 196 std::map<std::string, uint64_t> prev_day_vmstat_; 197 std::map<std::string, uint64_t> prev_day_pixel_vmstat_; 198 std::map<std::string, std::vector<uint64_t>> prev_procstat_; 199 std::map<std::string, std::map<std::string, uint64_t>> prev_cma_stat_; 200 std::map<std::string, std::map<std::string, uint64_t>> prev_cma_stat_ext_; 201 int prev_kswapd_pid_ = -1; 202 int prev_kcompactd_pid_ = -1; 203 uint64_t prev_kswapd_stime_ = 0; 204 uint64_t prev_kcompactd_stime_ = 0; 205 bool ker_mm_metrics_support_; 206 }; 207 208 } // namespace pixel 209 } // namespace google 210 } // namespace hardware 211 } // namespace android 212 213 #endif // HARDWARE_GOOGLE_PIXEL_PIXELSTATS_MMMETRICSREPORTER_H 214