d54627e73cab8d7d8dd6163b3a98dfed0a4f21a5
[vuplus_xbmc] / xbmc / utils / CPUInfo.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
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.
9  *
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.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "CPUInfo.h"
22 #include "Temperature.h"
23 #include <string>
24 #include <string.h>
25
26 #if defined(TARGET_DARWIN)
27 #include <sys/types.h>
28 #include <sys/sysctl.h>
29 #ifdef TARGET_DARWIN_OSX
30 #include "osx/smc.h"
31 #ifdef __ppc__
32 #include <mach-o/arch.h>
33 #endif
34 #endif
35 #endif
36
37 #if defined(TARGET_FREEBSD)
38 #include <sys/types.h>
39 #include <sys/sysctl.h>
40 #include <sys/resource.h>
41 #endif
42
43 #if defined(TARGET_LINUX) && defined(__ARM_NEON__) && !defined(TARGET_ANDROID)
44 #include <fcntl.h>
45 #include <unistd.h>
46 #include <elf.h>
47 #include <linux/auxvec.h>
48 #include <asm/hwcap.h>
49 #endif
50
51 #if defined(TARGET_ANDROID)
52 #include "android/activity/AndroidFeatures.h"
53 #endif
54
55 #ifdef TARGET_WINDOWS
56 #include <intrin.h>
57
58 // Defines to help with calls to CPUID
59 #define CPUID_INFOTYPE_STANDARD 0x00000001
60 #define CPUID_INFOTYPE_EXTENDED 0x80000001
61
62 // Standard Features
63 // Bitmasks for the values returned by a call to cpuid with eax=0x00000001
64 #define CPUID_00000001_ECX_SSE3  (1<<0)
65 #define CPUID_00000001_ECX_SSSE3 (1<<9)
66 #define CPUID_00000001_ECX_SSE4  (1<<19)
67 #define CPUID_00000001_ECX_SSE42 (1<<20)
68
69 #define CPUID_00000001_EDX_MMX   (1<<23)
70 #define CPUID_00000001_EDX_SSE   (1<<25)
71 #define CPUID_00000001_EDX_SSE2  (1<<26)
72
73 // Extended Features
74 // Bitmasks for the values returned by a call to cpuid with eax=0x80000001
75 #define CPUID_80000001_EDX_MMX2     (1<<22)
76 #define CPUID_80000001_EDX_MMX      (1<<23)
77 #define CPUID_80000001_EDX_3DNOWEXT (1<<30)
78 #define CPUID_80000001_EDX_3DNOW    (1<<31)
79
80
81 // Help with the __cpuid intrinsic of MSVC
82 #define CPUINFO_EAX 0
83 #define CPUINFO_EBX 1
84 #define CPUINFO_ECX 2
85 #define CPUINFO_EDX 3
86
87 #endif
88
89 #include "log.h"
90 #include "settings/AdvancedSettings.h"
91 #include "utils/StringUtils.h"
92
93 using namespace std;
94
95 // In milliseconds
96 #define MINIMUM_TIME_BETWEEN_READS 500
97
98 #ifdef TARGET_WINDOWS
99 /* replacement gettimeofday implementation, copy from dvdnav_internal.h */
100 #include <sys/timeb.h>
101 static inline int _private_gettimeofday( struct timeval *tv, void *tz )
102 {
103   struct timeb t;
104   ftime( &t );
105   tv->tv_sec = t.time;
106   tv->tv_usec = t.millitm * 1000;
107   return 0;
108 }
109 #define gettimeofday(TV, TZ) _private_gettimeofday((TV), (TZ))
110 #endif
111
112 CCPUInfo::CCPUInfo(void)
113 {
114   m_fProcStat = m_fProcTemperature = m_fCPUFreq = NULL;
115   m_lastUsedPercentage = 0;
116   m_cpuFeatures = 0;
117
118 #if defined(TARGET_DARWIN)
119   size_t len = 4;
120   std::string cpuVendor;
121   
122   // The number of cores.
123   if (sysctlbyname("hw.activecpu", &m_cpuCount, &len, NULL, 0) == -1)
124       m_cpuCount = 1;
125
126   // The model.
127 #ifdef __ppc__
128   const NXArchInfo *info = NXGetLocalArchInfo();
129   if (info != NULL)
130     m_cpuModel = info->description;
131 #else
132   // NXGetLocalArchInfo is ugly for intel so keep using this method
133   char buffer[512];
134   len = 512;
135   if (sysctlbyname("machdep.cpu.brand_string", &buffer, &len, NULL, 0) == 0)
136     m_cpuModel = buffer;
137
138   // The CPU vendor
139   len = 512;
140   if (sysctlbyname("machdep.cpu.vendor", &buffer, &len, NULL, 0) == 0)
141     cpuVendor = buffer;
142   
143 #endif
144   
145   // The CPU features
146   len = 512;
147   if (sysctlbyname("machdep.cpu.features", &buffer, &len, NULL, 0) == 0)
148   {
149     char* needle = buffer;
150     if (needle)
151     {
152       char* tok = NULL,
153       * save;
154       tok = strtok_r(needle, " ", &save);
155       while (tok)
156       {
157         if (0 == strcmp(tok, "MMX"))
158           m_cpuFeatures |= CPU_FEATURE_MMX;
159         else if (0 == strcmp(tok, "MMXEXT"))
160           m_cpuFeatures |= CPU_FEATURE_MMX2;
161         else if (0 == strcmp(tok, "SSE"))
162           m_cpuFeatures |= CPU_FEATURE_SSE;
163         else if (0 == strcmp(tok, "SSE2"))
164           m_cpuFeatures |= CPU_FEATURE_SSE2;
165         else if (0 == strcmp(tok, "SSE3"))
166           m_cpuFeatures |= CPU_FEATURE_SSE3;
167         else if (0 == strcmp(tok, "SSSE3"))
168           m_cpuFeatures |= CPU_FEATURE_SSSE3;
169         else if (0 == strcmp(tok, "SSE4.1"))
170           m_cpuFeatures |= CPU_FEATURE_SSE4;
171         else if (0 == strcmp(tok, "SSE4.2"))
172           m_cpuFeatures |= CPU_FEATURE_SSE42;
173         tok = strtok_r(NULL, " ", &save);
174       }
175     }
176   }
177
178   // Go through each core.
179   for (int i=0; i<m_cpuCount; i++)
180   {
181     CoreInfo core;
182     core.m_id = i;
183     core.m_strModel = m_cpuModel;
184     core.m_strVendor = cpuVendor;
185     m_cores[core.m_id] = core;
186   }
187
188 #elif defined(TARGET_WINDOWS)
189   char rgValue [128];
190   HKEY hKey;
191   DWORD dwSize=128;
192   DWORD dwMHz=0;
193   LONG ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",0, KEY_READ, &hKey);
194   ret = RegQueryValueEx(hKey,"ProcessorNameString", NULL, NULL, (LPBYTE)rgValue, &dwSize);
195   if(ret == 0)
196     m_cpuModel = rgValue;
197   else
198     m_cpuModel = "Unknown";
199
200   RegCloseKey(hKey);
201
202   SYSTEM_INFO siSysInfo;
203   GetSystemInfo(&siSysInfo);
204   m_cpuCount = siSysInfo.dwNumberOfProcessors;
205
206   CoreInfo core;
207   m_cores[0] = core;
208
209 #elif defined(TARGET_FREEBSD)
210   size_t len;
211   int i;
212   char cpumodel[512];
213
214   len = sizeof(m_cpuCount);
215   if (sysctlbyname("hw.ncpu", &m_cpuCount, &len, NULL, 0) != 0)
216     m_cpuCount = 1;
217
218   len = sizeof(cpumodel);
219   if (sysctlbyname("hw.model", &cpumodel, &len, NULL, 0) != 0)
220     (void)strncpy(cpumodel, "Unknown", 8);
221   m_cpuModel = cpumodel;
222
223   for (i = 0; i < m_cpuCount; i++)
224   {
225     CoreInfo core;
226     core.m_id = i;
227     core.m_strModel = m_cpuModel;
228     m_cores[core.m_id] = core;
229   }
230 #else
231   m_fProcStat = fopen("/proc/stat", "r");
232   m_fProcTemperature = fopen("/proc/acpi/thermal_zone/THM0/temperature", "r");
233   if (m_fProcTemperature == NULL)
234     m_fProcTemperature = fopen("/proc/acpi/thermal_zone/THRM/temperature", "r");
235   if (m_fProcTemperature == NULL)
236     m_fProcTemperature = fopen("/proc/acpi/thermal_zone/THR0/temperature", "r");
237   if (m_fProcTemperature == NULL)
238     m_fProcTemperature = fopen("/proc/acpi/thermal_zone/TZ0/temperature", "r");
239   // read from the new location of the temperature data on new kernels, 2.6.39, 3.0 etc
240   if (m_fProcTemperature == NULL)   
241     m_fProcTemperature = fopen("/sys/class/hwmon/hwmon0/temp1_input", "r");
242   if (m_fProcTemperature == NULL)   
243     m_fProcTemperature = fopen("/sys/class/thermal/thermal_zone0/temp", "r");  // On Raspberry PIs
244
245   m_fCPUFreq = fopen ("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq", "r");
246
247
248   FILE* fCPUInfo = fopen("/proc/cpuinfo", "r");
249   m_cpuCount = 0;
250   if (fCPUInfo)
251   {
252     char buffer[512];
253
254     int nCurrId = 0;
255     while (fgets(buffer, sizeof(buffer), fCPUInfo))
256     {
257       if (strncmp(buffer, "processor", strlen("processor"))==0)
258       {
259         char *needle = strstr(buffer, ":");
260         if (needle)
261         {
262           CoreInfo core;
263           core.m_id = atoi(needle+2);
264           nCurrId = core.m_id;
265           m_cores[core.m_id] = core;
266         }
267         m_cpuCount++;
268       }
269       else if (strncmp(buffer, "vendor_id", strlen("vendor_id"))==0)
270       {
271         char *needle = strstr(buffer, ":");
272         if (needle && strlen(needle)>3)
273         {
274           needle+=2;
275           m_cores[nCurrId].m_strVendor = needle;
276           m_cores[nCurrId].m_strVendor.Trim();
277         }
278       }
279       else if (strncmp(buffer, "Processor", strlen("Processor"))==0)
280       {
281         char *needle = strstr(buffer, ":");
282         if (needle && strlen(needle)>3)
283         {
284           needle+=2;
285           m_cpuModel = needle;
286           m_cores[nCurrId].m_strModel = m_cpuModel;
287           m_cores[nCurrId].m_strModel.Trim();
288         }
289       }
290       else if (strncmp(buffer, "BogoMIPS", strlen("BogoMIPS"))==0)
291       {
292         char *needle = strstr(buffer, ":");
293         if (needle && strlen(needle)>3)
294         {
295           needle+=2;
296           m_cpuBogoMips = needle;
297           m_cores[nCurrId].m_strBogoMips = m_cpuBogoMips;
298           m_cores[nCurrId].m_strBogoMips.Trim();
299         }
300       }
301       else if (strncmp(buffer, "Hardware", strlen("Hardware"))==0)
302       {
303         char *needle = strstr(buffer, ":");
304         if (needle && strlen(needle)>3)
305         {
306           needle+=2;
307           m_cpuHardware = needle;
308           m_cores[nCurrId].m_strHardware = m_cpuHardware;
309           m_cores[nCurrId].m_strHardware.Trim();
310         }
311       }
312       else if (strncmp(buffer, "Revision", strlen("Revision"))==0)
313       {
314         char *needle = strstr(buffer, ":");
315         if (needle && strlen(needle)>3)
316         {
317           needle+=2;
318           m_cpuRevision = needle;
319           m_cores[nCurrId].m_strRevision = m_cpuRevision;
320           m_cores[nCurrId].m_strRevision.Trim();
321         }
322       }
323       else if (strncmp(buffer, "Serial", strlen("Serial"))==0)
324       {
325         char *needle = strstr(buffer, ":");
326         if (needle && strlen(needle)>3)
327         {
328           needle+=2;
329           m_cpuSerial = needle;
330           m_cores[nCurrId].m_strSerial = m_cpuSerial;
331           m_cores[nCurrId].m_strSerial.Trim();
332         }
333       }
334       else if (strncmp(buffer, "model name", strlen("model name"))==0)
335       {
336         char *needle = strstr(buffer, ":");
337         if (needle && strlen(needle)>3)
338         {
339           needle+=2;
340           m_cpuModel = needle;
341           m_cores[nCurrId].m_strModel = m_cpuModel;
342           m_cores[nCurrId].m_strModel.Trim();
343         }
344       }
345       else if (strncmp(buffer, "flags", 5) == 0)
346       {
347         char* needle = strchr(buffer, ':');
348         if (needle)
349         {
350           char* tok = NULL,
351               * save;
352           needle++;
353           tok = strtok_r(needle, " ", &save);
354           while (tok)
355           {
356             if (0 == strcmp(tok, "mmx"))
357               m_cpuFeatures |= CPU_FEATURE_MMX;
358             else if (0 == strcmp(tok, "mmxext"))
359               m_cpuFeatures |= CPU_FEATURE_MMX2;
360             else if (0 == strcmp(tok, "sse"))
361               m_cpuFeatures |= CPU_FEATURE_SSE;
362             else if (0 == strcmp(tok, "sse2"))
363               m_cpuFeatures |= CPU_FEATURE_SSE2;
364             else if (0 == strcmp(tok, "sse3"))
365               m_cpuFeatures |= CPU_FEATURE_SSE3;
366             else if (0 == strcmp(tok, "ssse3"))
367               m_cpuFeatures |= CPU_FEATURE_SSSE3;
368             else if (0 == strcmp(tok, "sse4_1"))
369               m_cpuFeatures |= CPU_FEATURE_SSE4;
370             else if (0 == strcmp(tok, "sse4_2"))
371               m_cpuFeatures |= CPU_FEATURE_SSE42;
372             else if (0 == strcmp(tok, "3dnow"))
373               m_cpuFeatures |= CPU_FEATURE_3DNOW;
374             else if (0 == strcmp(tok, "3dnowext"))
375               m_cpuFeatures |= CPU_FEATURE_3DNOWEXT;
376             tok = strtok_r(NULL, " ", &save);
377           }
378         }
379       }
380     }
381     fclose(fCPUInfo);
382   }
383   else
384   {
385     m_cpuCount = 1;
386     m_cpuModel = "Unknown";
387   }
388
389 #endif
390   StringUtils::RemoveDuplicatedSpacesAndTabs(m_cpuModel);
391
392   /* Set some default for empty string variables */
393   if (m_cpuBogoMips.empty())
394     m_cpuBogoMips = "N/A";
395   if (m_cpuHardware.empty())
396     m_cpuHardware = "N/A";
397   if (m_cpuRevision.empty())
398     m_cpuRevision = "N/A";
399   if (m_cpuSerial.empty())
400     m_cpuSerial = "N/A";
401
402   readProcStat(m_userTicks, m_niceTicks, m_systemTicks, m_idleTicks, m_ioTicks);
403   m_nextUsedReadTime.Set(MINIMUM_TIME_BETWEEN_READS);
404
405   ReadCPUFeatures();
406
407   // Set MMX2 when SSE is present as SSE is a superset of MMX2 and Intel doesn't set the MMX2 cap
408   if (m_cpuFeatures & CPU_FEATURE_SSE)
409     m_cpuFeatures |= CPU_FEATURE_MMX2;
410
411   if (HasNeon())
412     m_cpuFeatures |= CPU_FEATURE_NEON;
413
414 }
415
416 CCPUInfo::~CCPUInfo()
417 {
418   if (m_fProcStat != NULL)
419     fclose(m_fProcStat);
420
421   if (m_fProcTemperature != NULL)
422     fclose(m_fProcTemperature);
423
424   if (m_fCPUFreq != NULL)
425     fclose(m_fCPUFreq);
426 }
427
428 int CCPUInfo::getUsedPercentage()
429 {
430   if (!m_nextUsedReadTime.IsTimePast())
431     return m_lastUsedPercentage;
432
433   unsigned long long userTicks;
434   unsigned long long niceTicks;
435   unsigned long long systemTicks;
436   unsigned long long idleTicks;
437   unsigned long long ioTicks;
438
439   if (!readProcStat(userTicks, niceTicks, systemTicks, idleTicks, ioTicks))
440     return m_lastUsedPercentage;
441
442   userTicks -= m_userTicks;
443   niceTicks -= m_niceTicks;
444   systemTicks -= m_systemTicks;
445   idleTicks -= m_idleTicks;
446   ioTicks -= m_ioTicks;
447
448 #ifdef TARGET_WINDOWS
449   if(userTicks + systemTicks == 0)
450     return m_lastUsedPercentage;
451   int result = (int) ((userTicks + systemTicks - idleTicks) * 100 / (userTicks + systemTicks));
452 #else
453   if(userTicks + niceTicks + systemTicks + idleTicks + ioTicks == 0)
454     return m_lastUsedPercentage;
455   int result = (int) ((userTicks + niceTicks + systemTicks) * 100 / (userTicks + niceTicks + systemTicks + idleTicks + ioTicks));
456 #endif
457
458   m_userTicks += userTicks;
459   m_niceTicks += niceTicks;
460   m_systemTicks += systemTicks;
461   m_idleTicks += idleTicks;
462   m_ioTicks += ioTicks;
463
464   m_lastUsedPercentage = result;
465   m_nextUsedReadTime.Set(MINIMUM_TIME_BETWEEN_READS);
466
467   return result;
468 }
469
470 float CCPUInfo::getCPUFrequency()
471 {
472   // Get CPU frequency, scaled to MHz.
473 #if defined(TARGET_DARWIN)
474   long long hz = 0;
475   size_t len = sizeof(hz);
476   if (sysctlbyname("hw.cpufrequency", &hz, &len, NULL, 0) == -1)
477     return 0.f;
478   return hz / 1000000.0;
479 #elif defined TARGET_WINDOWS
480   HKEY hKey;
481   DWORD dwMHz=0;
482   DWORD dwSize=sizeof(dwMHz);
483   LONG ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",0, KEY_READ, &hKey);
484   ret = RegQueryValueEx(hKey,"~MHz", NULL, NULL, (LPBYTE)&dwMHz, &dwSize);
485   RegCloseKey(hKey);
486   if(ret == 0)
487     return float(dwMHz);
488   else
489     return 0.f;
490 #elif defined(TARGET_FREEBSD)
491   int hz = 0;
492   size_t len = sizeof(hz);
493   if (sysctlbyname("dev.cpu.0.freq", &hz, &len, NULL, 0) != 0)
494     hz = 0;
495   return (float)hz;
496 #else
497   int value = 0;
498   if (m_fCPUFreq)
499   {
500     rewind(m_fCPUFreq);
501     fflush(m_fCPUFreq);
502     fscanf(m_fCPUFreq, "%d", &value);
503   }
504   return value / 1000.0;
505 #endif
506 }
507
508 bool CCPUInfo::getTemperature(CTemperature& temperature)
509 {
510   int         value = 0;
511   char        scale = 0;
512   
513 #if defined(TARGET_DARWIN_OSX)
514   value = SMCGetTemperature(SMC_KEY_CPU_TEMP);
515   scale = 'c';
516 #else
517   int         ret   = 0;
518   FILE        *p    = NULL;
519   CStdString  cmd   = g_advancedSettings.m_cpuTempCmd;
520
521   temperature.SetState(CTemperature::invalid);
522
523   if (cmd.IsEmpty() && m_fProcTemperature == NULL)
524     return false;
525
526   if (!cmd.IsEmpty())
527   {
528     p = popen (cmd.c_str(), "r");
529     if (p)
530     {
531       ret = fscanf(p, "%d %c", &value, &scale);
532       pclose(p);
533     }
534   }
535   else
536   {
537     // procfs is deprecated in the linux kernel, we should move away from
538     // using it for temperature data.  It doesn't seem that sysfs has a
539     // general enough interface to bother implementing ATM.
540     
541     rewind(m_fProcTemperature);
542     fflush(m_fProcTemperature);
543     ret = fscanf(m_fProcTemperature, "temperature: %d %c", &value, &scale);
544     
545     // read from the temperature file of the new kernels
546     if (!ret)
547     {
548       ret = fscanf(m_fProcTemperature, "%d", &value);
549       value = value / 1000;
550       scale = 'c';
551       ret++;
552     }
553   }
554
555   if (ret != 2)
556     return false; 
557 #endif
558
559   if (scale == 'C' || scale == 'c')
560     temperature = CTemperature::CreateFromCelsius(value);
561   else if (scale == 'F' || scale == 'f')
562     temperature = CTemperature::CreateFromFahrenheit(value);
563   else
564     return false;
565   
566   return true;
567 }
568
569 bool CCPUInfo::HasCoreId(int nCoreId) const
570 {
571   map<int, CoreInfo>::const_iterator iter = m_cores.find(nCoreId);
572   if (iter != m_cores.end())
573     return true;
574   return false;
575 }
576
577 const CoreInfo &CCPUInfo::GetCoreInfo(int nCoreId)
578 {
579   map<int, CoreInfo>::iterator iter = m_cores.find(nCoreId);
580   if (iter != m_cores.end())
581     return iter->second;
582
583   static CoreInfo dummy;
584   return dummy;
585 }
586
587 bool CCPUInfo::readProcStat(unsigned long long& user, unsigned long long& nice,
588     unsigned long long& system, unsigned long long& idle, unsigned long long& io)
589 {
590
591 #ifdef TARGET_WINDOWS
592   FILETIME idleTime;
593   FILETIME kernelTime;
594   FILETIME userTime;
595   ULARGE_INTEGER ulTime;
596   unsigned long long coreUser, coreSystem, coreIdle;
597   GetSystemTimes( &idleTime, &kernelTime, &userTime );
598   ulTime.HighPart = userTime.dwHighDateTime;
599   ulTime.LowPart = userTime.dwLowDateTime;
600   user = coreUser = ulTime.QuadPart;
601
602   ulTime.HighPart = kernelTime.dwHighDateTime;
603   ulTime.LowPart = kernelTime.dwLowDateTime;
604   system = coreSystem = ulTime.QuadPart;
605
606   ulTime.HighPart = idleTime.dwHighDateTime;
607   ulTime.LowPart = idleTime.dwLowDateTime;
608   idle = coreIdle = ulTime.QuadPart;
609
610   nice = 0;
611
612   coreUser -= m_cores[0].m_user;
613   coreSystem -= m_cores[0].m_system;
614   coreIdle -= m_cores[0].m_idle;
615   m_cores[0].m_fPct = ((double)(coreUser + coreSystem - coreIdle) * 100.0) / (double)(coreUser + coreSystem);
616   m_cores[0].m_user += coreUser;
617   m_cores[0].m_system += coreSystem;
618   m_cores[0].m_idle += coreIdle;
619
620   io = 0;
621
622 #elif defined(TARGET_FREEBSD)
623   long *cptimes;
624   size_t len;
625   int i;
626
627   len = sizeof(long) * 32 * CPUSTATES;
628   if (sysctlbyname("kern.cp_times", NULL, &len, NULL, 0) != 0)
629     return false;
630   cptimes = (long*)malloc(len);
631   if (cptimes == NULL)
632     return false;
633   if (sysctlbyname("kern.cp_times", cptimes, &len, NULL, 0) != 0)
634   {
635     free(cptimes);
636     return false;
637   }
638   user = 0;
639   nice = 0;
640   system = 0;
641   idle = 0;
642   io = 0;
643   for (i = 0; i < m_cpuCount; i++)
644   {
645     long coreUser, coreNice, coreSystem, coreIdle, coreIO;
646     double total;
647
648     coreUser   = cptimes[i * CPUSTATES + CP_USER];
649     coreNice   = cptimes[i * CPUSTATES + CP_NICE];
650     coreSystem = cptimes[i * CPUSTATES + CP_SYS];
651     coreIO     = cptimes[i * CPUSTATES + CP_INTR];
652     coreIdle   = cptimes[i * CPUSTATES + CP_IDLE];
653
654     map<int, CoreInfo>::iterator iter = m_cores.find(i);
655     if (iter != m_cores.end())
656     {
657       coreUser -= iter->second.m_user;
658       coreNice -= iter->second.m_nice;
659       coreSystem -= iter->second.m_system;
660       coreIdle -= iter->second.m_idle;
661       coreIO -= iter->second.m_io;
662
663       total = (double)(coreUser + coreNice + coreSystem + coreIdle + coreIO);
664       if(total != 0.0f)
665         iter->second.m_fPct = ((double)(coreUser + coreNice + coreSystem) * 100.0) / total;
666
667       iter->second.m_user += coreUser;
668       iter->second.m_nice += coreNice;
669       iter->second.m_system += coreSystem;
670       iter->second.m_idle += coreIdle;
671       iter->second.m_io += coreIO;
672
673       user   += coreUser;
674       nice   += coreNice;
675       system += coreSystem;
676       idle   += coreIdle;
677       io     += coreIO;
678     }
679   }
680   free(cptimes);
681 #else
682   if (m_fProcStat == NULL)
683     return false;
684
685   rewind(m_fProcStat);
686   fflush(m_fProcStat);
687
688   char buf[256];
689   if (!fgets(buf, sizeof(buf), m_fProcStat))
690     return false;
691
692   int num = sscanf(buf, "cpu %llu %llu %llu %llu %llu %*s\n", &user, &nice, &system, &idle, &io);
693   if (num < 5)
694     io = 0;
695
696   while (fgets(buf, sizeof(buf), m_fProcStat) && num >= 4)
697   {
698     unsigned long long coreUser, coreNice, coreSystem, coreIdle, coreIO;
699     int nCpu=0;
700     num = sscanf(buf, "cpu%d %llu %llu %llu %llu %llu %*s\n", &nCpu, &coreUser, &coreNice, &coreSystem, &coreIdle, &coreIO);
701     if (num < 6)
702       coreIO = 0;
703
704     map<int, CoreInfo>::iterator iter = m_cores.find(nCpu);
705     if (num > 4 && iter != m_cores.end())
706     {
707       coreUser -= iter->second.m_user;
708       coreNice -= iter->second.m_nice;
709       coreSystem -= iter->second.m_system;
710       coreIdle -= iter->second.m_idle;
711       coreIO -= iter->second.m_io;
712
713       double total = (double)(coreUser + coreNice + coreSystem + coreIdle + coreIO);
714       if(total == 0.0f)
715         iter->second.m_fPct = 0.0f;
716       else
717         iter->second.m_fPct = ((double)(coreUser + coreNice + coreSystem) * 100.0) / total;
718
719       iter->second.m_user += coreUser;
720       iter->second.m_nice += coreNice;
721       iter->second.m_system += coreSystem;
722       iter->second.m_idle += coreIdle;
723       iter->second.m_io += coreIO;
724     }
725   }
726 #endif
727
728   return true;
729 }
730
731 CStdString CCPUInfo::GetCoresUsageString() const
732 {
733   CStdString strCores;
734   map<int, CoreInfo>::const_iterator iter = m_cores.begin();
735   while (iter != m_cores.end())
736   {
737     CStdString strCore;
738 #ifdef TARGET_WINDOWS
739     // atm we get only the average over all cores
740     strCore.Format("CPU %d core(s) average: %3.1f%% ",m_cpuCount, iter->second.m_fPct);
741 #else
742     strCore.Format("CPU%d: %3.1f%% ",iter->first, iter->second.m_fPct);
743 #endif
744     strCores+=strCore;
745     iter++;
746   }
747   return strCores;
748 }
749
750 void CCPUInfo::ReadCPUFeatures()
751 {
752 #ifdef TARGET_WINDOWS
753
754   int CPUInfo[4]; // receives EAX, EBX, ECD and EDX in that order
755
756   __cpuid(CPUInfo, 0);
757   int MaxStdInfoType = CPUInfo[0];
758
759   if (MaxStdInfoType >= CPUID_INFOTYPE_STANDARD)
760   {
761     __cpuid(CPUInfo, CPUID_INFOTYPE_STANDARD);
762     if (CPUInfo[CPUINFO_EDX] & CPUID_00000001_EDX_MMX)
763       m_cpuFeatures |= CPU_FEATURE_MMX;
764     if (CPUInfo[CPUINFO_EDX] & CPUID_00000001_EDX_SSE)
765       m_cpuFeatures |= CPU_FEATURE_SSE;
766     if (CPUInfo[CPUINFO_EDX] & CPUID_00000001_EDX_SSE2)
767       m_cpuFeatures |= CPU_FEATURE_SSE2;
768     if (CPUInfo[CPUINFO_ECX] & CPUID_00000001_ECX_SSE3)
769       m_cpuFeatures |= CPU_FEATURE_SSE3;
770     if (CPUInfo[CPUINFO_ECX] & CPUID_00000001_ECX_SSSE3)
771       m_cpuFeatures |= CPU_FEATURE_SSSE3;
772     if (CPUInfo[CPUINFO_ECX] & CPUID_00000001_ECX_SSE4)
773       m_cpuFeatures |= CPU_FEATURE_SSE4;
774     if (CPUInfo[CPUINFO_ECX] & CPUID_00000001_ECX_SSE42)
775       m_cpuFeatures |= CPU_FEATURE_SSE42;
776   }
777
778   __cpuid(CPUInfo, 0x80000000);
779   int MaxExtInfoType = CPUInfo[0];
780
781   if (MaxExtInfoType >= CPUID_INFOTYPE_EXTENDED)
782   {
783     __cpuid(CPUInfo, CPUID_INFOTYPE_EXTENDED);
784
785     if (CPUInfo[CPUINFO_EDX] & CPUID_80000001_EDX_MMX)
786       m_cpuFeatures |= CPU_FEATURE_MMX;
787     if (CPUInfo[CPUINFO_EDX] & CPUID_80000001_EDX_MMX2)
788       m_cpuFeatures |= CPU_FEATURE_MMX2;
789     if (CPUInfo[CPUINFO_EDX] & CPUID_80000001_EDX_3DNOW)
790       m_cpuFeatures |= CPU_FEATURE_3DNOW;
791     if (CPUInfo[CPUINFO_EDX] & CPUID_80000001_EDX_3DNOWEXT)
792       m_cpuFeatures |= CPU_FEATURE_3DNOWEXT;
793   }
794
795 #elif defined(TARGET_DARWIN)
796   #if defined(__ppc__)
797     m_cpuFeatures |= CPU_FEATURE_ALTIVEC;
798   #elif defined(TARGET_DARWIN_IOS)
799   #else
800     size_t len = 512;
801     char buffer[512] ={0};
802
803     if (sysctlbyname("machdep.cpu.features", &buffer, &len, NULL, 0) == 0)
804     {
805       strcat(buffer, " ");
806       if (strstr(buffer,"MMX"))
807         m_cpuFeatures |= CPU_FEATURE_MMX;
808       if (strstr(buffer,"SSE "))
809         m_cpuFeatures |= CPU_FEATURE_SSE;
810       if (strstr(buffer,"SSE2"))
811         m_cpuFeatures |= CPU_FEATURE_SSE2;
812       if (strstr(buffer,"SSE3 "))
813         m_cpuFeatures |= CPU_FEATURE_SSE3;
814       if (strstr(buffer,"SSSE3"))
815         m_cpuFeatures |= CPU_FEATURE_SSSE3;
816       if (strstr(buffer,"SSE4.1"))
817         m_cpuFeatures |= CPU_FEATURE_SSE4;
818       if (strstr(buffer,"SSE4.2"))
819         m_cpuFeatures |= CPU_FEATURE_SSE42;
820       if (strstr(buffer,"3DNOW "))
821         m_cpuFeatures |= CPU_FEATURE_3DNOW;
822       if (strstr(buffer,"3DNOWEXT"))
823        m_cpuFeatures |= CPU_FEATURE_3DNOWEXT;
824     }
825     else
826       m_cpuFeatures |= CPU_FEATURE_MMX;
827   #endif
828 #elif defined(LINUX)
829 // empty on purpose, the implementation is in the constructor
830 #elif !defined(__powerpc__) && !defined(__ppc__) && !defined(__arm__)
831   m_cpuFeatures |= CPU_FEATURE_MMX;
832 #elif defined(__powerpc__) || defined(__ppc__)
833   m_cpuFeatures |= CPU_FEATURE_ALTIVEC;
834 #endif
835 }
836
837 bool CCPUInfo::HasNeon()
838 {
839   static int has_neon = -1;
840 #if defined (TARGET_ANDROID)
841   if (has_neon == -1)
842     has_neon = (CAndroidFeatures::HasNeon()) ? 1 : 0;
843
844 #elif defined(TARGET_DARWIN_IOS)
845   has_neon = 1;
846
847 #elif defined(TARGET_LINUX) && defined(__ARM_NEON__)
848   if (has_neon == -1)
849   {
850     has_neon = 0;
851     // why are we not looking at the Features in
852     // /proc/cpuinfo for neon ?
853     int fd = open("/proc/self/auxv", O_RDONLY);
854     if (fd >= 0)
855     {
856       Elf32_auxv_t auxv;
857       while (read(fd, &auxv, sizeof(Elf32_auxv_t)) == sizeof(Elf32_auxv_t))
858       {
859         if (auxv.a_type == AT_HWCAP)
860         {
861           has_neon = (auxv.a_un.a_val & HWCAP_NEON) ? 1 : 0;
862           break;
863         }
864       }
865       close(fd);
866     }
867   }
868
869 #endif
870
871   return has_neon == 1;
872 }
873
874 CCPUInfo g_cpuInfo;
875 /*
876 int main()
877 {
878   CCPUInfo c;
879   usleep(...);
880   int r = c.getUsedPercentage();
881   printf("%d\n", r);
882 }
883 */