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