Visual Servoing Platform  version 3.2.0 under development (2019-01-22)
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
43 namespace FeatureDetector
44 {
45 using std::cout;
46 using std::endl;
47 using std::memcpy;
48 using std::memset;
53 void cpu_x86::print(const char *label, bool yes)
54 {
55  cout << label;
56  cout << (yes ? "Yes" : "No") << endl;
57 }
62 cpu_x86::cpu_x86()
63 {
64  memset(this, 0, sizeof(*this));
65  detect_host();
66 }
67 bool 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 }
90 bool 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 }
102 std::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 }
123 void 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 }
195 void 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