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 45 private: 46 struct MmMetricsInfo { 47 std::string name; 48 int atom_key; 49 bool update_diff; 50 }; 51 52 enum CmaType { 53 FARAWIMG = 0, 54 FAIMG = 1, 55 FATPU = 2, 56 FAPREV = 3, 57 VFRAME = 4, 58 VSTREAM = 5, 59 }; 60 61 static const std::vector<MmMetricsInfo> kMmMetricsPerHourInfo; 62 static const std::vector<MmMetricsInfo> kMmMetricsPerDayInfo; 63 static const std::vector<MmMetricsInfo> kCmaStatusInfo; 64 static const std::vector<MmMetricsInfo> kCmaStatusExtInfo; 65 66 // raw PSI 67 static constexpr const char *kPsiBasePath = "/proc/pressure"; 68 static constexpr const char *kPsiTypes[3] = {"cpu", "io", "memory"}; 69 static constexpr const char *kPsiCategories[2] = {"full", "some"}; 70 static constexpr const char *kPsiMetricNames[4] = {"avg10", "avg60", "avg300", "total"}; 71 static constexpr int kPsiNumFiles = sizeof(kPsiTypes) / sizeof(kPsiTypes[0]); 72 static constexpr int kPsiNumCategories = sizeof(kPsiCategories) / sizeof(kPsiCategories[0]); 73 // number of statistics metric names (one total and several timed averages, per category) 74 static constexpr int kPsiNumNames = sizeof(kPsiMetricNames) / sizeof(kPsiMetricNames[0]); 75 76 // Though cpu has no 'full' category, here we assume it has 77 // So, all file will contain 2 lines x 4 metrics per line = 8 metrics total. 78 static constexpr int kPsiMetricsPerFile = kPsiNumCategories * kPsiNumNames; 79 80 // we have 1 'total' and all others 'averages' per category 81 // "total" metrics are already accumulative and thus no aggregation is needed. 82 // raw values are used. 83 static constexpr int kPsiNumTotals = 1; 84 static constexpr int kPsiNumAvgs = kPsiNumNames - kPsiNumTotals; 85 86 // -1 since "cpu" type has no "full" category 87 static constexpr int kPsiNumAllCategories = kPsiNumFiles * kPsiNumCategories - 1; 88 89 // number of raw metrics: total and avgs, and the combined all: added together. 90 static constexpr int kPsiNumAllTotals = kPsiNumAllCategories * kPsiNumTotals; 91 static constexpr int kPsiNumAllAvgs = kPsiNumAllCategories * kPsiNumAvgs; 92 static constexpr int kPsiNumAllMetrics = kPsiNumAllTotals + kPsiNumAllAvgs; 93 94 // aggregated into (1) min, (2) max, (3) average (internally the sum is kept than the average) 95 static constexpr int kPsiNumOfAggregatedType = 3; 96 97 // # of upload metrics will have a aggregation factor on all 'average' type raw metrics. 98 static constexpr int kPsiNumAllUploadAvgMetrics = kPsiNumAllAvgs * kPsiNumOfAggregatedType; 99 static constexpr int kPsiNumAllUploadTotalMetrics = kPsiNumAllTotals; 100 static constexpr int kPsiNumAllUploadMetrics = 101 kPsiNumAllUploadTotalMetrics + kPsiNumAllUploadAvgMetrics; 102 103 bool checkKernelMMMetricSupport(); 104 MmMetricsSupported()105 bool MmMetricsSupported() { 106 // Currently, we collect these metrics and report this atom only for userdebug_or_eng 107 // We only grant permissions to access sysfs for userdebug_or_eng. 108 // Add a check to avoid unnecessary access. 109 // In addition, we need to check the kernel MM metrics support. 110 return !is_user_build_ && ker_mm_metrics_support_; 111 } 112 CmaMetricsSupported()113 bool CmaMetricsSupported() { 114 // For CMA metric 115 return ker_mm_metrics_support_; 116 } 117 118 bool ReadFileToUint(const char *const path, uint64_t *val); 119 bool reportVendorAtom(const std::shared_ptr<IStats> &stats_client, int atom_id, 120 const std::vector<VendorAtomValue> &values, const std::string &atom_name); 121 void readCompactionDurationStat(std::vector<long> *store); 122 void fillCompactionDurationStatAtom(const std::vector<long> &store, 123 std::vector<VendorAtomValue> *values); 124 void readDirectReclaimStat(std::vector<long> *store); 125 void fillDirectReclaimStatAtom(const std::vector<long> &store, 126 std::vector<VendorAtomValue> *values); 127 void readPressureStall(const char *basePath, std::vector<long> *store); 128 bool parsePressureStallFileContent(bool is_cpu, std::string lines, std::vector<long> *store, 129 int file_save_idx); 130 bool parsePressureStallWords(std::vector<std::string> words, std::vector<long> *store, 131 int line_save_idx); 132 bool savePressureMetrics(std::string name, std::string value, std::vector<long> *store, 133 int base_save_idx); 134 void fillPressureStallAtom(std::vector<VendorAtomValue> *values); 135 void aggregatePressureStall(); 136 std::map<std::string, uint64_t> readVmStat(const char *path); 137 uint64_t getIonTotalPools(); 138 uint64_t getGpuMemory(); 139 void fillAtomValues(const std::vector<MmMetricsInfo> &metrics_info, 140 const std::map<std::string, uint64_t> &mm_metrics, 141 std::map<std::string, uint64_t> *prev_mm_metrics, 142 std::vector<VendorAtomValue> *atom_values); 143 bool isValidPid(int pid, const char *name); 144 int findPidByProcessName(const char *name); 145 uint64_t getStimeByPid(int pid); 146 void fillProcessStime(int atom_key, const char *name, int *pid, uint64_t *prev_stime, 147 std::vector<VendorAtomValue> *atom_values); 148 std::map<std::string, uint64_t> readCmaStat(const std::string &cma_type, 149 const std::vector<MmMetricsInfo> &metrics_info); 150 void reportCmaStatusAtom( 151 const std::shared_ptr<IStats> &stats_client, int atom_id, const std::string &cma_type, 152 int cma_name_offset, const std::vector<MmMetricsInfo> &metrics_info, 153 std::map<std::string, std::map<std::string, uint64_t>> *all_prev_cma_stat); 154 155 const char *const kVmstatPath; 156 const char *const kIonTotalPoolsPath; 157 const char *const kIonTotalPoolsPathForLegacy; 158 const char *const kGpuTotalPages; 159 const char *const kCompactDuration; 160 const char *const kDirectReclaimBasePath; 161 const char *const kPixelStatMm; 162 // Proto messages are 1-indexed and VendorAtom field numbers start at 2, so 163 // store everything in the values array at the index of the field number 164 // -2. 165 static constexpr int kVendorAtomOffset = 2; 166 static constexpr int kNumCompactionDurationPrevMetrics = 6; 167 static constexpr int kNumDirectReclaimPrevMetrics = 20; 168 169 std::vector<long> prev_compaction_duration_; 170 std::vector<long> prev_direct_reclaim_; 171 long prev_psi_total_[kPsiNumAllTotals]; 172 long psi_total_[kPsiNumAllTotals]; 173 long psi_aggregated_[kPsiNumAllUploadAvgMetrics]; // min, max and avg of original avgXXX 174 int psi_data_set_count_ = 0; 175 std::map<std::string, uint64_t> prev_hour_vmstat_; 176 std::map<std::string, uint64_t> prev_day_vmstat_; 177 std::map<std::string, uint64_t> prev_day_pixel_vmstat_; 178 std::map<std::string, std::map<std::string, uint64_t>> prev_cma_stat_; 179 std::map<std::string, std::map<std::string, uint64_t>> prev_cma_stat_ext_; 180 int kswapd_pid_ = -1; 181 int kcompactd_pid_ = -1; 182 uint64_t prev_kswapd_stime_ = 0; 183 uint64_t prev_kcompactd_stime_ = 0; 184 bool is_user_build_; 185 bool ker_mm_metrics_support_; 186 }; 187 188 } // namespace pixel 189 } // namespace google 190 } // namespace hardware 191 } // namespace android 192 193 #endif // HARDWARE_GOOGLE_PIXEL_PIXELSTATS_MMMETRICSREPORTER_H 194