Merge pull request #4676 from jmarshallnz/dont_set_scraper_on_tvshow_on_nfo
[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           StringUtils::Trim(m_cores[nCurrId].m_strVendor);
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           StringUtils::Trim(m_cores[nCurrId].m_strModel);
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           StringUtils::Trim(m_cores[nCurrId].m_strBogoMips);
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           StringUtils::Trim(m_cores[nCurrId].m_strHardware);
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           StringUtils::Trim(m_cores[nCurrId].m_strRevision);
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           StringUtils::Trim(m_cores[nCurrId].m_strSerial);
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           StringUtils::Trim(m_cores[nCurrId].m_strModel);
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::Replace(m_cpuModel, '\r', ' ');
391   StringUtils::Replace(m_cpuModel, '\n', ' ');
392   StringUtils::Trim(m_cpuModel);
393   StringUtils::RemoveDuplicatedSpacesAndTabs(m_cpuModel);
394
395   /* Set some default for empty string variables */
396   if (m_cpuBogoMips.empty())
397     m_cpuBogoMips = "N/A";
398   if (m_cpuHardware.empty())
399     m_cpuHardware = "N/A";
400   if (m_cpuRevision.empty())
401     m_cpuRevision = "N/A";
402   if (m_cpuSerial.empty())
403     m_cpuSerial = "N/A";
404
405   readProcStat(m_userTicks, m_niceTicks, m_systemTicks, m_idleTicks, m_ioTicks);
406   m_nextUsedReadTime.Set(MINIMUM_TIME_BETWEEN_READS);
407
408   ReadCPUFeatures();
409
410   // Set MMX2 when SSE is present as SSE is a superset of MMX2 and Intel doesn't set the MMX2 cap
411   if (m_cpuFeatures & CPU_FEATURE_SSE)
412     m_cpuFeatures |= CPU_FEATURE_MMX2;
413
414   if (HasNeon())
415     m_cpuFeatures |= CPU_FEATURE_NEON;
416
417 }
418
419 CCPUInfo::~CCPUInfo()
420 {
421   if (m_fProcStat != NULL)
422     fclose(m_fProcStat);
423
424   if (m_fProcTemperature != NULL)
425     fclose(m_fProcTemperature);
426
427   if (m_fCPUFreq != NULL)
428     fclose(m_fCPUFreq);
429 }
430
431 int CCPUInfo::getUsedPercentage()
432 {
433   if (!m_nextUsedReadTime.IsTimePast())
434     return m_lastUsedPercentage;
435
436   unsigned long long userTicks;
437   unsigned long long niceTicks;
438   unsigned long long systemTicks;
439   unsigned long long idleTicks;
440   unsigned long long ioTicks;
441
442   if (!readProcStat(userTicks, niceTicks, systemTicks, idleTicks, ioTicks))
443     return m_lastUsedPercentage;
444
445   userTicks -= m_userTicks;
446   niceTicks -= m_niceTicks;
447   systemTicks -= m_systemTicks;
448   idleTicks -= m_idleTicks;
449   ioTicks -= m_ioTicks;
450
451 #ifdef TARGET_WINDOWS
452   if(userTicks + systemTicks == 0)
453     return m_lastUsedPercentage;
454   int result = (int) ((userTicks + systemTicks - idleTicks) * 100 / (userTicks + systemTicks));
455 #else
456   if(userTicks + niceTicks + systemTicks + idleTicks + ioTicks == 0)
457     return m_lastUsedPercentage;
458   int result = (int) ((userTicks + niceTicks + systemTicks) * 100 / (userTicks + niceTicks + systemTicks + idleTicks + ioTicks));
459 #endif
460
461   m_userTicks += userTicks;
462   m_niceTicks += niceTicks;
463   m_systemTicks += systemTicks;
464   m_idleTicks += idleTicks;
465   m_ioTicks += ioTicks;
466
467   m_lastUsedPercentage = result;
468   m_nextUsedReadTime.Set(MINIMUM_TIME_BETWEEN_READS);
469
470   return result;
471 }
472
473 float CCPUInfo::getCPUFrequency()
474 {
475   // Get CPU frequency, scaled to MHz.
476 #if defined(TARGET_DARWIN)
477   long long hz = 0;
478   size_t len = sizeof(hz);
479   if (sysctlbyname("hw.cpufrequency", &hz, &len, NULL, 0) == -1)
480     return 0.f;
481   return hz / 1000000.0;
482 #elif defined TARGET_WINDOWS
483   HKEY hKey;
484   DWORD dwMHz=0;
485   DWORD dwSize=sizeof(dwMHz);
486   LONG ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",0, KEY_READ, &hKey);
487   ret = RegQueryValueEx(hKey,"~MHz", NULL, NULL, (LPBYTE)&dwMHz, &dwSize);
488   RegCloseKey(hKey);
489   if(ret == 0)
490     return float(dwMHz);
491   else
492     return 0.f;
493 #elif defined(TARGET_FREEBSD)
494   int hz = 0;
495   size_t len = sizeof(hz);
496   if (sysctlbyname("dev.cpu.0.freq", &hz, &len, NULL, 0) != 0)
497     hz = 0;
498   return (float)hz;
499 #else
500   int value = 0;
501   if (m_fCPUFreq)
502   {
503     rewind(m_fCPUFreq);
504     fflush(m_fCPUFreq);
505     fscanf(m_fCPUFreq, "%d", &value);
506   }
507   return value / 1000.0;
508 #endif
509 }
510
511 bool CCPUInfo::getTemperature(CTemperature& temperature)
512 {
513   int         value = 0;
514   char        scale = 0;
515   
516 #if defined(TARGET_DARWIN_OSX)
517   value = SMCGetTemperature(SMC_KEY_CPU_TEMP);
518   scale = 'c';
519 #else
520   int         ret   = 0;
521   FILE        *p    = NULL;
522   CStdString  cmd   = g_advancedSettings.m_cpuTempCmd;
523
524   temperature.SetState(CTemperature::invalid);
525
526   if (cmd.empty() && m_fProcTemperature == NULL)
527     return false;
528
529   if (!cmd.empty())
530   {
531     p = popen (cmd.c_str(), "r");
532     if (p)
533     {
534       ret = fscanf(p, "%d %c", &value, &scale);
535       pclose(p);
536     }
537   }
538   else
539   {
540     // procfs is deprecated in the linux kernel, we should move away from
541     // using it for temperature data.  It doesn't seem that sysfs has a
542     // general enough interface to bother implementing ATM.
543     
544     rewind(m_fProcTemperature);
545     fflush(m_fProcTemperature);
546     ret = fscanf(m_fProcTemperature, "temperature: %d %c", &value, &scale);
547     
548     // read from the temperature file of the new kernels
549     if (!ret)
550     {
551       ret = fscanf(m_fProcTemperature, "%d", &value);
552       value = value / 1000;
553       scale = 'c';
554       ret++;
555     }
556   }
557
558   if (ret != 2)
559     return false; 
560 #endif
561
562   if (scale == 'C' || scale == 'c')
563     temperature = CTemperature::CreateFromCelsius(value);
564   else if (scale == 'F' || scale == 'f')
565     temperature = CTemperature::CreateFromFahrenheit(value);
566   else
567     return false;
568   
569   return true;
570 }
571
572 bool CCPUInfo::HasCoreId(int nCoreId) const
573 {
574   map<int, CoreInfo>::const_iterator iter = m_cores.find(nCoreId);
575   if (iter != m_cores.end())
576     return true;
577   return false;
578 }
579
580 const CoreInfo &CCPUInfo::GetCoreInfo(int nCoreId)
581 {
582   map<int, CoreInfo>::iterator iter = m_cores.find(nCoreId);
583   if (iter != m_cores.end())
584     return iter->second;
585
586   static CoreInfo dummy;
587   return dummy;
588 }
589
590 bool CCPUInfo::readProcStat(unsigned long long& user, unsigned long long& nice,
591     unsigned long long& system, unsigned long long& idle, unsigned long long& io)
592 {
593
594 #ifdef TARGET_WINDOWS
595   FILETIME idleTime;
596   FILETIME kernelTime;
597   FILETIME userTime;
598   ULARGE_INTEGER ulTime;
599   unsigned long long coreUser, coreSystem, coreIdle;
600   GetSystemTimes( &idleTime, &kernelTime, &userTime );
601   ulTime.HighPart = userTime.dwHighDateTime;
602   ulTime.LowPart = userTime.dwLowDateTime;
603   user = coreUser = ulTime.QuadPart;
604
605   ulTime.HighPart = kernelTime.dwHighDateTime;
606   ulTime.LowPart = kernelTime.dwLowDateTime;
607   system = coreSystem = ulTime.QuadPart;
608
609   ulTime.HighPart = idleTime.dwHighDateTime;
610   ulTime.LowPart = idleTime.dwLowDateTime;
611   idle = coreIdle = ulTime.QuadPart;
612
613   nice = 0;
614
615   coreUser -= m_cores[0].m_user;
616   coreSystem -= m_cores[0].m_system;
617   coreIdle -= m_cores[0].m_idle;
618   m_cores[0].m_fPct = ((double)(coreUser + coreSystem - coreIdle) * 100.0) / (double)(coreUser + coreSystem);
619   m_cores[0].m_user += coreUser;
620   m_cores[0].m_system += coreSystem;
621   m_cores[0].m_idle += coreIdle;
622
623   io = 0;
624
625 #elif defined(TARGET_FREEBSD)
626   long *cptimes;
627   size_t len;
628   int i;
629
630   len = sizeof(long) * 32 * CPUSTATES;
631   if (sysctlbyname("kern.cp_times", NULL, &len, NULL, 0) != 0)
632     return false;
633   cptimes = (long*)malloc(len);
634   if (cptimes == NULL)
635     return false;
636   if (sysctlbyname("kern.cp_times", cptimes, &len, NULL, 0) != 0)
637   {
638     free(cptimes);
639     return false;
640   }
641   user = 0;
642   nice = 0;
643   system = 0;
644   idle = 0;
645   io = 0;
646   for (i = 0; i < m_cpuCount; i++)
647   {
648     long coreUser, coreNice, coreSystem, coreIdle, coreIO;
649     double total;
650
651     coreUser   = cptimes[i * CPUSTATES + CP_USER];
652     coreNice   = cptimes[i * CPUSTATES + CP_NICE];
653     coreSystem = cptimes[i * CPUSTATES + CP_SYS];
654     coreIO     = cptimes[i * CPUSTATES + CP_INTR];
655     coreIdle   = cptimes[i * CPUSTATES + CP_IDLE];
656
657     map<int, CoreInfo>::iterator iter = m_cores.find(i);
658     if (iter != m_cores.end())
659     {
660       coreUser -= iter->second.m_user;
661       coreNice -= iter->second.m_nice;
662       coreSystem -= iter->second.m_system;
663       coreIdle -= iter->second.m_idle;
664       coreIO -= iter->second.m_io;
665
666       total = (double)(coreUser + coreNice + coreSystem + coreIdle + coreIO);
667       if(total != 0.0f)
668         iter->second.m_fPct = ((double)(coreUser + coreNice + coreSystem) * 100.0) / total;
669
670       iter->second.m_user += coreUser;
671       iter->second.m_nice += coreNice;
672       iter->second.m_system += coreSystem;
673       iter->second.m_idle += coreIdle;
674       iter->second.m_io += coreIO;
675
676       user   += coreUser;
677       nice   += coreNice;
678       system += coreSystem;
679       idle   += coreIdle;
680       io     += coreIO;
681     }
682   }
683   free(cptimes);
684 #else
685   if (m_fProcStat == NULL)
686     return false;
687
688 #ifdef TARGET_ANDROID
689   // Just another (vanilla) NDK quirk:
690   // rewind + fflush do not actually flush the buffers,
691   // the same initial content is returned rather than re-read
692   fclose(m_fProcStat);
693   m_fProcStat = fopen("/proc/stat", "r");
694 #else
695   rewind(m_fProcStat);
696   fflush(m_fProcStat);
697 #endif
698
699   char buf[256];
700   if (!fgets(buf, sizeof(buf), m_fProcStat))
701     return false;
702
703   int num = sscanf(buf, "cpu %llu %llu %llu %llu %llu %*s\n", &user, &nice, &system, &idle, &io);
704   if (num < 5)
705     io = 0;
706
707   while (fgets(buf, sizeof(buf), m_fProcStat) && num >= 4)
708   {
709     unsigned long long coreUser, coreNice, coreSystem, coreIdle, coreIO;
710     int nCpu=0;
711     num = sscanf(buf, "cpu%d %llu %llu %llu %llu %llu %*s\n", &nCpu, &coreUser, &coreNice, &coreSystem, &coreIdle, &coreIO);
712     if (num < 6)
713       coreIO = 0;
714
715     map<int, CoreInfo>::iterator iter = m_cores.find(nCpu);
716     if (num > 4 && iter != m_cores.end())
717     {
718       coreUser -= iter->second.m_user;
719       coreNice -= iter->second.m_nice;
720       coreSystem -= iter->second.m_system;
721       coreIdle -= iter->second.m_idle;
722       coreIO -= iter->second.m_io;
723
724       double total = (double)(coreUser + coreNice + coreSystem + coreIdle + coreIO);
725       if(total == 0.0f)
726         iter->second.m_fPct = 0.0f;
727       else
728         iter->second.m_fPct = ((double)(coreUser + coreNice + coreSystem) * 100.0) / total;
729
730       iter->second.m_user += coreUser;
731       iter->second.m_nice += coreNice;
732       iter->second.m_system += coreSystem;
733       iter->second.m_idle += coreIdle;
734       iter->second.m_io += coreIO;
735     }
736   }
737 #endif
738
739   return true;
740 }
741
742 std::string CCPUInfo::GetCoresUsageString() const
743 {
744   std::string strCores;
745   map<int, CoreInfo>::const_iterator iter = m_cores.begin();
746   while (iter != m_cores.end())
747   {
748     std::string strCore;
749 #ifdef TARGET_WINDOWS
750     // atm we get only the average over all cores
751     strCore = StringUtils::Format("CPU %d core(s) average: %3.1f%% ", m_cpuCount, iter->second.m_fPct);
752 #else
753     strCore = StringUtils::Format("CPU%d: %3.1f%% ", iter->first, iter->second.m_fPct);
754 #endif
755     strCores+=strCore;
756     iter++;
757   }
758   return strCores;
759 }
760
761 void CCPUInfo::ReadCPUFeatures()
762 {
763 #ifdef TARGET_WINDOWS
764
765   int CPUInfo[4]; // receives EAX, EBX, ECD and EDX in that order
766
767   __cpuid(CPUInfo, 0);
768   int MaxStdInfoType = CPUInfo[0];
769
770   if (MaxStdInfoType >= CPUID_INFOTYPE_STANDARD)
771   {
772     __cpuid(CPUInfo, CPUID_INFOTYPE_STANDARD);
773     if (CPUInfo[CPUINFO_EDX] & CPUID_00000001_EDX_MMX)
774       m_cpuFeatures |= CPU_FEATURE_MMX;
775     if (CPUInfo[CPUINFO_EDX] & CPUID_00000001_EDX_SSE)
776       m_cpuFeatures |= CPU_FEATURE_SSE;
777     if (CPUInfo[CPUINFO_EDX] & CPUID_00000001_EDX_SSE2)
778       m_cpuFeatures |= CPU_FEATURE_SSE2;
779     if (CPUInfo[CPUINFO_ECX] & CPUID_00000001_ECX_SSE3)
780       m_cpuFeatures |= CPU_FEATURE_SSE3;
781     if (CPUInfo[CPUINFO_ECX] & CPUID_00000001_ECX_SSSE3)
782       m_cpuFeatures |= CPU_FEATURE_SSSE3;
783     if (CPUInfo[CPUINFO_ECX] & CPUID_00000001_ECX_SSE4)
784       m_cpuFeatures |= CPU_FEATURE_SSE4;
785     if (CPUInfo[CPUINFO_ECX] & CPUID_00000001_ECX_SSE42)
786       m_cpuFeatures |= CPU_FEATURE_SSE42;
787   }
788
789   __cpuid(CPUInfo, 0x80000000);
790   int MaxExtInfoType = CPUInfo[0];
791
792   if (MaxExtInfoType >= CPUID_INFOTYPE_EXTENDED)
793   {
794     __cpuid(CPUInfo, CPUID_INFOTYPE_EXTENDED);
795
796     if (CPUInfo[CPUINFO_EDX] & CPUID_80000001_EDX_MMX)
797       m_cpuFeatures |= CPU_FEATURE_MMX;
798     if (CPUInfo[CPUINFO_EDX] & CPUID_80000001_EDX_MMX2)
799       m_cpuFeatures |= CPU_FEATURE_MMX2;
800     if (CPUInfo[CPUINFO_EDX] & CPUID_80000001_EDX_3DNOW)
801       m_cpuFeatures |= CPU_FEATURE_3DNOW;
802     if (CPUInfo[CPUINFO_EDX] & CPUID_80000001_EDX_3DNOWEXT)
803       m_cpuFeatures |= CPU_FEATURE_3DNOWEXT;
804   }
805
806 #elif defined(TARGET_DARWIN)
807   #if defined(__ppc__)
808     m_cpuFeatures |= CPU_FEATURE_ALTIVEC;
809   #elif defined(TARGET_DARWIN_IOS)
810   #else
811     size_t len = 512;
812     char buffer[512] ={0};
813
814     if (sysctlbyname("machdep.cpu.features", &buffer, &len, NULL, 0) == 0)
815     {
816       strcat(buffer, " ");
817       if (strstr(buffer,"MMX"))
818         m_cpuFeatures |= CPU_FEATURE_MMX;
819       if (strstr(buffer,"SSE "))
820         m_cpuFeatures |= CPU_FEATURE_SSE;
821       if (strstr(buffer,"SSE2"))
822         m_cpuFeatures |= CPU_FEATURE_SSE2;
823       if (strstr(buffer,"SSE3 "))
824         m_cpuFeatures |= CPU_FEATURE_SSE3;
825       if (strstr(buffer,"SSSE3"))
826         m_cpuFeatures |= CPU_FEATURE_SSSE3;
827       if (strstr(buffer,"SSE4.1"))
828         m_cpuFeatures |= CPU_FEATURE_SSE4;
829       if (strstr(buffer,"SSE4.2"))
830         m_cpuFeatures |= CPU_FEATURE_SSE42;
831       if (strstr(buffer,"3DNOW "))
832         m_cpuFeatures |= CPU_FEATURE_3DNOW;
833       if (strstr(buffer,"3DNOWEXT"))
834        m_cpuFeatures |= CPU_FEATURE_3DNOWEXT;
835     }
836     else
837       m_cpuFeatures |= CPU_FEATURE_MMX;
838   #endif
839 #elif defined(LINUX)
840 // empty on purpose, the implementation is in the constructor
841 #elif !defined(__powerpc__) && !defined(__ppc__) && !defined(__arm__)
842   m_cpuFeatures |= CPU_FEATURE_MMX;
843 #elif defined(__powerpc__) || defined(__ppc__)
844   m_cpuFeatures |= CPU_FEATURE_ALTIVEC;
845 #endif
846 }
847
848 bool CCPUInfo::HasNeon()
849 {
850   static int has_neon = -1;
851 #if defined (TARGET_ANDROID)
852   if (has_neon == -1)
853     has_neon = (CAndroidFeatures::HasNeon()) ? 1 : 0;
854
855 #elif defined(TARGET_DARWIN_IOS)
856   has_neon = 1;
857
858 #elif defined(TARGET_LINUX) && defined(__ARM_NEON__)
859   if (has_neon == -1)
860   {
861     has_neon = 0;
862     // why are we not looking at the Features in
863     // /proc/cpuinfo for neon ?
864     int fd = open("/proc/self/auxv", O_RDONLY);
865     if (fd >= 0)
866     {
867       Elf32_auxv_t auxv;
868       while (read(fd, &auxv, sizeof(Elf32_auxv_t)) == sizeof(Elf32_auxv_t))
869       {
870         if (auxv.a_type == AT_HWCAP)
871         {
872           has_neon = (auxv.a_un.a_val & HWCAP_NEON) ? 1 : 0;
873           break;
874         }
875       }
876       close(fd);
877     }
878   }
879
880 #endif
881
882   return has_neon == 1;
883 }
884
885 CCPUInfo g_cpuInfo;
886 /*
887 int main()
888 {
889   CCPUInfo c;
890   usleep(...);
891   int r = c.getUsedPercentage();
892   printf("%d\n", r);
893 }
894 */