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