2 * Copyright (C) 2005-2008 Team XBMC
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)
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
27 #include <sys/types.h>
28 #include <sys/sysctl.h>
30 #include <mach-o/arch.h>
35 #include "AdvancedSettings.h"
40 #define MINIMUM_TIME_BETWEEN_READS 2
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
)
50 tv
->tv_usec
= t
.millitm
* 1000;
53 #define gettimeofday(TV, TZ) _private_gettimeofday((TV), (TZ))
56 CCPUInfo::CCPUInfo(void)
58 m_fProcStat
= m_fProcTemperature
= m_fCPUInfo
= NULL
;
59 m_lastUsedPercentage
= 0;
64 // The number of cores.
65 if (sysctlbyname("hw.activecpu", &m_cpuCount
, &len
, NULL
, 0) == -1)
70 const NXArchInfo
*info
= NXGetLocalArchInfo();
72 m_cpuModel
= info
->description
;
74 // NXGetLocalArchInfo is ugly for intel so keep using this method
77 if (sysctlbyname("machdep.cpu.brand_string", &buffer
, &len
, NULL
, 0) == 0)
81 // Go through each core.
82 for (int i
=0; i
<m_cpuCount
; i
++)
86 m_cores
[core
.m_id
] = core
;
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
);
98 m_cpuModel
= "Unknown";
102 SYSTEM_INFO siSysInfo
;
103 GetSystemInfo(&siSysInfo
);
104 m_cpuCount
= siSysInfo
.dwNumberOfProcessors
;
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");
126 while (fgets(buffer
, sizeof(buffer
), m_fCPUInfo
))
128 if (strncmp(buffer
, "processor", strlen("processor"))==0)
130 char *needle
= strstr(buffer
, ":");
134 core
.m_id
= atoi(needle
+2);
136 m_cores
[core
.m_id
] = core
;
140 else if (strncmp(buffer
, "vendor_id", strlen("vendor_id"))==0)
142 char *needle
= strstr(buffer
, ":");
143 if (needle
&& strlen(needle
)>3)
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)
157 m_cores
[nCurrId
].m_strModel
= m_cpuModel
;
158 m_cores
[nCurrId
].m_strModel
.Trim();
166 m_cpuModel
= "Unknown";
169 readProcStat(m_userTicks
, m_niceTicks
, m_systemTicks
, m_idleTicks
, m_ioTicks
);
173 CCPUInfo::~CCPUInfo()
175 if (m_fProcStat
!= NULL
)
178 if (m_fProcTemperature
!= NULL
)
179 fclose(m_fProcTemperature
);
181 if (m_fCPUInfo
!= NULL
)
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
))
203 userTicks
-= m_userTicks
;
204 niceTicks
-= m_niceTicks
;
205 systemTicks
-= m_systemTicks
;
206 idleTicks
-= m_idleTicks
;
207 ioTicks
-= m_ioTicks
;
210 if(userTicks
+ systemTicks
== 0)
211 return m_lastUsedPercentage
;
212 int result
= (int) ((userTicks
+ systemTicks
- idleTicks
) * 100 / (userTicks
+ systemTicks
));
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
));
219 m_userTicks
+= userTicks
;
220 m_niceTicks
+= niceTicks
;
221 m_systemTicks
+= systemTicks
;
222 m_idleTicks
+= idleTicks
;
223 m_ioTicks
+= ioTicks
;
225 m_lastUsedPercentage
= result
;
230 float CCPUInfo::getCPUFrequency()
232 // Get CPU frequency, scaled to MHz.
235 size_t len
= sizeof(hz
);
236 if (sysctlbyname("hw.cpufrequency", &hz
, &len
, NULL
, 0) == -1)
238 return hz
/ 1000000.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
);
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
);
271 CTemperature
CCPUInfo::getTemperature()
277 CStdString cmd
= g_advancedSettings
.m_cpuTempCmd
;
279 if (cmd
.IsEmpty() && m_fProcTemperature
== NULL
)
280 return CTemperature();
284 p
= popen (cmd
.c_str(), "r");
287 ret
= fscanf(p
, "%d %c", &value
, &scale
);
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
);
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())
319 const CoreInfo
&CCPUInfo::GetCoreInfo(int nCoreId
)
321 map
<int, CoreInfo
>::iterator iter
= m_cores
.find(nCoreId
);
322 if (iter
!= m_cores
.end())
325 static CoreInfo 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
)
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
;
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
;
365 if (m_fProcStat
== NULL
)
372 if (!fgets(buf
, sizeof(buf
), m_fProcStat
))
375 int num
= sscanf(buf
, "cpu %llu %llu %llu %llu %llu %*s\n", &user
, &nice
, &system
, &idle
, &io
);
379 while (fgets(buf
, sizeof(buf
), m_fProcStat
) && num
>= 4)
381 unsigned long long coreUser
, coreNice
, coreSystem
, coreIdle
, coreIO
;
383 num
= sscanf(buf
, "cpu%d %llu %llu %llu %llu %llu %*s\n", &nCpu
, &coreUser
, &coreNice
, &coreSystem
, &coreIdle
, &coreIO
);
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
;
408 m_lastReadTime
= time(NULL
);
412 CStdString
CCPUInfo::GetCoresUsageString() const
415 map
<int, CoreInfo
>::const_iterator iter
= m_cores
.begin();
416 while (iter
!= m_cores
.end())
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
);
423 strCore
.Format("CPU%d: %3.1f%% ",iter
->first
, iter
->second
.m_fPct
);
438 int r = c.getUsedPercentage();