1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "rs_profiler_telemetry.h"
17
18 #include "rs_profiler_settings.h"
19
20 namespace OHOS::Rosen {
21
22 static const StringParameter TERMAL("paths.termal");
23 static const StringParameter CURRENT("paths.current");
24 static const StringParameter VOLTAGE("paths.voltage");
25 static const StringParameter MEMORY("paths.memory");
26 // cpu
27 static const StringParameter CPU_USAGE("paths.cpu.time");
28 static const StringParameter CPU_CORES("paths.cpu.cores");
29 static const StringParameter CPU_FREQUENCY("paths.cpu.frequency");
30 static const StringParameter CPU_FREQUENCY_POLICY("paths.cpu.frequency.policy");
31 // gpu
32 static const StringParameter GPU_FREQUENCY("paths.gpu.frequency");
33 static const StringParameter GPU_FREQUENCY_MIN("paths.gpu.frequency.min");
34 static const StringParameter GPU_FREQUENCY_MAX("paths.gpu.frequency.max");
35 static const StringParameter GPU_LOAD("paths.gpu.load");
36
37 struct CpuTime final {
38 static const uint32_t COUNT = 7;
39 double times[COUNT] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
40 double total = 0;
41 };
42
GetTemperaturePath()43 static std::string GetTemperaturePath()
44 {
45 std::vector<std::string> directories;
46 Utils::IterateDirectory(*TERMAL, directories);
47
48 std::string type;
49 for (const std::string& directory : directories) {
50 Utils::LoadContent(Utils::MakePath(directory, "type"), type);
51 if (type.find("soc_thermal") != std::string::npos) {
52 return Utils::MakePath(directory, "temp");
53 }
54 }
55
56 return {};
57 }
58
59 // cpufreq
GetCpuFrequencyPath(uint32_t cpu)60 static std::string GetCpuFrequencyPath(uint32_t cpu)
61 {
62 return Utils::MakePath(*CPU_FREQUENCY + std::to_string(cpu), "cpufreq");
63 }
64
GetCpuCurrentFrequencyPath(uint32_t cpu)65 static std::string GetCpuCurrentFrequencyPath(uint32_t cpu)
66 {
67 return Utils::MakePath(GetCpuFrequencyPath(cpu), "scaling_cur_freq");
68 }
69
70 // cpupolicy
GetCpuFrequencyPolicyPath(uint32_t cpu)71 static std::string GetCpuFrequencyPolicyPath(uint32_t cpu)
72 {
73 return *CPU_FREQUENCY_POLICY + std::to_string(cpu);
74 }
75
GetCpuCurrentFrequencyPolicyPath(uint32_t cpu)76 static std::string GetCpuCurrentFrequencyPolicyPath(uint32_t cpu)
77 {
78 return Utils::MakePath(GetCpuFrequencyPolicyPath(cpu), "scaling_cur_freq");
79 }
80
GetCpuMinFrequencyPolicyPath(uint32_t cpu)81 static std::string GetCpuMinFrequencyPolicyPath(uint32_t cpu)
82 {
83 return Utils::MakePath(GetCpuFrequencyPolicyPath(cpu), "scaling_min_freq");
84 }
85
GetCpuMaxFrequencyPolicyPath(uint32_t cpu)86 static std::string GetCpuMaxFrequencyPolicyPath(uint32_t cpu)
87 {
88 return Utils::MakePath(GetCpuFrequencyPolicyPath(cpu), "scaling_max_freq");
89 }
90
TemperatureToString(float temperature)91 static std::string TemperatureToString(float temperature)
92 {
93 return std::to_string(temperature) + " °C";
94 }
95
CurrentToString(float current)96 static std::string CurrentToString(float current)
97 {
98 return std::to_string(current) + " mA";
99 }
100
VoltageToString(float voltage)101 static std::string VoltageToString(float voltage)
102 {
103 return std::to_string(voltage) + " V";
104 }
105
MemoryToString(uint64_t memory)106 static std::string MemoryToString(uint64_t memory)
107 {
108 return std::to_string(memory * Utils::MICRO) + " GB";
109 }
110
FrequencyToString(float frequency)111 static std::string FrequencyToString(float frequency)
112 {
113 return std::to_string(frequency) + " GHz";
114 }
115
LoadToString(float load)116 static std::string LoadToString(float load)
117 {
118 return std::to_string(load) + " %";
119 }
120
FrequencyLoadToString(const FrequencyLoadInfo & info)121 static std::string FrequencyLoadToString(const FrequencyLoadInfo& info)
122 {
123 return FrequencyToString(info.current) + "(min: " + FrequencyToString(info.min) +
124 " max: " + FrequencyToString(info.max) + " load: " + LoadToString(info.load) + ")";
125 }
126
GetMetric(const std::string & name)127 static std::string GetMetric(const std::string& name)
128 {
129 std::string metric("0");
130 Utils::LoadContent(name, metric);
131 return metric;
132 }
133
GetMetricFloat(const std::string & name)134 static float GetMetricFloat(const std::string& name)
135 {
136 return Utils::ToFp32(GetMetric(name));
137 }
138
GetCPUTemperature(CPUInfo & cpu)139 static void GetCPUTemperature(CPUInfo& cpu)
140 {
141 cpu.temperature = GetMetricFloat(GetTemperaturePath()) * Utils::MILLI;
142 }
143
GetBattery(CPUInfo & cpu)144 static void GetBattery(CPUInfo& cpu)
145 {
146 cpu.current = GetMetricFloat(*CURRENT) * Utils::MICRO;
147 cpu.voltage = GetMetricFloat(*VOLTAGE) * Utils::MICRO;
148 }
149
GetValue(const std::string & name,const std::vector<std::string> & lines,uint64_t & value)150 static void GetValue(const std::string& name, const std::vector<std::string>& lines, uint64_t& value)
151 {
152 for (const std::string& line : lines) {
153 if (line.find(name) != std::string::npos) {
154 value = Utils::ToUint64(Utils::ExtractNumber(line));
155 return;
156 }
157 }
158 }
159
GetCPUMemory(CPUInfo & cpu)160 static void GetCPUMemory(CPUInfo& cpu)
161 {
162 std::vector<std::string> lines;
163 Utils::LoadLines(*MEMORY, lines);
164
165 if (!lines.empty()) {
166 GetValue("MemTotal", lines, cpu.ramTotal);
167 GetValue("MemFree", lines, cpu.ramFree);
168 }
169 }
170
GetCpuTime(const std::vector<std::string> & args,CpuTime & info)171 static uint32_t GetCpuTime(const std::vector<std::string>& args, CpuTime& info)
172 {
173 constexpr size_t cpuWordSize = 3;
174 if (args[0].size() == cpuWordSize) {
175 // this is cpu total line
176 return UINT_MAX;
177 }
178
179 info.total = 0;
180 for (uint32_t i = 0; i < CpuTime::COUNT; i++) {
181 info.times[i] = Utils::ToUint64(args[i + 1]);
182 info.total += info.times[i];
183 }
184
185 return Utils::ToUint64(args[0].data() + cpuWordSize);
186 }
187
IsCpuLine(const std::vector<std::string> & args)188 static bool IsCpuLine(const std::vector<std::string>& args)
189 {
190 constexpr size_t required = 11;
191 return (args.size() == required) && (args[0].find("cpu") == 0);
192 }
193
GetCpuTime(std::vector<CpuTime> & infos)194 static void GetCpuTime(std::vector<CpuTime>& infos)
195 {
196 std::vector<std::string> lines;
197 Utils::LoadLines(*CPU_USAGE, lines);
198 if (lines.empty()) {
199 return;
200 }
201
202 size_t processed = 0u;
203 for (const auto& line : lines) {
204 const std::vector<std::string> args = Utils::Split(line);
205 if (!IsCpuLine(args) || (processed == infos.size())) {
206 // either there are no more cpu lines in the file
207 // or all cpus were processed
208 return;
209 }
210
211 CpuTime info;
212 const size_t id = GetCpuTime(args, info);
213 if (id < infos.size()) {
214 infos[id] = info;
215 processed++;
216 }
217 }
218 }
219
GetCpuTotalUsage(const CpuTime & info,const CpuTime & lastInfo)220 static float GetCpuTotalUsage(const CpuTime& info, const CpuTime& lastInfo)
221 {
222 const double deltaTotal = info.total - lastInfo.total;
223 if (deltaTotal <= 0.0) {
224 return 0.0;
225 }
226
227 double usage = 0.0;
228 for (uint32_t i = 0; i < CpuTime::COUNT; i++) {
229 usage += std::max(info.times[i] - lastInfo.times[i], 0.0);
230 }
231
232 constexpr double ratioToPercent = 100.0;
233 return static_cast<float>(usage * ratioToPercent / deltaTotal);
234 }
235
GetCoreCount()236 static uint32_t GetCoreCount()
237 {
238 std::string line;
239 Utils::LoadLine(*CPU_CORES, line);
240
241 if (line.empty()) {
242 return 0;
243 }
244
245 if (line.size() == 1) {
246 return 1;
247 }
248
249 constexpr size_t multiCoreLineLength = 3;
250 if (line.size() >= multiCoreLineLength) {
251 constexpr uint32_t maxCoreIndex = 2;
252 return Utils::ToUint32(line.substr(maxCoreIndex)) + 1;
253 }
254
255 return 0;
256 }
257
GetCPUCores(CPUInfo & cpu)258 static void GetCPUCores(CPUInfo& cpu)
259 {
260 const uint32_t cores = GetCoreCount();
261 cpu.cores = std::min(CPUInfo::MAX_CORES, cores);
262
263 for (uint32_t i = 0; i < cpu.cores; i++) {
264 cpu.coreFrequencyLoad[i].current = GetMetricFloat(GetCpuCurrentFrequencyPath(i)) * Utils::MICRO;
265 }
266
267 std::vector<CpuTime> cpuTime(cpu.cores);
268 GetCpuTime(cpuTime);
269
270 static std::mutex mutex;
271 static std::vector<CpuTime> lastCpuTime;
272
273 const std::lock_guard<std::mutex> guard(mutex);
274 if (lastCpuTime.size() < cpu.cores) {
275 lastCpuTime.resize(cpu.cores);
276 }
277
278 for (size_t i = 0; i < cpu.cores; i++) {
279 cpu.coreFrequencyLoad[i].load = GetCpuTotalUsage(cpuTime[i], lastCpuTime[i]);
280 }
281
282 lastCpuTime = cpuTime;
283 }
284
GetGPUFrequencyLoad(GPUInfo & gpu)285 static void GetGPUFrequencyLoad(GPUInfo& gpu)
286 {
287 gpu.frequencyLoad.current = GetMetricFloat(*GPU_FREQUENCY) * Utils::NANO;
288 gpu.frequencyLoad.min = GetMetricFloat(*GPU_FREQUENCY_MIN) * Utils::NANO;
289 gpu.frequencyLoad.max = GetMetricFloat(*GPU_FREQUENCY_MAX) * Utils::NANO;
290 gpu.frequencyLoad.load = GetMetricFloat(*GPU_LOAD);
291 }
292
GetDeviceInfo()293 DeviceInfo RSTelemetry::GetDeviceInfo()
294 {
295 DeviceInfo info;
296 GetBattery(info.cpu);
297 GetCPUTemperature(info.cpu);
298 GetCPUMemory(info.cpu);
299 GetCPUCores(info.cpu);
300 GetGPUFrequencyLoad(info.gpu);
301 return info;
302 }
303
GetDeviceInfoString()304 std::string RSTelemetry::GetDeviceInfoString()
305 {
306 const DeviceInfo info = GetDeviceInfo();
307
308 std::string out;
309 for (size_t i = 0; i < info.cpu.cores; i++) {
310 out += +"\nCPU" + std::to_string(i) + ": " + FrequencyLoadToString(info.cpu.coreFrequencyLoad[i]);
311 }
312
313 out += "\nTemperature: " + TemperatureToString(info.cpu.temperature);
314 out += "\nCurrent: " + CurrentToString(info.cpu.current) + "\nVoltage: " + VoltageToString(info.cpu.voltage);
315 out += "\nRAM Total: " + MemoryToString(info.cpu.ramTotal) + "\nRAM Free: " + MemoryToString(info.cpu.ramFree);
316 out += "\nGPU: " + FrequencyLoadToString(info.gpu.frequencyLoad);
317 return out;
318 }
319
GetDeviceFrequencyString()320 std::string RSTelemetry::GetDeviceFrequencyString()
321 {
322 std::string out;
323
324 constexpr int32_t count = 3;
325 for (int32_t i = 0; i < count; i++) {
326 const auto current = GetMetricFloat(GetCpuCurrentFrequencyPolicyPath(i)) * Utils::MICRO;
327 const auto max = GetMetricFloat(GetCpuMaxFrequencyPolicyPath(i)) * Utils::MICRO;
328 const auto min = GetMetricFloat(GetCpuMinFrequencyPolicyPath(i)) * Utils::MICRO;
329 out += "CPU" + std::to_string(i) + ": " + FrequencyToString(current) + "(min=" + FrequencyToString(min) +
330 " max=" + FrequencyToString(max) + ")\n";
331 }
332
333 const DeviceInfo info = GetDeviceInfo();
334 out += "GPU: " + FrequencyLoadToString(info.gpu.frequencyLoad);
335
336 return out;
337 }
338
GetCpuAffinityString()339 std::string RSTelemetry::GetCpuAffinityString()
340 {
341 std::string out = "Cpu affinity mask: ";
342 const uint32_t cores = GetCoreCount();
343 for (uint32_t i = 0; i < cores; i++) {
344 out += Utils::GetCpuAffinity(i) ? "1" : "0";
345 }
346
347 return out;
348 }
349 } // namespace OHOS::Rosen