Visual Servoing Platform version 3.5.0
cpu_x86.cpp
1/* cpu_x86.cpp
2 *
3 * Author : Alexander J. Yee
4 * Date Created : 04/12/2014
5 * Last Modified : 04/12/2014
6 *
7 * Modification for ViSP:
8 * - UNKNOWN_ARCH (ARM, ...)
9 * - ifndef _XCR_XFEATURE_ENABLED_MASK (MinGW)
10 */
11
16// Dependencies
17#include "cpu_x86.h"
18#include <cstring>
19#include <iostream>
24#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)
25#if defined(_WIN32) && ( !defined(__MINGW32__) || ( !defined(__i386) && !defined(_M_IX86) ) )
26#include "cpu_x86_Windows.ipp"
27#elif defined(__GNUC__) || defined(__clang__)
28#include "cpu_x86_Linux.ipp"
29#else
30//# error "No cpuid intrinsic defined for compiler."
31#define UNKNOWN_ARCH
32#endif
33#else
34//# error "No cpuid intrinsic defined for processor architecture."
35#define UNKNOWN_ARCH
36#endif
37
38#ifndef _XCR_XFEATURE_ENABLED_MASK
39#define _XCR_XFEATURE_ENABLED_MASK 0
40#endif
41
42#ifndef DOXYGEN_SHOULD_SKIP_THIS
43namespace FeatureDetector
44{
45using std::cout;
46using std::endl;
47using std::memcpy;
48using std::memset;
53void cpu_x86::print(const char *label, bool yes)
54{
55 cout << label;
56 cout << (yes ? "Yes" : "No") << endl;
57}
62cpu_x86::cpu_x86()
63{
64 memset(this, 0, sizeof(*this));
65 detect_host();
66}
67bool cpu_x86::detect_OS_AVX()
68{
69#ifndef UNKNOWN_ARCH
70 // Copied from: http://stackoverflow.com/a/22521619/922184
71
72 bool avxSupported = false;
73
74 int cpuInfo[4];
75 cpuid(cpuInfo, 1);
76
77 bool osUsesXSAVE_XRSTORE = (cpuInfo[2] & (1 << 27)) != 0;
78 bool cpuAVXSuport = (cpuInfo[2] & (1 << 28)) != 0;
79
80 if (osUsesXSAVE_XRSTORE && cpuAVXSuport) {
81 uint64_t xcrFeatureMask = xgetbv(_XCR_XFEATURE_ENABLED_MASK);
82 avxSupported = (xcrFeatureMask & 0x6) == 0x6;
83 }
84
85 return avxSupported;
86#else
87 return false;
88#endif
89}
90bool cpu_x86::detect_OS_AVX512()
91{
92#ifndef UNKNOWN_ARCH
93 if (!detect_OS_AVX())
94 return false;
95
96 uint64_t xcrFeatureMask = xgetbv(_XCR_XFEATURE_ENABLED_MASK);
97 return (xcrFeatureMask & 0xe6) == 0xe6;
98#else
99 return false;
100#endif
101}
102std::string cpu_x86::get_vendor_string()
103{
104#ifndef UNKNOWN_ARCH
105 int32_t CPUInfo[4];
106 char name[13];
107
108 cpuid(CPUInfo, 0);
109 memcpy(name + 0, &CPUInfo[1], 4);
110 memcpy(name + 4, &CPUInfo[3], 4);
111 memcpy(name + 8, &CPUInfo[2], 4);
112 name[12] = '\0';
113
114 return name;
115#else
116 return std::string();
117#endif
118}
123void cpu_x86::detect_host()
124{
125#ifndef UNKNOWN_ARCH
126 // OS Features
127 OS_x64 = detect_OS_x64();
128 OS_AVX = detect_OS_AVX();
129 OS_AVX512 = detect_OS_AVX512();
130
131 // Vendor
132 std::string vendor(get_vendor_string());
133 if (vendor == "GenuineIntel") {
134 Vendor_Intel = true;
135 } else if (vendor == "AuthenticAMD") {
136 Vendor_AMD = true;
137 }
138
139 int info[4];
140 cpuid(info, 0);
141 int nIds = info[0];
142
143 cpuid(info, 0x80000000);
144 uint32_t nExIds = info[0];
145
146 // Detect Features
147 if (nIds >= 0x00000001) {
148 cpuid(info, 0x00000001);
149 HW_MMX = (info[3] & ((int)1 << 23)) != 0;
150 HW_SSE = (info[3] & ((int)1 << 25)) != 0;
151 HW_SSE2 = (info[3] & ((int)1 << 26)) != 0;
152 HW_SSE3 = (info[2] & ((int)1 << 0)) != 0;
153
154 HW_SSSE3 = (info[2] & ((int)1 << 9)) != 0;
155 HW_SSE41 = (info[2] & ((int)1 << 19)) != 0;
156 HW_SSE42 = (info[2] & ((int)1 << 20)) != 0;
157 HW_AES = (info[2] & ((int)1 << 25)) != 0;
158
159 HW_AVX = (info[2] & ((int)1 << 28)) != 0;
160 HW_FMA3 = (info[2] & ((int)1 << 12)) != 0;
161
162 HW_RDRAND = (info[2] & ((int)1 << 30)) != 0;
163 }
164 if (nIds >= 0x00000007) {
165 cpuid(info, 0x00000007);
166 HW_AVX2 = (info[1] & ((int)1 << 5)) != 0;
167
168 HW_BMI1 = (info[1] & ((int)1 << 3)) != 0;
169 HW_BMI2 = (info[1] & ((int)1 << 8)) != 0;
170 HW_ADX = (info[1] & ((int)1 << 19)) != 0;
171 HW_MPX = (info[1] & ((int)1 << 14)) != 0;
172 HW_SHA = (info[1] & ((int)1 << 29)) != 0;
173 HW_PREFETCHWT1 = (info[2] & ((int)1 << 0)) != 0;
174
175 HW_AVX512_F = (info[1] & ((int)1 << 16)) != 0;
176 HW_AVX512_CD = (info[1] & ((int)1 << 28)) != 0;
177 HW_AVX512_PF = (info[1] & ((int)1 << 26)) != 0;
178 HW_AVX512_ER = (info[1] & ((int)1 << 27)) != 0;
179 HW_AVX512_VL = (info[1] & ((int)1 << 31)) != 0;
180 HW_AVX512_BW = (info[1] & ((int)1 << 30)) != 0;
181 HW_AVX512_DQ = (info[1] & ((int)1 << 17)) != 0;
182 HW_AVX512_IFMA = (info[1] & ((int)1 << 21)) != 0;
183 HW_AVX512_VBMI = (info[2] & ((int)1 << 1)) != 0;
184 }
185 if (nExIds >= 0x80000001) {
186 cpuid(info, 0x80000001);
187 HW_x64 = (info[3] & ((int)1 << 29)) != 0;
188 HW_ABM = (info[2] & ((int)1 << 5)) != 0;
189 HW_SSE4a = (info[2] & ((int)1 << 6)) != 0;
190 HW_FMA4 = (info[2] & ((int)1 << 16)) != 0;
191 HW_XOP = (info[2] & ((int)1 << 11)) != 0;
192 }
193#endif
194}
195void cpu_x86::print() const
196{
197 cout << "CPU Vendor:" << endl;
198 print(" AMD = ", Vendor_AMD);
199 print(" Intel = ", Vendor_Intel);
200 cout << endl;
201
202 cout << "OS Features:" << endl;
203#ifdef _WIN32
204 print(" 64-bit = ", OS_x64);
205#endif
206 print(" OS AVX = ", OS_AVX);
207 print(" OS AVX512 = ", OS_AVX512);
208 cout << endl;
209
210 cout << "Hardware Features:" << endl;
211 print(" MMX = ", HW_MMX);
212 print(" x64 = ", HW_x64);
213 print(" ABM = ", HW_ABM);
214 print(" RDRAND = ", HW_RDRAND);
215 print(" BMI1 = ", HW_BMI1);
216 print(" BMI2 = ", HW_BMI2);
217 print(" ADX = ", HW_ADX);
218 print(" MPX = ", HW_MPX);
219 print(" PREFETCHWT1 = ", HW_PREFETCHWT1);
220 cout << endl;
221
222 cout << "SIMD: 128-bit" << endl;
223 print(" SSE = ", HW_SSE);
224 print(" SSE2 = ", HW_SSE2);
225 print(" SSE3 = ", HW_SSE3);
226 print(" SSSE3 = ", HW_SSSE3);
227 print(" SSE4a = ", HW_SSE4a);
228 print(" SSE4.1 = ", HW_SSE41);
229 print(" SSE4.2 = ", HW_SSE42);
230 print(" AES-NI = ", HW_AES);
231 print(" SHA = ", HW_SHA);
232 cout << endl;
233
234 cout << "SIMD: 256-bit" << endl;
235 print(" AVX = ", HW_AVX);
236 print(" XOP = ", HW_XOP);
237 print(" FMA3 = ", HW_FMA3);
238 print(" FMA4 = ", HW_FMA4);
239 print(" AVX2 = ", HW_AVX2);
240 cout << endl;
241
242 cout << "SIMD: 512-bit" << endl;
243 print(" AVX512-F = ", HW_AVX512_F);
244 print(" AVX512-CD = ", HW_AVX512_CD);
245 print(" AVX512-PF = ", HW_AVX512_PF);
246 print(" AVX512-ER = ", HW_AVX512_ER);
247 print(" AVX512-VL = ", HW_AVX512_VL);
248 print(" AVX512-BW = ", HW_AVX512_BW);
249 print(" AVX512-DQ = ", HW_AVX512_DQ);
250 print(" AVX512-IFMA = ", HW_AVX512_IFMA);
251 print(" AVX512-VBMI = ", HW_AVX512_VBMI);
252 cout << endl;
253
254 cout << "Summary:" << endl;
255 print(" Safe to use AVX: ", HW_AVX && OS_AVX);
256 print(" Safe to use AVX512: ", HW_AVX512_F && OS_AVX512);
257 cout << endl;
258}
263} // namespace FeatureDetector
264#endif