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 static std::string path;
46 if (!path.empty()) {
47 return path;
48 }
49
50 std::vector<std::string> directories;
51 Utils::IterateDirectory(*TERMAL, directories);
52
53 std::string type;
54 for (const std::string& directory : directories) {
55 Utils::LoadContent(Utils::MakePath(directory, "type"), type);
56 if (type.find("soc_thermal") != std::string::npos) {
57 path = Utils::MakePath(directory, "temp");
58 break;
59 }
60 }
61
62 return path;
63 }
64
65 // cpufreq
GetCpuFrequencyPath(uint32_t cpu)66 static std::string GetCpuFrequencyPath(uint32_t cpu)
67 {
68 return Utils::MakePath(*CPU_FREQUENCY + std::to_string(cpu), "cpufreq");
69 }
70
GetCpuCurrentFrequencyPath(uint32_t cpu)71 static std::string GetCpuCurrentFrequencyPath(uint32_t cpu)
72 {
73 return Utils::MakePath(GetCpuFrequencyPath(cpu), "scaling_cur_freq");
74 }
75
76 // cpupolicy
GetCpuFrequencyPolicyPath(uint32_t cpu)77 static std::string GetCpuFrequencyPolicyPath(uint32_t cpu)
78 {
79 return *CPU_FREQUENCY_POLICY + std::to_string(cpu);
80 }
81
GetCpuCurrentFrequencyPolicyPath(uint32_t cpu)82 static std::string GetCpuCurrentFrequencyPolicyPath(uint32_t cpu)
83 {
84 return Utils::MakePath(GetCpuFrequencyPolicyPath(cpu), "scaling_cur_freq");
85 }
86
GetCpuMinFrequencyPolicyPath(uint32_t cpu)87 static std::string GetCpuMinFrequencyPolicyPath(uint32_t cpu)
88 {
89 return Utils::MakePath(GetCpuFrequencyPolicyPath(cpu), "scaling_min_freq");
90 }
91
GetCpuMaxFrequencyPolicyPath(uint32_t cpu)92 static std::string GetCpuMaxFrequencyPolicyPath(uint32_t cpu)
93 {
94 return Utils::MakePath(GetCpuFrequencyPolicyPath(cpu), "scaling_max_freq");
95 }
96
TemperatureToString(float temperature)97 static std::string TemperatureToString(float temperature)
98 {
99 return std::to_string(temperature) + " °C";
100 }
101
CurrentToString(float current)102 static std::string CurrentToString(float current)
103 {
104 return std::to_string(current) + " mA";
105 }
106
VoltageToString(float voltage)107 static std::string VoltageToString(float voltage)
108 {
109 return std::to_string(voltage) + " V";
110 }
111
MemoryToString(uint64_t memory)112 static std::string MemoryToString(uint64_t memory)
113 {
114 return std::to_string(memory * Utils::MICRO) + " GB";
115 }
116
FrequencyToString(float frequency)117 static std::string FrequencyToString(float frequency)
118 {
119 return std::to_string(frequency) + " GHz";
120 }
121
LoadToString(float load)122 static std::string LoadToString(float load)
123 {
124 return std::to_string(load) + " %";
125 }
126
FrequencyLoadToString(const FrequencyLoadInfo & info)127 static std::string FrequencyLoadToString(const FrequencyLoadInfo& info)
128 {
129 return FrequencyToString(info.current) + "(min: " + FrequencyToString(info.min) +
130 " max: " + FrequencyToString(info.max) + " load: " + LoadToString(info.load) + ")";
131 }
132
GetMetric(const std::string & name)133 static std::string GetMetric(const std::string& name)
134 {
135 std::string metric("0");
136 Utils::LoadContent(name, metric);
137 return metric;
138 }
139
GetMetricFloat(const std::string & name)140 static float GetMetricFloat(const std::string& name)
141 {
142 return Utils::ToFp32(GetMetric(name));
143 }
144
GetCPUTemperature(CPUInfo & cpu)145 static void GetCPUTemperature(CPUInfo& cpu)
146 {
147 cpu.temperature = GetMetricFloat(GetTemperaturePath()) * Utils::MILLI;
148 }
149
GetBattery(CPUInfo & cpu)150 static void GetBattery(CPUInfo& cpu)
151 {
152 cpu.current = GetMetricFloat(*CURRENT) * Utils::MICRO;
153 cpu.voltage = GetMetricFloat(*VOLTAGE) * Utils::MICRO;
154 }
155
GetValue(const std::string & name,const std::vector<std::string> & lines,uint64_t & value)156 static void GetValue(const std::string& name, const std::vector<std::string>& lines, uint64_t& value)
157 {
158 for (const std::string& line : lines) {
159 if (line.find(name) != std::string::npos) {
160 value = Utils::ToUint64(Utils::ExtractNumber(line));
161 return;
162 }
163 }
164 }
165
GetCPUMemory(CPUInfo & cpu)166 static void GetCPUMemory(CPUInfo& cpu)
167 {
168 std::vector<std::string> lines;
169 Utils::LoadLines(*MEMORY, lines);
170
171 if (!lines.empty()) {
172 GetValue("MemTotal", lines, cpu.ramTotal);
173 GetValue("MemFree", lines, cpu.ramFree);
174 }
175 }
176
GetCpuTime(const std::vector<std::string> & args,CpuTime & info)177 static uint32_t GetCpuTime(const std::vector<std::string>& args, CpuTime& info)
178 {
179 constexpr size_t cpuWordSize = 3;
180 if (args[0].size() == cpuWordSize) {
181 // this is cpu total line
182 return UINT_MAX;
183 }
184
185 info.total = 0;
186 for (uint32_t i = 0; i < CpuTime::COUNT; i++) {
187 info.times[i] = Utils::ToUint64(args[i + 1]);
188 info.total += info.times[i];
189 }
190
191 return Utils::ToUint64(args[0].data() + cpuWordSize);
192 }
193
IsCpuLine(const std::vector<std::string> & args)194 static bool IsCpuLine(const std::vector<std::string>& args)
195 {
196 constexpr size_t required = 11;
197 return (args.size() == required) && (args[0].find("cpu") == 0);
198 }
199
GetCpuTime(std::vector<CpuTime> & infos)200 static void GetCpuTime(std::vector<CpuTime>& infos)
201 {
202 std::vector<std::string> lines;
203 Utils::LoadLines(*CPU_USAGE, lines);
204 if (lines.empty()) {
205 return;
206 }
207
208 size_t processed = 0u;
209 for (const auto& line : lines) {
210 const std::vector<std::string> args = Utils::Split(line);
211 if (!IsCpuLine(args) || (processed == infos.size())) {
212 // either there are no more cpu lines in the file
213 // or all cpus were processed
214 return;
215 }
216
217 CpuTime info;
218 const size_t id = GetCpuTime(args, info);
219 if (id < infos.size()) {
220 infos[id] = info;
221 processed++;
222 }
223 }
224 }
225
GetCpuTotalUsage(const CpuTime & info,const CpuTime & lastInfo)226 static double GetCpuTotalUsage(const CpuTime& info, const CpuTime& lastInfo)
227 {
228 const double deltaTotal = info.total - lastInfo.total;
229 if (deltaTotal <= 0.0) {
230 return 0.0;
231 }
232
233 double usage = 0.0;
234 for (uint32_t i = 0; i < CpuTime::COUNT; i++) {
235 usage += std::max(info.times[i] - lastInfo.times[i], 0.0);
236 }
237
238 constexpr double ratioToPercent = 100.0;
239 return usage * ratioToPercent / deltaTotal;
240 }
241
GetCoreCount()242 static uint32_t GetCoreCount()
243 {
244 std::string line;
245 Utils::LoadLine(*CPU_CORES, line);
246
247 if (line.empty()) {
248 return 0;
249 }
250
251 if (line.size() == 1) {
252 return 1;
253 }
254
255 constexpr size_t multiCoreLineLength = 3;
256 if (line.size() >= multiCoreLineLength) {
257 constexpr uint32_t maxCoreIndex = 2;
258 return Utils::ToUint32(line.substr(maxCoreIndex)) + 1;
259 }
260
261 return 0;
262 }
263
GetCPUCores(CPUInfo & cpu)264 static void GetCPUCores(CPUInfo& cpu)
265 {
266 static const uint32_t CORE_COUNT = GetCoreCount();
267 cpu.cores = std::min(CPUInfo::MAX_CORES, CORE_COUNT);
268
269 for (uint32_t i = 0; i < cpu.cores; i++) {
270 cpu.coreFrequencyLoad[i].current = GetMetricFloat(GetCpuCurrentFrequencyPath(i)) * Utils::MICRO;
271 }
272
273 static std::vector<CpuTime> cpuTimeInfos;
274 if (cpuTimeInfos.empty()) {
275 cpuTimeInfos.resize(cpu.cores);
276 }
277
278 static std::vector<CpuTime> lastCpuTimeInfos;
279 if (lastCpuTimeInfos.empty()) {
280 lastCpuTimeInfos.resize(cpu.cores);
281 }
282
283 GetCpuTime(cpuTimeInfos);
284 for (size_t i = 0; i < cpu.cores; i++) {
285 cpu.coreFrequencyLoad[i].load = GetCpuTotalUsage(cpuTimeInfos[i], lastCpuTimeInfos[i]);
286 }
287 lastCpuTimeInfos = cpuTimeInfos;
288 }
289
GetGPUFrequencyLoad(GPUInfo & gpu)290 static void GetGPUFrequencyLoad(GPUInfo& gpu)
291 {
292 gpu.frequencyLoad.current = GetMetricFloat(*GPU_FREQUENCY) * Utils::NANO;
293 gpu.frequencyLoad.min = GetMetricFloat(*GPU_FREQUENCY_MIN) * Utils::NANO;
294 gpu.frequencyLoad.max = GetMetricFloat(*GPU_FREQUENCY_MAX) * Utils::NANO;
295 gpu.frequencyLoad.load = GetMetricFloat(*GPU_LOAD);
296 }
297
GetDeviceInfo()298 const DeviceInfo& RSTelemetry::GetDeviceInfo()
299 {
300 static DeviceInfo info;
301 GetBattery(info.cpu);
302 GetCPUTemperature(info.cpu);
303 GetCPUMemory(info.cpu);
304 GetCPUCores(info.cpu);
305 GetGPUFrequencyLoad(info.gpu);
306 return info;
307 }
308
GetDeviceInfoString()309 std::string RSTelemetry::GetDeviceInfoString()
310 {
311 const DeviceInfo info = GetDeviceInfo();
312
313 std::string out;
314 for (size_t i = 0; i < info.cpu.cores; i++) {
315 out += +"\nCPU" + std::to_string(i) + ": " + FrequencyLoadToString(info.cpu.coreFrequencyLoad[i]);
316 }
317
318 out += "\nTemperature: " + TemperatureToString(info.cpu.temperature) +
319 "\nCurrent: " + CurrentToString(info.cpu.current) + "\nVoltage: " + VoltageToString(info.cpu.voltage) +
320 "\nRAM Total: " + MemoryToString(info.cpu.ramTotal) + "\nRAM Free: " + MemoryToString(info.cpu.ramFree) +
321 "\nGPU: " + FrequencyLoadToString(info.gpu.frequencyLoad);
322
323 return out;
324 }
325
GetDeviceFrequencyString()326 std::string RSTelemetry::GetDeviceFrequencyString()
327 {
328 std::string out;
329
330 constexpr int32_t count = 3;
331 for (int32_t i = 0; i < count; i++) {
332 const auto current = GetMetricFloat(GetCpuCurrentFrequencyPolicyPath(i)) * Utils::MICRO;
333 const auto max = GetMetricFloat(GetCpuMaxFrequencyPolicyPath(i)) * Utils::MICRO;
334 const auto min = GetMetricFloat(GetCpuMinFrequencyPolicyPath(i)) * Utils::MICRO;
335 out += "CPU" + std::to_string(i) + ": " + FrequencyToString(current) + "(min=" + FrequencyToString(min) +
336 " max=" + FrequencyToString(max) + ")\n";
337 }
338
339 const DeviceInfo info = GetDeviceInfo();
340 out += "GPU: " + FrequencyLoadToString(info.gpu.frequencyLoad);
341
342 return out;
343 }
344
GetCpuAffinityString()345 std::string RSTelemetry::GetCpuAffinityString()
346 {
347 std::string out = "Cpu affinity mask: ";
348 const uint32_t cores = GetCoreCount();
349 for (uint32_t i = 0; i < cores; i++) {
350 out += Utils::GetCpuAffinity(i) ? "1" : "0";
351 }
352
353 return out;
354 }
355 } // namespace OHOS::Rosen