changed: update version strings for beta4
[xbmc.git] / xbmc / utils / CPUInfo.cpp
blob5dabf4c70027706dfef66814a5a81990e12a994e
1 /*
2 * Copyright (C) 2005-2008 Team XBMC
3 * http://www.xbmc.org
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
22 #include "CPUInfo.h"
23 #include <string>
24 #include <string.h>
26 #ifdef __APPLE__
27 #include <sys/types.h>
28 #include <sys/sysctl.h>
29 #ifdef __ppc__
30 #include <mach-o/arch.h>
31 #endif
32 #endif
34 #include "log.h"
35 #include "AdvancedSettings.h"
37 using namespace std;
39 // In seconds
40 #define MINIMUM_TIME_BETWEEN_READS 2
42 #ifdef _WIN32
43 /* replacement gettimeofday implementation, copy from dvdnav_internal.h */
44 #include <sys/timeb.h>
45 static inline int _private_gettimeofday( struct timeval *tv, void *tz )
47 struct timeb t;
48 ftime( &t );
49 tv->tv_sec = t.time;
50 tv->tv_usec = t.millitm * 1000;
51 return 0;
53 #define gettimeofday(TV, TZ) _private_gettimeofday((TV), (TZ))
54 #endif
56 CCPUInfo::CCPUInfo(void)
58 m_fProcStat = m_fProcTemperature = m_fCPUInfo = NULL;
59 m_lastUsedPercentage = 0;
61 #ifdef __APPLE__
62 size_t len = 4;
64 // The number of cores.
65 if (sysctlbyname("hw.activecpu", &m_cpuCount, &len, NULL, 0) == -1)
66 m_cpuCount = 1;
68 // The model.
69 #ifdef __ppc__
70 const NXArchInfo *info = NXGetLocalArchInfo();
71 if (info != NULL)
72 m_cpuModel = info->description;
73 #else
74 // NXGetLocalArchInfo is ugly for intel so keep using this method
75 char buffer[512];
76 len = 512;
77 if (sysctlbyname("machdep.cpu.brand_string", &buffer, &len, NULL, 0) == 0)
78 m_cpuModel = buffer;
79 #endif
81 // Go through each core.
82 for (int i=0; i<m_cpuCount; i++)
84 CoreInfo core;
85 core.m_id = i;
86 m_cores[core.m_id] = core;
88 #elif defined(_WIN32)
89 char rgValue [128];
90 HKEY hKey;
91 DWORD dwSize=128;
92 DWORD dwMHz=0;
93 LONG ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",0, KEY_READ, &hKey);
94 ret = RegQueryValueEx(hKey,"ProcessorNameString", NULL, NULL, (LPBYTE)rgValue, &dwSize);
95 if(ret == 0)
96 m_cpuModel = rgValue;
97 else
98 m_cpuModel = "Unknown";
100 RegCloseKey(hKey);
102 SYSTEM_INFO siSysInfo;
103 GetSystemInfo(&siSysInfo);
104 m_cpuCount = siSysInfo.dwNumberOfProcessors;
106 CoreInfo core;
107 m_cores[0] = core;
109 #else
110 m_fProcStat = fopen("/proc/stat", "r");
111 m_fProcTemperature = fopen("/proc/acpi/thermal_zone/THM0/temperature", "r");
112 if (m_fProcTemperature == NULL)
113 m_fProcTemperature = fopen("/proc/acpi/thermal_zone/THRM/temperature", "r");
114 if (m_fProcTemperature == NULL)
115 m_fProcTemperature = fopen("/proc/acpi/thermal_zone/THR0/temperature", "r");
116 if (m_fProcTemperature == NULL)
117 m_fProcTemperature = fopen("/proc/acpi/thermal_zone/TZ0/temperature", "r");
119 m_fCPUInfo = fopen("/proc/cpuinfo", "r");
120 m_cpuCount = 0;
121 if (m_fCPUInfo)
123 char buffer[512];
125 int nCurrId = 0;
126 while (fgets(buffer, sizeof(buffer), m_fCPUInfo))
128 if (strncmp(buffer, "processor", strlen("processor"))==0)
130 char *needle = strstr(buffer, ":");
131 if (needle)
133 CoreInfo core;
134 core.m_id = atoi(needle+2);
135 nCurrId = core.m_id;
136 m_cores[core.m_id] = core;
138 m_cpuCount++;
140 else if (strncmp(buffer, "vendor_id", strlen("vendor_id"))==0)
142 char *needle = strstr(buffer, ":");
143 if (needle && strlen(needle)>3)
145 needle+=2;
146 m_cores[nCurrId].m_strVendor = needle;
147 m_cores[nCurrId].m_strVendor.Trim();
150 else if (strncmp(buffer, "model name", strlen("model name"))==0)
152 char *needle = strstr(buffer, ":");
153 if (needle && strlen(needle)>3)
155 needle+=2;
156 m_cpuModel = needle;
157 m_cores[nCurrId].m_strModel = m_cpuModel;
158 m_cores[nCurrId].m_strModel.Trim();
163 else
165 m_cpuCount = 1;
166 m_cpuModel = "Unknown";
169 readProcStat(m_userTicks, m_niceTicks, m_systemTicks, m_idleTicks, m_ioTicks);
170 #endif
173 CCPUInfo::~CCPUInfo()
175 if (m_fProcStat != NULL)
176 fclose(m_fProcStat);
178 if (m_fProcTemperature != NULL)
179 fclose(m_fProcTemperature);
181 if (m_fCPUInfo != NULL)
182 fclose(m_fCPUInfo);
185 int CCPUInfo::getUsedPercentage()
187 if (m_lastReadTime + MINIMUM_TIME_BETWEEN_READS > time(NULL))
189 return m_lastUsedPercentage;
192 unsigned long long userTicks;
193 unsigned long long niceTicks;
194 unsigned long long systemTicks;
195 unsigned long long idleTicks;
196 unsigned long long ioTicks;
198 if (!readProcStat(userTicks, niceTicks, systemTicks, idleTicks, ioTicks))
200 return 0;
203 userTicks -= m_userTicks;
204 niceTicks -= m_niceTicks;
205 systemTicks -= m_systemTicks;
206 idleTicks -= m_idleTicks;
207 ioTicks -= m_ioTicks;
209 #ifdef _WIN32
210 if(userTicks + systemTicks == 0)
211 return m_lastUsedPercentage;
212 int result = (int) ((userTicks + systemTicks - idleTicks) * 100 / (userTicks + systemTicks));
213 #else
214 if(userTicks + niceTicks + systemTicks + idleTicks + ioTicks == 0)
215 return m_lastUsedPercentage;
216 int result = (int) ((userTicks + niceTicks + systemTicks) * 100 / (userTicks + niceTicks + systemTicks + idleTicks + ioTicks));
217 #endif
219 m_userTicks += userTicks;
220 m_niceTicks += niceTicks;
221 m_systemTicks += systemTicks;
222 m_idleTicks += idleTicks;
223 m_ioTicks += ioTicks;
225 m_lastUsedPercentage = result;
227 return result;
230 float CCPUInfo::getCPUFrequency()
232 // Get CPU frequency, scaled to MHz.
233 #ifdef __APPLE__
234 long long hz = 0;
235 size_t len = sizeof(hz);
236 if (sysctlbyname("hw.cpufrequency", &hz, &len, NULL, 0) == -1)
237 return 0.f;
238 return hz / 1000000.0;
239 #elif defined _WIN32
240 HKEY hKey;
241 DWORD dwMHz=0;
242 DWORD dwSize=sizeof(dwMHz);
243 LONG ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",0, KEY_READ, &hKey);
244 ret = RegQueryValueEx(hKey,"~MHz", NULL, NULL, (LPBYTE)&dwMHz, &dwSize);
245 RegCloseKey(hKey);
246 if(ret == 0)
248 return float(dwMHz);
250 else
251 return 0.f;
252 #else
253 float mhz = 0.f;
254 char buf[256],
255 *needle = NULL;
256 if (!m_fCPUInfo)
257 return mhz;
258 rewind(m_fCPUInfo);
259 fflush(m_fCPUInfo);
260 while (fgets(buf, 256, m_fCPUInfo) != NULL) {
261 if (strncmp(buf, "cpu MHz", 7) == 0) {
262 needle = strchr(buf, ':');
263 sscanf(++needle, "%f", &mhz);
264 break;
267 return mhz;
268 #endif
271 CTemperature CCPUInfo::getTemperature()
273 int value = 0,
274 ret = 0;
275 char scale = 0;
276 FILE *p = NULL;
277 CStdString cmd = g_advancedSettings.m_cpuTempCmd;
279 if (cmd.IsEmpty() && m_fProcTemperature == NULL)
280 return CTemperature();
282 if (!cmd.IsEmpty())
284 p = popen (cmd.c_str(), "r");
285 if (p)
287 ret = fscanf(p, "%d %c", &value, &scale);
288 pclose(p);
291 else
293 // procfs is deprecated in the linux kernel, we should move away from
294 // using it for temperature data. It doesn't seem that sysfs has a
295 // general enough interface to bother implementing ATM.
296 rewind(m_fProcTemperature);
297 fflush(m_fProcTemperature);
298 ret = fscanf(m_fProcTemperature, "temperature: %d %c", &value, &scale);
301 if (ret != 2)
302 return CTemperature();
304 if (scale == 'C' || scale == 'c')
305 return CTemperature::CreateFromCelsius(value);
306 if (scale == 'F' || scale == 'f')
307 return CTemperature::CreateFromFahrenheit(value);
308 return CTemperature();
311 bool CCPUInfo::HasCoreId(int nCoreId) const
313 map<int, CoreInfo>::const_iterator iter = m_cores.find(nCoreId);
314 if (iter != m_cores.end())
315 return true;
316 return false;
319 const CoreInfo &CCPUInfo::GetCoreInfo(int nCoreId)
321 map<int, CoreInfo>::iterator iter = m_cores.find(nCoreId);
322 if (iter != m_cores.end())
323 return iter->second;
325 static CoreInfo dummy;
326 return dummy;
329 bool CCPUInfo::readProcStat(unsigned long long& user, unsigned long long& nice,
330 unsigned long long& system, unsigned long long& idle, unsigned long long& io)
333 #ifdef _WIN32
334 FILETIME idleTime;
335 FILETIME kernelTime;
336 FILETIME userTime;
337 ULARGE_INTEGER ulTime;
338 unsigned long long coreUser, coreSystem, coreIdle;
339 GetSystemTimes( &idleTime, &kernelTime, &userTime );
340 ulTime.HighPart = userTime.dwHighDateTime;
341 ulTime.LowPart = userTime.dwLowDateTime;
342 user = coreUser = ulTime.QuadPart;
344 ulTime.HighPart = kernelTime.dwHighDateTime;
345 ulTime.LowPart = kernelTime.dwLowDateTime;
346 system = coreSystem = ulTime.QuadPart;
348 ulTime.HighPart = idleTime.dwHighDateTime;
349 ulTime.LowPart = idleTime.dwLowDateTime;
350 idle = coreIdle = ulTime.QuadPart;
352 nice = 0;
354 coreUser -= m_cores[0].m_user;
355 coreSystem -= m_cores[0].m_system;
356 coreIdle -= m_cores[0].m_idle;
357 m_cores[0].m_fPct = ((double)(coreUser + coreSystem - coreIdle) * 100.0) / (double)(coreUser + coreSystem);
358 m_cores[0].m_user += coreUser;
359 m_cores[0].m_system += coreSystem;
360 m_cores[0].m_idle += coreIdle;
362 io = 0;
364 #else
365 if (m_fProcStat == NULL)
366 return false;
368 rewind(m_fProcStat);
369 fflush(m_fProcStat);
371 char buf[256];
372 if (!fgets(buf, sizeof(buf), m_fProcStat))
373 return false;
375 int num = sscanf(buf, "cpu %llu %llu %llu %llu %llu %*s\n", &user, &nice, &system, &idle, &io);
376 if (num < 5)
377 io = 0;
379 while (fgets(buf, sizeof(buf), m_fProcStat) && num >= 4)
381 unsigned long long coreUser, coreNice, coreSystem, coreIdle, coreIO;
382 int nCpu=0;
383 num = sscanf(buf, "cpu%d %llu %llu %llu %llu %llu %*s\n", &nCpu, &coreUser, &coreNice, &coreSystem, &coreIdle, &coreIO);
384 if (num < 6)
385 coreIO = 0;
387 map<int, CoreInfo>::iterator iter = m_cores.find(nCpu);
388 if (num > 4 && iter != m_cores.end())
390 coreUser -= iter->second.m_user;
391 coreNice -= iter->second.m_nice;
392 coreSystem -= iter->second.m_system;
393 coreIdle -= iter->second.m_idle;
394 coreIO -= iter->second.m_io;
396 double total = (double)(coreUser + coreNice + coreSystem + coreIdle + coreIO);
397 iter->second.m_fPct = ((double)(coreUser + coreNice + coreSystem) * 100.0) / total;
399 iter->second.m_user += coreUser;
400 iter->second.m_nice += coreNice;
401 iter->second.m_system += coreSystem;
402 iter->second.m_idle += coreIdle;
403 iter->second.m_io += coreIO;
406 #endif
408 m_lastReadTime = time(NULL);
409 return true;
412 CStdString CCPUInfo::GetCoresUsageString() const
414 CStdString strCores;
415 map<int, CoreInfo>::const_iterator iter = m_cores.begin();
416 while (iter != m_cores.end())
418 CStdString strCore;
419 #ifdef _WIN32
420 // atm we get only the average over all cores
421 strCore.Format("CPU %d core(s) average: %3.1f%% ",m_cpuCount, iter->second.m_fPct);
422 #else
423 strCore.Format("CPU%d: %3.1f%% ",iter->first, iter->second.m_fPct);
424 #endif
425 strCores+=strCore;
426 iter++;
428 return strCores;
431 CCPUInfo g_cpuInfo;
434 int main()
436 CCPUInfo c;
437 usleep(...);
438 int r = c.getUsedPercentage();
439 printf("%d\n", r);