2 * Copyright (C) 2005-2013 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, see
17 * <http://www.gnu.org/licenses/>.
22 #include "Temperature.h"
26 #if defined(TARGET_DARWIN)
27 #include <sys/types.h>
28 #include <sys/sysctl.h>
29 #ifdef TARGET_DARWIN_OSX
32 #include <mach-o/arch.h>
37 #if defined(TARGET_FREEBSD)
38 #include <sys/types.h>
39 #include <sys/sysctl.h>
40 #include <sys/resource.h>
43 #if defined(TARGET_LINUX) && defined(__ARM_NEON__) && !defined(TARGET_ANDROID)
47 #include <linux/auxvec.h>
48 #include <asm/hwcap.h>
51 #if defined(TARGET_ANDROID)
52 #include "android/activity/AndroidFeatures.h"
58 // Defines to help with calls to CPUID
59 #define CPUID_INFOTYPE_STANDARD 0x00000001
60 #define CPUID_INFOTYPE_EXTENDED 0x80000001
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)
69 #define CPUID_00000001_EDX_MMX (1<<23)
70 #define CPUID_00000001_EDX_SSE (1<<25)
71 #define CPUID_00000001_EDX_SSE2 (1<<26)
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)
81 // Help with the __cpuid intrinsic of MSVC
90 #include "settings/AdvancedSettings.h"
91 #include "utils/StringUtils.h"
96 #define MINIMUM_TIME_BETWEEN_READS 500
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 )
106 tv->tv_usec = t.millitm * 1000;
109 #define gettimeofday(TV, TZ) _private_gettimeofday((TV), (TZ))
112 CCPUInfo::CCPUInfo(void)
114 m_fProcStat = m_fProcTemperature = m_fCPUFreq = NULL;
115 m_lastUsedPercentage = 0;
118 #if defined(TARGET_DARWIN)
120 std::string cpuVendor;
122 // The number of cores.
123 if (sysctlbyname("hw.activecpu", &m_cpuCount, &len, NULL, 0) == -1)
128 const NXArchInfo *info = NXGetLocalArchInfo();
130 m_cpuModel = info->description;
132 // NXGetLocalArchInfo is ugly for intel so keep using this method
135 if (sysctlbyname("machdep.cpu.brand_string", &buffer, &len, NULL, 0) == 0)
140 if (sysctlbyname("machdep.cpu.vendor", &buffer, &len, NULL, 0) == 0)
147 if (sysctlbyname("machdep.cpu.features", &buffer, &len, NULL, 0) == 0)
149 char* needle = buffer;
154 tok = strtok_r(needle, " ", &save);
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);
178 // Go through each core.
179 for (int i=0; i<m_cpuCount; i++)
183 core.m_strModel = m_cpuModel;
184 core.m_strVendor = cpuVendor;
185 m_cores[core.m_id] = core;
188 #elif defined(TARGET_WINDOWS)
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);
196 m_cpuModel = rgValue;
198 m_cpuModel = "Unknown";
202 SYSTEM_INFO siSysInfo;
203 GetSystemInfo(&siSysInfo);
204 m_cpuCount = siSysInfo.dwNumberOfProcessors;
209 #elif defined(TARGET_FREEBSD)
214 len = sizeof(m_cpuCount);
215 if (sysctlbyname("hw.ncpu", &m_cpuCount, &len, NULL, 0) != 0)
218 len = sizeof(cpumodel);
219 if (sysctlbyname("hw.model", &cpumodel, &len, NULL, 0) != 0)
220 (void)strncpy(cpumodel, "Unknown", 8);
221 m_cpuModel = cpumodel;
223 for (i = 0; i < m_cpuCount; i++)
227 core.m_strModel = m_cpuModel;
228 m_cores[core.m_id] = core;
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
245 m_fCPUFreq = fopen ("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq", "r");
248 FILE* fCPUInfo = fopen("/proc/cpuinfo", "r");
255 while (fgets(buffer, sizeof(buffer), fCPUInfo))
257 if (strncmp(buffer, "processor", strlen("processor"))==0)
259 char *needle = strstr(buffer, ":");
263 core.m_id = atoi(needle+2);
265 m_cores[core.m_id] = core;
269 else if (strncmp(buffer, "vendor_id", strlen("vendor_id"))==0)
271 char *needle = strstr(buffer, ":");
272 if (needle && strlen(needle)>3)
275 m_cores[nCurrId].m_strVendor = needle;
276 StringUtils::Trim(m_cores[nCurrId].m_strVendor);
279 else if (strncmp(buffer, "Processor", strlen("Processor"))==0)
281 char *needle = strstr(buffer, ":");
282 if (needle && strlen(needle)>3)
286 m_cores[nCurrId].m_strModel = m_cpuModel;
287 StringUtils::Trim(m_cores[nCurrId].m_strModel);
290 else if (strncmp(buffer, "BogoMIPS", strlen("BogoMIPS"))==0)
292 char *needle = strstr(buffer, ":");
293 if (needle && strlen(needle)>3)
296 m_cpuBogoMips = needle;
297 m_cores[nCurrId].m_strBogoMips = m_cpuBogoMips;
298 StringUtils::Trim(m_cores[nCurrId].m_strBogoMips);
301 else if (strncmp(buffer, "Hardware", strlen("Hardware"))==0)
303 char *needle = strstr(buffer, ":");
304 if (needle && strlen(needle)>3)
307 m_cpuHardware = needle;
308 m_cores[nCurrId].m_strHardware = m_cpuHardware;
309 StringUtils::Trim(m_cores[nCurrId].m_strHardware);
312 else if (strncmp(buffer, "Revision", strlen("Revision"))==0)
314 char *needle = strstr(buffer, ":");
315 if (needle && strlen(needle)>3)
318 m_cpuRevision = needle;
319 m_cores[nCurrId].m_strRevision = m_cpuRevision;
320 StringUtils::Trim(m_cores[nCurrId].m_strRevision);
323 else if (strncmp(buffer, "Serial", strlen("Serial"))==0)
325 char *needle = strstr(buffer, ":");
326 if (needle && strlen(needle)>3)
329 m_cpuSerial = needle;
330 m_cores[nCurrId].m_strSerial = m_cpuSerial;
331 StringUtils::Trim(m_cores[nCurrId].m_strSerial);
334 else if (strncmp(buffer, "model name", strlen("model name"))==0)
336 char *needle = strstr(buffer, ":");
337 if (needle && strlen(needle)>3)
341 m_cores[nCurrId].m_strModel = m_cpuModel;
342 StringUtils::Trim(m_cores[nCurrId].m_strModel);
345 else if (strncmp(buffer, "flags", 5) == 0)
347 char* needle = strchr(buffer, ':');
353 tok = strtok_r(needle, " ", &save);
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);
386 m_cpuModel = "Unknown";
390 StringUtils::Replace(m_cpuModel, '\r', ' ');
391 StringUtils::Replace(m_cpuModel, '\n', ' ');
392 StringUtils::Trim(m_cpuModel);
393 StringUtils::RemoveDuplicatedSpacesAndTabs(m_cpuModel);
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())
405 readProcStat(m_userTicks, m_niceTicks, m_systemTicks, m_idleTicks, m_ioTicks);
406 m_nextUsedReadTime.Set(MINIMUM_TIME_BETWEEN_READS);
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;
415 m_cpuFeatures |= CPU_FEATURE_NEON;
419 CCPUInfo::~CCPUInfo()
421 if (m_fProcStat != NULL)
424 if (m_fProcTemperature != NULL)
425 fclose(m_fProcTemperature);
427 if (m_fCPUFreq != NULL)
431 int CCPUInfo::getUsedPercentage()
433 if (!m_nextUsedReadTime.IsTimePast())
434 return m_lastUsedPercentage;
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;
442 if (!readProcStat(userTicks, niceTicks, systemTicks, idleTicks, ioTicks))
443 return m_lastUsedPercentage;
445 userTicks -= m_userTicks;
446 niceTicks -= m_niceTicks;
447 systemTicks -= m_systemTicks;
448 idleTicks -= m_idleTicks;
449 ioTicks -= m_ioTicks;
451 #ifdef TARGET_WINDOWS
452 if(userTicks + systemTicks == 0)
453 return m_lastUsedPercentage;
454 int result = (int) ((userTicks + systemTicks - idleTicks) * 100 / (userTicks + systemTicks));
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));
461 m_userTicks += userTicks;
462 m_niceTicks += niceTicks;
463 m_systemTicks += systemTicks;
464 m_idleTicks += idleTicks;
465 m_ioTicks += ioTicks;
467 m_lastUsedPercentage = result;
468 m_nextUsedReadTime.Set(MINIMUM_TIME_BETWEEN_READS);
473 float CCPUInfo::getCPUFrequency()
475 // Get CPU frequency, scaled to MHz.
476 #if defined(TARGET_DARWIN)
478 size_t len = sizeof(hz);
479 if (sysctlbyname("hw.cpufrequency", &hz, &len, NULL, 0) == -1)
481 return hz / 1000000.0;
482 #elif defined TARGET_WINDOWS
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);
493 #elif defined(TARGET_FREEBSD)
495 size_t len = sizeof(hz);
496 if (sysctlbyname("dev.cpu.0.freq", &hz, &len, NULL, 0) != 0)
505 fscanf(m_fCPUFreq, "%d", &value);
507 return value / 1000.0;
511 bool CCPUInfo::getTemperature(CTemperature& temperature)
516 #if defined(TARGET_DARWIN_OSX)
517 value = SMCGetTemperature(SMC_KEY_CPU_TEMP);
522 CStdString cmd = g_advancedSettings.m_cpuTempCmd;
524 temperature.SetState(CTemperature::invalid);
526 if (cmd.empty() && m_fProcTemperature == NULL)
531 p = popen (cmd.c_str(), "r");
534 ret = fscanf(p, "%d %c", &value, &scale);
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.
544 rewind(m_fProcTemperature);
545 fflush(m_fProcTemperature);
546 ret = fscanf(m_fProcTemperature, "temperature: %d %c", &value, &scale);
548 // read from the temperature file of the new kernels
551 ret = fscanf(m_fProcTemperature, "%d", &value);
552 value = value / 1000;
562 if (scale == 'C' || scale == 'c')
563 temperature = CTemperature::CreateFromCelsius(value);
564 else if (scale == 'F' || scale == 'f')
565 temperature = CTemperature::CreateFromFahrenheit(value);
572 bool CCPUInfo::HasCoreId(int nCoreId) const
574 map<int, CoreInfo>::const_iterator iter = m_cores.find(nCoreId);
575 if (iter != m_cores.end())
580 const CoreInfo &CCPUInfo::GetCoreInfo(int nCoreId)
582 map<int, CoreInfo>::iterator iter = m_cores.find(nCoreId);
583 if (iter != m_cores.end())
586 static CoreInfo dummy;
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)
594 #ifdef TARGET_WINDOWS
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;
605 ulTime.HighPart = kernelTime.dwHighDateTime;
606 ulTime.LowPart = kernelTime.dwLowDateTime;
607 system = coreSystem = ulTime.QuadPart;
609 ulTime.HighPart = idleTime.dwHighDateTime;
610 ulTime.LowPart = idleTime.dwLowDateTime;
611 idle = coreIdle = ulTime.QuadPart;
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;
625 #elif defined(TARGET_FREEBSD)
630 len = sizeof(long) * 32 * CPUSTATES;
631 if (sysctlbyname("kern.cp_times", NULL, &len, NULL, 0) != 0)
633 cptimes = (long*)malloc(len);
636 if (sysctlbyname("kern.cp_times", cptimes, &len, NULL, 0) != 0)
646 for (i = 0; i < m_cpuCount; i++)
648 long coreUser, coreNice, coreSystem, coreIdle, coreIO;
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];
657 map<int, CoreInfo>::iterator iter = m_cores.find(i);
658 if (iter != m_cores.end())
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;
666 total = (double)(coreUser + coreNice + coreSystem + coreIdle + coreIO);
668 iter->second.m_fPct = ((double)(coreUser + coreNice + coreSystem) * 100.0) / total;
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;
678 system += coreSystem;
685 if (m_fProcStat == NULL)
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
693 m_fProcStat = fopen("/proc/stat", "r");
700 if (!fgets(buf, sizeof(buf), m_fProcStat))
703 int num = sscanf(buf, "cpu %llu %llu %llu %llu %llu %*s\n", &user, &nice, &system, &idle, &io);
707 while (fgets(buf, sizeof(buf), m_fProcStat) && num >= 4)
709 unsigned long long coreUser, coreNice, coreSystem, coreIdle, coreIO;
711 num = sscanf(buf, "cpu%d %llu %llu %llu %llu %llu %*s\n", &nCpu, &coreUser, &coreNice, &coreSystem, &coreIdle, &coreIO);
715 map<int, CoreInfo>::iterator iter = m_cores.find(nCpu);
716 if (num > 4 && iter != m_cores.end())
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;
724 double total = (double)(coreUser + coreNice + coreSystem + coreIdle + coreIO);
726 iter->second.m_fPct = 0.0f;
728 iter->second.m_fPct = ((double)(coreUser + coreNice + coreSystem) * 100.0) / total;
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;
742 std::string CCPUInfo::GetCoresUsageString() const
744 std::string strCores;
745 map<int, CoreInfo>::const_iterator iter = m_cores.begin();
746 while (iter != m_cores.end())
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);
753 strCore = StringUtils::Format("CPU%d: %3.1f%% ", iter->first, iter->second.m_fPct);
761 void CCPUInfo::ReadCPUFeatures()
763 #ifdef TARGET_WINDOWS
765 int CPUInfo[4]; // receives EAX, EBX, ECD and EDX in that order
768 int MaxStdInfoType = CPUInfo[0];
770 if (MaxStdInfoType >= CPUID_INFOTYPE_STANDARD)
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;
789 __cpuid(CPUInfo, 0x80000000);
790 int MaxExtInfoType = CPUInfo[0];
792 if (MaxExtInfoType >= CPUID_INFOTYPE_EXTENDED)
794 __cpuid(CPUInfo, CPUID_INFOTYPE_EXTENDED);
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;
806 #elif defined(TARGET_DARWIN)
808 m_cpuFeatures |= CPU_FEATURE_ALTIVEC;
809 #elif defined(TARGET_DARWIN_IOS)
812 char buffer[512] ={0};
814 if (sysctlbyname("machdep.cpu.features", &buffer, &len, NULL, 0) == 0)
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;
837 m_cpuFeatures |= CPU_FEATURE_MMX;
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;
848 bool CCPUInfo::HasNeon()
850 static int has_neon = -1;
851 #if defined (TARGET_ANDROID)
853 has_neon = (CAndroidFeatures::HasNeon()) ? 1 : 0;
855 #elif defined(TARGET_DARWIN_IOS)
858 #elif defined(TARGET_LINUX) && defined(__ARM_NEON__)
862 // why are we not looking at the Features in
863 // /proc/cpuinfo for neon ?
864 int fd = open("/proc/self/auxv", O_RDONLY);
868 while (read(fd, &auxv, sizeof(Elf32_auxv_t)) == sizeof(Elf32_auxv_t))
870 if (auxv.a_type == AT_HWCAP)
872 has_neon = (auxv.a_un.a_val & HWCAP_NEON) ? 1 : 0;
882 return has_neon == 1;
891 int r = c.getUsedPercentage();