[PVR][Estuary] Timer settings dialog: Show client name in timer type selection dialog...
[xbmc.git] / xbmc / platform / linux / CPUInfoLinux.cpp
blob88aad500289283830241303f06ddf38037c2c0f5
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "CPUInfoLinux.h"
11 #include "utils/StringUtils.h"
12 #include "utils/Temperature.h"
14 #include "platform/linux/SysfsPath.h"
16 #include <fstream>
17 #include <regex>
18 #include <sstream>
19 #include <vector>
21 #if (defined(__arm__) && defined(HAS_NEON)) || defined(__aarch64__)
22 #include <asm/hwcap.h>
23 #include <sys/auxv.h>
24 #elif defined(__i386__) || defined(__x86_64__)
25 #include <cpuid.h>
26 #endif
28 #include <unistd.h>
30 namespace
32 enum CpuStates
34 STATE_USER,
35 STATE_NICE,
36 STATE_SYSTEM,
37 STATE_IDLE,
38 STATE_IOWAIT,
39 STATE_IRQ,
40 STATE_SOFTIRQ,
41 STATE_STEAL,
42 STATE_GUEST,
43 STATE_GUEST_NICE,
44 STATE_MAX
47 struct CpuData
49 public:
50 std::size_t GetActiveTime() const
52 return state[STATE_USER] + state[STATE_NICE] + state[STATE_SYSTEM] + state[STATE_IRQ] +
53 state[STATE_SOFTIRQ] + state[STATE_STEAL] + state[STATE_GUEST] + state[STATE_GUEST_NICE];
56 std::size_t GetIdleTime() const { return state[STATE_IDLE] + state[STATE_IOWAIT]; }
58 std::size_t GetTotalTime() const { return GetActiveTime() + GetIdleTime(); }
60 std::string cpu;
61 std::size_t state[STATE_MAX];
63 } // namespace
65 std::shared_ptr<CCPUInfo> CCPUInfo::GetCPUInfo()
67 return std::make_shared<CCPUInfoLinux>();
70 CCPUInfoLinux::CCPUInfoLinux()
72 CSysfsPath machinePath{"/sys/bus/soc/devices/soc0/machine"};
73 if (machinePath.Exists())
74 m_cpuHardware = machinePath.Get<std::string>();
76 CSysfsPath familyPath{"/sys/bus/soc/devices/soc0/family"};
77 if (familyPath.Exists())
78 m_cpuSoC = familyPath.Get<std::string>();
80 CSysfsPath socPath{"/sys/bus/soc/devices/soc0/soc_id"};
81 if (socPath.Exists())
82 m_cpuSoC += " " + socPath.Get<std::string>();
84 CSysfsPath revisionPath{"/sys/bus/soc/devices/soc0/revision"};
85 if (revisionPath.Exists())
86 m_cpuRevision += revisionPath.Get<std::string>();
88 CSysfsPath serialPath{"/sys/bus/soc/devices/soc0/serial_number"};
89 if (serialPath.Exists())
90 m_cpuSerial += serialPath.Get<std::string>();
92 const std::string freqStr{"/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq"};
93 CSysfsPath freqPath{freqStr};
94 if (freqPath.Exists())
95 m_freqPath = freqStr;
97 const std::array<std::string, 4> modules = {
98 "coretemp",
99 "k10temp",
100 "scpi_sensors",
101 "imx_thermal_zone",
104 for (int i = 0; i < 20; i++)
106 CSysfsPath path{"/sys/class/hwmon/hwmon" + std::to_string(i) + "/name"};
107 if (!path.Exists())
108 continue;
110 auto name = path.Get<std::string>();
112 if (name.empty())
113 continue;
115 for (const auto& module : modules)
117 if (module == name)
119 std::string tempStr{"/sys/class/hwmon/hwmon" + std::to_string(i) + "/temp1_input"};
120 CSysfsPath tempPath{tempStr};
121 if (!tempPath.Exists())
122 continue;
124 m_tempPath = tempStr;
125 break;
129 if (!m_tempPath.empty())
130 break;
133 m_cpuCount = sysconf(_SC_NPROCESSORS_ONLN);
135 for (int core = 0; core < m_cpuCount; core++)
137 CoreInfo coreInfo;
138 coreInfo.m_id = core;
139 m_cores.emplace_back(coreInfo);
142 #if defined(__i386__) || defined(__x86_64__)
143 unsigned int eax;
144 unsigned int ebx;
145 unsigned int ecx;
146 unsigned int edx;
148 m_cpuVendor.clear();
150 if (__get_cpuid(CPUID_INFOTYPE_MANUFACTURER, &eax, &ebx, &ecx, &edx))
152 m_cpuVendor.append(reinterpret_cast<const char*>(&ebx), 4);
153 m_cpuVendor.append(reinterpret_cast<const char*>(&edx), 4);
154 m_cpuVendor.append(reinterpret_cast<const char*>(&ecx), 4);
157 if (__get_cpuid(CPUID_INFOTYPE_EXTENDED_IMPLEMENTED, &eax, &ebx, &ecx, &edx))
159 if (eax >= CPUID_INFOTYPE_PROCESSOR_3)
161 m_cpuModel.clear();
163 if (__get_cpuid(CPUID_INFOTYPE_PROCESSOR_1, &eax, &ebx, &ecx, &edx))
165 m_cpuModel.append(reinterpret_cast<const char*>(&eax), 4);
166 m_cpuModel.append(reinterpret_cast<const char*>(&ebx), 4);
167 m_cpuModel.append(reinterpret_cast<const char*>(&ecx), 4);
168 m_cpuModel.append(reinterpret_cast<const char*>(&edx), 4);
171 if (__get_cpuid(CPUID_INFOTYPE_PROCESSOR_2, &eax, &ebx, &ecx, &edx))
173 m_cpuModel.append(reinterpret_cast<const char*>(&eax), 4);
174 m_cpuModel.append(reinterpret_cast<const char*>(&ebx), 4);
175 m_cpuModel.append(reinterpret_cast<const char*>(&ecx), 4);
176 m_cpuModel.append(reinterpret_cast<const char*>(&edx), 4);
179 if (__get_cpuid(CPUID_INFOTYPE_PROCESSOR_3, &eax, &ebx, &ecx, &edx))
181 m_cpuModel.append(reinterpret_cast<const char*>(&eax), 4);
182 m_cpuModel.append(reinterpret_cast<const char*>(&ebx), 4);
183 m_cpuModel.append(reinterpret_cast<const char*>(&ecx), 4);
184 m_cpuModel.append(reinterpret_cast<const char*>(&edx), 4);
189 if (__get_cpuid(CPUID_INFOTYPE_STANDARD, &eax, &eax, &ecx, &edx))
191 if (edx & CPUID_00000001_EDX_MMX)
192 m_cpuFeatures |= CPU_FEATURE_MMX;
194 if (edx & CPUID_00000001_EDX_SSE)
195 m_cpuFeatures |= CPU_FEATURE_SSE;
197 if (edx & CPUID_00000001_EDX_SSE2)
198 m_cpuFeatures |= CPU_FEATURE_SSE2;
200 if (ecx & CPUID_00000001_ECX_SSE3)
201 m_cpuFeatures |= CPU_FEATURE_SSE3;
203 if (ecx & CPUID_00000001_ECX_SSSE3)
204 m_cpuFeatures |= CPU_FEATURE_SSSE3;
206 if (ecx & CPUID_00000001_ECX_SSE4)
207 m_cpuFeatures |= CPU_FEATURE_SSE4;
209 if (ecx & CPUID_00000001_ECX_SSE42)
210 m_cpuFeatures |= CPU_FEATURE_SSE42;
213 if (__get_cpuid(CPUID_INFOTYPE_EXTENDED_IMPLEMENTED, &eax, &eax, &ecx, &edx))
215 if (eax >= CPUID_INFOTYPE_EXTENDED)
217 if (edx & CPUID_80000001_EDX_MMX)
218 m_cpuFeatures |= CPU_FEATURE_MMX;
220 if (edx & CPUID_80000001_EDX_MMX2)
221 m_cpuFeatures |= CPU_FEATURE_MMX2;
223 if (edx & CPUID_80000001_EDX_3DNOW)
224 m_cpuFeatures |= CPU_FEATURE_3DNOW;
226 if (edx & CPUID_80000001_EDX_3DNOWEXT)
227 m_cpuFeatures |= CPU_FEATURE_3DNOWEXT;
230 #else
231 std::ifstream cpuinfo("/proc/cpuinfo");
232 std::regex re(".*: (.*)$");
234 for (std::string line; std::getline(cpuinfo, line);)
236 std::smatch match;
238 if (std::regex_match(line, match, re))
240 if (match.size() == 2)
242 std::ssub_match value = match[1];
244 if (line.find("model name") != std::string::npos)
246 if (m_cpuModel.empty())
247 m_cpuModel = value.str();
250 if (line.find("BogoMIPS") != std::string::npos)
252 if (m_cpuBogoMips.empty())
253 m_cpuBogoMips = value.str();
256 if (line.find("Hardware") != std::string::npos)
258 if (m_cpuHardware.empty())
259 m_cpuHardware = value.str();
262 if (line.find("Serial") != std::string::npos)
264 if (m_cpuSerial.empty())
265 m_cpuSerial = value.str();
268 if (line.find("Revision") != std::string::npos)
270 if (m_cpuRevision.empty())
271 m_cpuRevision = value.str();
276 #endif
278 m_cpuModel = m_cpuModel.substr(0, m_cpuModel.find(char(0))); // remove extra null terminations
280 #if defined(HAS_NEON) && defined(__arm__)
281 if (getauxval(AT_HWCAP) & HWCAP_NEON)
282 m_cpuFeatures |= CPU_FEATURE_NEON;
283 #endif
285 #if defined(HAS_NEON) && defined(__aarch64__)
286 if (getauxval(AT_HWCAP) & HWCAP_ASIMD)
287 m_cpuFeatures |= CPU_FEATURE_NEON;
288 #endif
290 // Set MMX2 when SSE is present as SSE is a superset of MMX2 and Intel doesn't set the MMX2 cap
291 if (m_cpuFeatures & CPU_FEATURE_SSE)
292 m_cpuFeatures |= CPU_FEATURE_MMX2;
295 int CCPUInfoLinux::GetUsedPercentage()
297 if (!m_nextUsedReadTime.IsTimePast())
298 return m_lastUsedPercentage;
300 std::vector<CpuData> cpuData;
302 std::ifstream infile("/proc/stat");
304 for (std::string line; std::getline(infile, line);)
306 if (line.find("cpu") != std::string::npos)
308 std::istringstream ss(line);
309 CpuData info;
311 ss >> info.cpu;
313 for (int i = 0; i < STATE_MAX; i++)
315 ss >> info.state[i];
318 cpuData.emplace_back(info);
322 auto activeTime = cpuData.front().GetActiveTime() - m_activeTime;
323 auto idleTime = cpuData.front().GetIdleTime() - m_idleTime;
324 auto totalTime = cpuData.front().GetTotalTime() - m_totalTime;
326 m_activeTime += activeTime;
327 m_idleTime += idleTime;
328 m_totalTime += totalTime;
330 m_lastUsedPercentage = activeTime * 100.0f / totalTime;
331 m_nextUsedReadTime.Set(MINIMUM_TIME_BETWEEN_READS);
333 cpuData.erase(cpuData.begin());
335 for (std::size_t core = 0; core < cpuData.size(); core++)
337 auto activeTime = cpuData[core].GetActiveTime() - m_cores[core].m_activeTime;
338 auto idleTime = cpuData[core].GetIdleTime() - m_cores[core].m_idleTime;
339 auto totalTime = cpuData[core].GetTotalTime() - m_cores[core].m_totalTime;
341 m_cores[core].m_usagePercent = activeTime * 100.0 / totalTime;
343 m_cores[core].m_activeTime += activeTime;
344 m_cores[core].m_idleTime += idleTime;
345 m_cores[core].m_totalTime += totalTime;
348 return static_cast<int>(m_lastUsedPercentage);
351 float CCPUInfoLinux::GetCPUFrequency()
353 if (m_freqPath.empty())
354 return 0;
356 CSysfsPath path{m_freqPath};
357 return path.Get<float>() / 1000.0f;
360 bool CCPUInfoLinux::GetTemperature(CTemperature& temperature)
362 if (CheckUserTemperatureCommand(temperature))
363 return true;
365 if (m_tempPath.empty())
366 return false;
368 CSysfsPath path{m_tempPath};
369 double value = path.Get<double>() / 1000.0;
371 temperature = CTemperature::CreateFromCelsius(value);
372 temperature.SetValid(true);
374 return true;