1 ///////////////////////////////////////////////////////////////////////////////
2 // MuldeR's Utilities for Qt
3 // Copyright (C) 2004-2016 LoRd_MuldeR <MuldeR2@GMX.de>
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
10 // This library 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 GNU
13 // Lesser General Public License for more details.
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 // http://www.gnu.org/licenses/lgpl-2.1.txt
20 //////////////////////////////////////////////////////////////////////////////////
23 #define WIN32_LEAN_AND_MEAN 1
27 #include <MUtils/CPUFeatures.h>
28 #include <MUtils/OSSupport.h>
29 #include "Utils_Win32.h"
31 #define MY_CPUID(X,Y) __cpuid(((int*)(X)), ((int)(Y)))
32 #define CHECK_VENDOR(X,Y,Z) (_stricmp((X), (Y)) ? 0U : (Z));
33 #define CHECK_FLAG(X,Y,Z) (((X) & (Y)) ? (Z) : 0U)
35 MUtils::CPUFetaures::cpu_info_t
MUtils::CPUFetaures::detect(void)
37 const OS::ArgumentMap
&args
= OS::arguments();
38 typedef BOOL (WINAPI
*IsWow64ProcessFun
)(__in HANDLE hProcess
, __out PBOOL Wow64Process
);
39 static const quint32 FLAGS_X64
= (FLAG_MMX
| FLAG_SSE
| FLAG_SSE2
);
42 SYSTEM_INFO systemInfo
;
45 //Initialize variables to zero
46 memset(&features
, 0, sizeof(cpu_info_t
));
47 memset(&systemInfo
, 0, sizeof(SYSTEM_INFO
));
48 memset(cpuInfo
, 0, sizeof(cpuInfo
));
50 //Detect the CPU identifier string
51 MY_CPUID(&cpuInfo
[0], 0);
52 const uint32_t max_basic_cap
= cpuInfo
[0];
53 memcpy(&features
.idstr
[0U * sizeof(uint32_t)], &cpuInfo
[1], sizeof(uint32_t));
54 memcpy(&features
.idstr
[1U * sizeof(uint32_t)], &cpuInfo
[3], sizeof(uint32_t));
55 memcpy(&features
.idstr
[2U * sizeof(uint32_t)], &cpuInfo
[2], sizeof(uint32_t));
56 features
.idstr
[3U * sizeof(uint32_t)] = '\0';
57 features
.vendor
|= CHECK_VENDOR(features
.idstr
, "GenuineIntel", VENDOR_INTEL
);
58 features
.vendor
|= CHECK_VENDOR(features
.idstr
, "AuthenticAMD", VENDOR_AMD
);
60 //Detect the CPU model and feature flags
61 if(max_basic_cap
>= 1)
63 MY_CPUID(&cpuInfo
[0], 1);
64 features
.features
|= CHECK_FLAG(cpuInfo
[3], 0x00008000, FLAG_CMOV
);
65 features
.features
|= CHECK_FLAG(cpuInfo
[3], 0x00800000, FLAG_MMX
);
66 features
.features
|= CHECK_FLAG(cpuInfo
[3], 0x02000000, FLAG_SSE
);
67 features
.features
|= CHECK_FLAG(cpuInfo
[3], 0x04000000, FLAG_SSE2
);
68 features
.features
|= CHECK_FLAG(cpuInfo
[2], 0x00000001, FLAG_SSE3
);
69 features
.features
|= CHECK_FLAG(cpuInfo
[2], 0x00000200, FLAG_SSSE3
);
70 features
.features
|= CHECK_FLAG(cpuInfo
[2], 0x00080000, FLAG_SSE41
);
71 features
.features
|= CHECK_FLAG(cpuInfo
[2], 0x00100000, FLAG_SSE42
);
74 if ((cpuInfo
[2] & 0x18000000) == 0x18000000)
76 if((_xgetbv(0) & 0x6ui
64) == 0x6ui
64) /*AVX requires OS support!*/
78 features
.features
|= FLAG_AVX
;
79 features
.features
|= CHECK_FLAG(cpuInfo
[2], 0x00001000, FLAG_FMA3
);
83 //Compute the CPU stepping, model and family
84 features
.stepping
= cpuInfo
[0] & 0xf;
85 features
.model
= ((cpuInfo
[0] >> 4) & 0xf) + (((cpuInfo
[0] >> 16) & 0xf) << 4);
86 features
.family
= ((cpuInfo
[0] >> 8) & 0xf) + ((cpuInfo
[0] >> 20) & 0xff);
89 //Detect extended feature flags
90 if (max_basic_cap
>= 7)
92 MY_CPUID(&cpuInfo
[1], 7);
93 if (features
.features
& FLAG_AVX
)
95 features
.features
|= CHECK_FLAG(cpuInfo
[2], 0x00000020, FLAG_AVX2
);
99 //Read the CPU "brand" string
100 if (max_basic_cap
> 0)
102 MY_CPUID(&cpuInfo
[0], 0x80000000);
103 const uint32_t max_extended_cap
= qBound(0x80000000, cpuInfo
[0], 0x80000004);
104 if (max_extended_cap
>= 0x80000001)
106 MY_CPUID(&cpuInfo
[0], 0x80000001);
107 features
.features
|= CHECK_FLAG(cpuInfo
[2], 0x00000020, FLAG_LZCNT
);
108 for (uint32_t i
= 0x80000002; i
<= max_extended_cap
; ++i
)
110 MY_CPUID(&cpuInfo
[0], i
);
111 memcpy(&features
.brand
[(i
- 0x80000002) * sizeof(cpuInfo
)], &cpuInfo
[0], sizeof(cpuInfo
));
113 features
.brand
[sizeof(features
.brand
) - 1] = '\0';
117 //Detect 64-Bit processors
118 #if (!(defined(_M_X64) || defined(_M_IA64)))
119 const IsWow64ProcessFun isWow64ProcessPtr
= MUtils::Win32Utils::resolve
<IsWow64ProcessFun
>(QLatin1String("kernel32"), QLatin1String("IsWow64Process"));
120 if(isWow64ProcessPtr
)
122 BOOL x64flag
= FALSE
;
123 if(isWow64ProcessPtr(GetCurrentProcess(), &x64flag
))
128 features
.features
|= FLAGS_X64
; /*x86_64 implies SSE2*/
134 features
.features
|= FLAGS_X64
;
137 //Make sure that (at least) the MMX flag has been set!
138 if (!(features
.features
& FLAG_MMX
))
140 qWarning("Warning: CPU does not seem to support MMX. Take care!\n");
141 features
.features
= 0;
144 //Count the number of available(!) CPU cores
145 DWORD_PTR procAffinity
, sysAffinity
;
146 if(GetProcessAffinityMask(GetCurrentProcess(), &procAffinity
, &sysAffinity
))
148 for(DWORD_PTR mask
= 1; mask
; mask
<<= 1)
150 features
.count
+= ((sysAffinity
& mask
) ? (1) : (0));
153 if(features
.count
< 1)
155 GetNativeSystemInfo(&systemInfo
);
156 features
.count
= qBound(1UL, systemInfo
.dwNumberOfProcessors
, 64UL);
159 //Apply manual CPU overwrites
160 bool userFlag
= false;
161 if (args
.contains(QLatin1String("cpu-no-simd"))) { userFlag
= true; features
.features
= 0U; }
162 if (args
.contains(QLatin1String("cpu-no-vendor"))) { userFlag
= true; features
.vendor
= 0U; }
163 if (args
.contains(QLatin1String("cpu-no-x64"))) { userFlag
= true; features
.x64
= 0U; }
166 qWarning("CPU flags overwritten by user-defined parameters. Take care!\n");