Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
cpu_x86.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4 *
5 * This software 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 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 */
30
31/* cpu_x86.cpp
32 *
33 * Author : Alexander J. Yee
34 * Date Created : 04/12/2014
35 * Last Modified : 04/12/2014
36 *
37 * Modification for ViSP:
38 * - UNKNOWN_ARCH (ARM, ...)
39 * - ifndef _XCR_XFEATURE_ENABLED_MASK (MinGW)
40 */
41
46// Dependencies
47#include "cpu_x86.h"
48#include <cstring>
49#include <iostream>
54#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)
55#if defined(_WIN32) && (!defined(__MINGW32__) || (!defined(__i386) && !defined(_M_IX86)))
56#include "cpu_x86_Windows.ipp"
57#elif defined(__GNUC__) || defined(__clang__)
58#include "cpu_x86_Linux.ipp"
59#else
60//# error "No cpuid intrinsic defined for compiler."
61#define UNKNOWN_ARCH
62#endif
63#else
64//# error "No cpuid intrinsic defined for processor architecture."
65#define UNKNOWN_ARCH
66#endif
67
68#ifndef _XCR_XFEATURE_ENABLED_MASK
69#define _XCR_XFEATURE_ENABLED_MASK 0
70#endif
71
72#ifndef DOXYGEN_SHOULD_SKIP_THIS
73namespace FeatureDetector
74{
75using std::cout;
76using std::endl;
77using std::memcpy;
78using std::memset;
83void cpuX86::print(const char *label, bool yes)
84{
85 cout << label;
86 cout << (yes ? "Yes" : "No") << endl;
87}
92cpuX86::cpuX86()
93{
94 memset(this, 0, sizeof(*this));
95 detect_host();
96}
97bool cpuX86::detect_OS_AVX()
98{
99#ifndef UNKNOWN_ARCH
100 // Copied from: http://stackoverflow.com/a/22521619/922184
101
102 bool avxSupported = false;
103
104 uint32_t cpuInfo[4];
105 cpuid(cpuInfo, 1);
106 const unsigned int index_2 = 2;
107 const unsigned int val_27 = 27;
108 const unsigned int val_28 = 28;
109
110 bool osUsesXSAVE_XRSTORE = (cpuInfo[index_2] & (1U << val_27)) != 0;
111 bool cpuAVXSuport = (cpuInfo[index_2] & (1U << val_28)) != 0;
112
113 if (osUsesXSAVE_XRSTORE && cpuAVXSuport) {
114 uint64_t xcrFeatureMask = xgetbv(_XCR_XFEATURE_ENABLED_MASK);
115 avxSupported = (xcrFeatureMask & 0x6U) == 0x6U;
116 }
117
118 return avxSupported;
119#else
120 return false;
121#endif
122}
123bool cpuX86::detect_OS_AVX512()
124{
125#ifndef UNKNOWN_ARCH
126 if (!detect_OS_AVX()) {
127 return false;
128 }
129
130 uint64_t xcrFeatureMask = xgetbv(_XCR_XFEATURE_ENABLED_MASK);
131 return (xcrFeatureMask & 0xe6U) == 0xe6U;
132#else
133 return false;
134#endif
135}
136std::string cpuX86::get_vendor_string()
137{
138#ifndef UNKNOWN_ARCH
139 uint32_t CPUInfo[4];
140 char name[13];
141
142 cpuid(CPUInfo, 0);
143 const unsigned int index_1 = 1;
144 const unsigned int index_2 = 2;
145 const unsigned int index_3 = 3;
146 const unsigned int val_4 = 4;
147 memcpy(name + 0, &CPUInfo[index_1], val_4);
148 memcpy(name + 4, &CPUInfo[index_3], val_4);
149 memcpy(name + 8, &CPUInfo[index_2], val_4);
150 name[12] = '\0';
151
152 return name;
153#else
154 return std::string();
155#endif
156}
161void cpuX86::detect_host()
162{
163#ifndef UNKNOWN_ARCH
164 // OS Features
165 OS_x64 = detect_OS_x64();
166 OS_AVX = detect_OS_AVX();
167 OS_AVX512 = detect_OS_AVX512();
168
169 // Vendor
170 std::string vendor(get_vendor_string());
171 if (vendor == "GenuineIntel") {
172 Vendor_Intel = true;
173 }
174 else if (vendor == "AuthenticAMD") {
175 Vendor_AMD = true;
176 }
177
178 uint32_t info[4];
179 cpuid(info, 0);
180 int nIds = info[0];
181
182 cpuid(info, 0x80000000);
183 uint32_t nExIds = info[0];
184 const unsigned int index_1 = 1;
185 const unsigned int index_2 = 2;
186 const unsigned int index_3 = 3;
187 const unsigned int val_1 = 1;
188 const unsigned int val_3 = 3;
189 const unsigned int val_5 = 5;
190 const unsigned int val_6 = 6;
191 const unsigned int val_8 = 8;
192 const unsigned int val_9 = 9;
193 const unsigned int val_11 = 11;
194 const unsigned int val_12 = 12;
195 const unsigned int val_14 = 14;
196 const unsigned int val_16 = 16;
197 const unsigned int val_17 = 17;
198 const unsigned int val_19 = 19;
199 const unsigned int val_20 = 20;
200 const unsigned int val_21 = 21;
201 const unsigned int val_23 = 23;
202 const unsigned int val_25 = 25;
203 const unsigned int val_26 = 26;
204 const unsigned int val_27 = 27;
205 const unsigned int val_28 = 28;
206 const unsigned int val_29 = 29;
207 const unsigned int val_30 = 30;
208 const unsigned int val_31 = 31;
209
210 // Detect Features
211 if (nIds >= 0x00000001) {
212 cpuid(info, 0x00000001);
213 HW_MMX = (info[index_3] & (1U << val_23)) != 0U;
214 HW_SSE = (info[index_3] & (1U << val_25)) != 0U;
215 HW_SSE2 = (info[index_3] & (1U << val_26)) != 0U;
216 HW_SSE3 = (info[index_2] & (1U << 0)) != 0U;
217
218 HW_SSSE3 = (info[index_2] & (1U << val_9)) != 0U;
219 HW_SSE41 = (info[index_2] & (1U << val_19)) != 0U;
220 HW_SSE42 = (info[index_2] & (1U << val_20)) != 0U;
221 HW_AES = (info[index_2] & (1U << val_25)) != 0U;
222
223 HW_AVX = (info[index_2] & (1U << val_28)) != 0U;
224 HW_FMA3 = (info[index_2] & (1U << val_12)) != 0U;
225
226 HW_RDRAND = (info[index_2] & (1U << val_30)) != 0U;
227 }
228 if (nIds >= 0x00000007) {
229 cpuid(info, 0x00000007);
230 HW_AVX2 = (info[index_1] & (1U << val_5)) != 0U;
231
232 HW_BMI1 = (info[index_1] & (1U << val_3)) != 0U;
233 HW_BMI2 = (info[index_1] & (1U << val_8)) != 0U;
234 HW_ADX = (info[index_1] & (1U << val_19)) != 0U;
235 HW_MPX = (info[index_1] & (1U << val_14)) != 0U;
236 HW_SHA = (info[index_1] & (1U << val_29)) != 0U;
237 HW_PREFETCHWT1 = (info[index_2] & (1U << 0)) != 0U;
238
239 HW_AVX512_F = (info[index_1] & (1U << val_16)) != 0U;
240 HW_AVX512_CD = (info[index_1] & (1U << val_28)) != 0U;
241 HW_AVX512_PF = (info[index_1] & (1U << val_26)) != 0U;
242 HW_AVX512_ER = (info[index_1] & (1U << val_27)) != 0U;
243 HW_AVX512_VL = (info[index_1] & (1U << val_31)) != 0U;
244 HW_AVX512_BW = (info[index_1] & (1U << val_30)) != 0U;
245 HW_AVX512_DQ = (info[index_1] & (1U << val_17)) != 0U;
246 HW_AVX512_IFMA = (info[index_1] & (1U << val_21)) != 0U;
247 HW_AVX512_VBMI = (info[index_2] & (1U << val_1)) != 0U;
248 }
249 if (nExIds >= 0x80000001) {
250 cpuid(info, 0x80000001);
251 HW_x64 = (info[index_3] & (1U << val_29)) != 0U;
252 HW_ABM = (info[index_2] & (1U << val_5)) != 0U;
253 HW_SSE4a = (info[index_2] & (1U << val_6)) != 0U;
254 HW_FMA4 = (info[index_2] & (1U << val_16)) != 0U;
255 HW_XOP = (info[index_2] & (1U << val_11)) != 0U;
256 }
257#endif
258}
259void cpuX86::print() const
260{
261 cout << "CPU Vendor:" << endl;
262 print(" AMD = ", Vendor_AMD);
263 print(" Intel = ", Vendor_Intel);
264 cout << endl;
265
266 cout << "OS Features:" << endl;
267#ifdef _WIN32
268 print(" 64-bit = ", OS_x64);
269#endif
270 print(" OS AVX = ", OS_AVX);
271 print(" OS AVX512 = ", OS_AVX512);
272 cout << endl;
273
274 cout << "Hardware Features:" << endl;
275 print(" MMX = ", HW_MMX);
276 print(" x64 = ", HW_x64);
277 print(" ABM = ", HW_ABM);
278 print(" RDRAND = ", HW_RDRAND);
279 print(" BMI1 = ", HW_BMI1);
280 print(" BMI2 = ", HW_BMI2);
281 print(" ADX = ", HW_ADX);
282 print(" MPX = ", HW_MPX);
283 print(" PREFETCHWT1 = ", HW_PREFETCHWT1);
284 cout << endl;
285
286 cout << "SIMD: 128-bit" << endl;
287 print(" SSE = ", HW_SSE);
288 print(" SSE2 = ", HW_SSE2);
289 print(" SSE3 = ", HW_SSE3);
290 print(" SSSE3 = ", HW_SSSE3);
291 print(" SSE4a = ", HW_SSE4a);
292 print(" SSE4.1 = ", HW_SSE41);
293 print(" SSE4.2 = ", HW_SSE42);
294 print(" AES-NI = ", HW_AES);
295 print(" SHA = ", HW_SHA);
296 cout << endl;
297
298 cout << "SIMD: 256-bit" << endl;
299 print(" AVX = ", HW_AVX);
300 print(" XOP = ", HW_XOP);
301 print(" FMA3 = ", HW_FMA3);
302 print(" FMA4 = ", HW_FMA4);
303 print(" AVX2 = ", HW_AVX2);
304 cout << endl;
305
306 cout << "SIMD: 512-bit" << endl;
307 print(" AVX512-F = ", HW_AVX512_F);
308 print(" AVX512-CD = ", HW_AVX512_CD);
309 print(" AVX512-PF = ", HW_AVX512_PF);
310 print(" AVX512-ER = ", HW_AVX512_ER);
311 print(" AVX512-VL = ", HW_AVX512_VL);
312 print(" AVX512-BW = ", HW_AVX512_BW);
313 print(" AVX512-DQ = ", HW_AVX512_DQ);
314 print(" AVX512-IFMA = ", HW_AVX512_IFMA);
315 print(" AVX512-VBMI = ", HW_AVX512_VBMI);
316 cout << endl;
317
318 cout << "Summary:" << endl;
319 print(" Safe to use AVX: ", HW_AVX && OS_AVX);
320 print(" Safe to use AVX512: ", HW_AVX512_F && OS_AVX512);
321 cout << endl;
322}
327} // namespace FeatureDetector
328#endif