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 #define LOG_TAG "pixelstats: ThermalStats"
18 
19 #include <aidl/android/frameworks/stats/IStats.h>
20 #include <android-base/file.h>
21 #include <android-base/properties.h>
22 #include <android-base/stringprintf.h>
23 #include <android-base/strings.h>
24 #include <android/binder_manager.h>
25 #include <hardware/google/pixel/pixelstats/pixelatoms.pb.h>
26 #include <pixelstats/ThermalStatsReporter.h>
27 #include <utils/Log.h>
28 
29 #include <cinttypes>
30 
31 namespace android {
32 namespace hardware {
33 namespace google {
34 namespace pixel {
35 
36 using aidl::android::frameworks::stats::IStats;
37 using aidl::android::frameworks::stats::VendorAtom;
38 using aidl::android::frameworks::stats::VendorAtomValue;
39 using android::base::ReadFileToString;
40 using android::hardware::google::pixel::PixelAtoms::ThermalDfsStats;
41 
ThermalStatsReporter()42 ThermalStatsReporter::ThermalStatsReporter() {}
43 
readDfsCount(const std::string & path,int64_t * val)44 bool ThermalStatsReporter::readDfsCount(const std::string &path, int64_t *val) {
45     std::string file_contents;
46 
47     if (path.empty()) {
48         ALOGE("Empty path");
49         return false;
50     }
51 
52     if (!ReadFileToString(path.c_str(), &file_contents)) {
53         ALOGE("Unable to read %s - %s", path.c_str(), strerror(errno));
54         return false;
55     } else {
56         int64_t trips[8];
57 
58         if (sscanf(file_contents.c_str(),
59                    "%" SCNd64 " %" SCNd64 " %" SCNd64 " %" SCNd64 " %" SCNd64 " %" SCNd64
60                    " %" SCNd64 " %" SCNd64,
61                    &trips[0], &trips[1], &trips[2], &trips[3], &trips[4], &trips[5], &trips[6],
62                    &trips[7]) < 8) {
63             ALOGE("Unable to parse trip_counters %s from file %s", file_contents.c_str(),
64                   path.c_str());
65             return false;
66         }
67 
68         /* Trip#6 corresponds to DFS count */
69         *val = trips[6];
70     }
71 
72     return true;
73 }
74 
captureThermalDfsStats(const std::vector<std::string> & thermal_stats_paths,struct ThermalDfsCounts * pcur_data)75 bool ThermalStatsReporter::captureThermalDfsStats(
76         const std::vector<std::string> &thermal_stats_paths, struct ThermalDfsCounts *pcur_data) {
77     bool report_stats = false;
78     std::string path;
79 
80     if (thermal_stats_paths.size() < kNumOfThermalDfsStats) {
81         ALOGE("Number of thermal stats paths (%zu) is less than expected (%d)",
82               thermal_stats_paths.size(), kNumOfThermalDfsStats);
83         return false;
84     }
85 
86     path = thermal_stats_paths[ThermalDfsStats::kBigDfsCountFieldNumber - kVendorAtomOffset];
87     if (!readDfsCount(path, &(pcur_data->big_count))) {
88         pcur_data->big_count = prev_data.big_count;
89     } else {
90         report_stats |= (pcur_data->big_count > prev_data.big_count);
91     }
92 
93     path = thermal_stats_paths[ThermalDfsStats::kMidDfsCountFieldNumber - kVendorAtomOffset];
94     if (!readDfsCount(path, &(pcur_data->mid_count))) {
95         pcur_data->mid_count = prev_data.mid_count;
96     } else {
97         report_stats |= (pcur_data->mid_count > prev_data.mid_count);
98     }
99 
100     path = thermal_stats_paths[ThermalDfsStats::kLittleDfsCountFieldNumber - kVendorAtomOffset];
101     if (!readDfsCount(path, &(pcur_data->little_count))) {
102         pcur_data->little_count = prev_data.little_count;
103     } else {
104         report_stats |= (pcur_data->little_count > prev_data.little_count);
105     }
106 
107     path = thermal_stats_paths[ThermalDfsStats::kGpuDfsCountFieldNumber - kVendorAtomOffset];
108     if (!readDfsCount(path, &(pcur_data->gpu_count))) {
109         pcur_data->gpu_count = prev_data.gpu_count;
110     } else {
111         report_stats |= (pcur_data->gpu_count > prev_data.gpu_count);
112     }
113 
114     path = thermal_stats_paths[ThermalDfsStats::kTpuDfsCountFieldNumber - kVendorAtomOffset];
115     if (!readDfsCount(path, &(pcur_data->tpu_count))) {
116         pcur_data->tpu_count = prev_data.tpu_count;
117     } else {
118         report_stats |= (pcur_data->tpu_count > prev_data.tpu_count);
119     }
120 
121     path = thermal_stats_paths[ThermalDfsStats::kAurDfsCountFieldNumber - kVendorAtomOffset];
122     if (!readDfsCount(path, &(pcur_data->aur_count))) {
123         pcur_data->aur_count = prev_data.aur_count;
124     } else {
125         report_stats |= (pcur_data->aur_count > prev_data.aur_count);
126     }
127 
128     return report_stats;
129 }
130 
logThermalDfsStats(const std::shared_ptr<IStats> & stats_client,const std::vector<std::string> & thermal_stats_paths)131 void ThermalStatsReporter::logThermalDfsStats(const std::shared_ptr<IStats> &stats_client,
132                                               const std::vector<std::string> &thermal_stats_paths) {
133     struct ThermalDfsCounts cur_data = prev_data;
134 
135     if (!captureThermalDfsStats(thermal_stats_paths, &cur_data)) {
136         prev_data = cur_data;
137         ALOGI("No update found for thermal stats");
138         return;
139     }
140 
141     VendorAtomValue tmp;
142     int64_t max_dfs_count = static_cast<int64_t>(INT32_MAX);
143     int dfs_count;
144     std::vector<VendorAtomValue> values(kNumOfThermalDfsStats);
145 
146     dfs_count = std::min<int64_t>(cur_data.big_count - prev_data.big_count, max_dfs_count);
147     tmp.set<VendorAtomValue::intValue>(dfs_count);
148     values[ThermalDfsStats::kBigDfsCountFieldNumber - kVendorAtomOffset] = tmp;
149 
150     dfs_count = std::min<int64_t>(cur_data.mid_count - prev_data.mid_count, max_dfs_count);
151     tmp.set<VendorAtomValue::intValue>(dfs_count);
152     values[ThermalDfsStats::kMidDfsCountFieldNumber - kVendorAtomOffset] = tmp;
153 
154     dfs_count = std::min<int64_t>(cur_data.little_count - prev_data.little_count, max_dfs_count);
155     tmp.set<VendorAtomValue::intValue>(dfs_count);
156     values[ThermalDfsStats::kLittleDfsCountFieldNumber - kVendorAtomOffset] = tmp;
157 
158     dfs_count = std::min<int64_t>(cur_data.gpu_count - prev_data.gpu_count, max_dfs_count);
159     tmp.set<VendorAtomValue::intValue>(dfs_count);
160     values[ThermalDfsStats::kGpuDfsCountFieldNumber - kVendorAtomOffset] = tmp;
161 
162     dfs_count = std::min<int64_t>(cur_data.tpu_count - prev_data.tpu_count, max_dfs_count);
163     tmp.set<VendorAtomValue::intValue>(dfs_count);
164     values[ThermalDfsStats::kTpuDfsCountFieldNumber - kVendorAtomOffset] = tmp;
165 
166     dfs_count = std::min<int64_t>(cur_data.aur_count - prev_data.aur_count, max_dfs_count);
167     tmp.set<VendorAtomValue::intValue>(dfs_count);
168     values[ThermalDfsStats::kAurDfsCountFieldNumber - kVendorAtomOffset] = tmp;
169 
170     prev_data = cur_data;
171 
172     ALOGD("Report updated thermal metrics to stats service");
173     // Send vendor atom to IStats HAL
174     VendorAtom event = {.reverseDomainName = "",
175                         .atomId = PixelAtoms::Atom::kThermalDfsStats,
176                         .values = std::move(values)};
177     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
178     if (!ret.isOk())
179         ALOGE("Unable to report thermal DFS stats to Stats service");
180 }
181 
logThermalStats(const std::shared_ptr<IStats> & stats_client,const std::vector<std::string> & thermal_stats_paths)182 void ThermalStatsReporter::logThermalStats(const std::shared_ptr<IStats> &stats_client,
183                                            const std::vector<std::string> &thermal_stats_paths) {
184     logThermalDfsStats(stats_client, thermal_stats_paths);
185 }
186 
187 }  // namespace pixel
188 }  // namespace google
189 }  // namespace hardware
190 }  // namespace android
191