• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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