Visual Servoing Platform version 3.6.0
Loading...
Searching...
No Matches
cpu_x86.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2023 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 cpu_x86::print(const char *label, bool yes)
84{
85 cout << label;
86 cout << (yes ? "Yes" : "No") << endl;
87}
92cpu_x86::cpu_x86()
93{
94 memset(this, 0, sizeof(*this));
95 detect_host();
96}
97bool cpu_x86::detect_OS_AVX()
98{
99#ifndef UNKNOWN_ARCH
100 // Copied from: http://stackoverflow.com/a/22521619/922184
101
102 bool avxSupported = false;
103
104 int cpuInfo[4];
105 cpuid(cpuInfo, 1);
106
107 bool osUsesXSAVE_XRSTORE = (cpuInfo[2] & (1 << 27)) != 0;
108 bool cpuAVXSuport = (cpuInfo[2] & (1 << 28)) != 0;
109
110 if (osUsesXSAVE_XRSTORE && cpuAVXSuport) {
111 uint64_t xcrFeatureMask = xgetbv(_XCR_XFEATURE_ENABLED_MASK);
112 avxSupported = (xcrFeatureMask & 0x6) == 0x6;
113 }
114
115 return avxSupported;
116#else
117 return false;
118#endif
119}
120bool cpu_x86::detect_OS_AVX512()
121{
122#ifndef UNKNOWN_ARCH
123 if (!detect_OS_AVX())
124 return false;
125
126 uint64_t xcrFeatureMask = xgetbv(_XCR_XFEATURE_ENABLED_MASK);
127 return (xcrFeatureMask & 0xe6) == 0xe6;
128#else
129 return false;
130#endif
131}
132std::string cpu_x86::get_vendor_string()
133{
134#ifndef UNKNOWN_ARCH
135 int32_t CPUInfo[4];
136 char name[13];
137
138 cpuid(CPUInfo, 0);
139 memcpy(name + 0, &CPUInfo[1], 4);
140 memcpy(name + 4, &CPUInfo[3], 4);
141 memcpy(name + 8, &CPUInfo[2], 4);
142 name[12] = '\0';
143
144 return name;
145#else
146 return std::string();
147#endif
148}
153void cpu_x86::detect_host()
154{
155#ifndef UNKNOWN_ARCH
156 // OS Features
157 OS_x64 = detect_OS_x64();
158 OS_AVX = detect_OS_AVX();
159 OS_AVX512 = detect_OS_AVX512();
160
161 // Vendor
162 std::string vendor(get_vendor_string());
163 if (vendor == "GenuineIntel") {
164 Vendor_Intel = true;
165 }
166 else if (vendor == "AuthenticAMD") {
167 Vendor_AMD = true;
168 }
169
170 int info[4];
171 cpuid(info, 0);
172 int nIds = info[0];
173
174 cpuid(info, 0x80000000);
175 uint32_t nExIds = info[0];
176
177 // Detect Features
178 if (nIds >= 0x00000001) {
179 cpuid(info, 0x00000001);
180 HW_MMX = (info[3] & ((int)1 << 23)) != 0;
181 HW_SSE = (info[3] & ((int)1 << 25)) != 0;
182 HW_SSE2 = (info[3] & ((int)1 << 26)) != 0;
183 HW_SSE3 = (info[2] & ((int)1 << 0)) != 0;
184
185 HW_SSSE3 = (info[2] & ((int)1 << 9)) != 0;
186 HW_SSE41 = (info[2] & ((int)1 << 19)) != 0;
187 HW_SSE42 = (info[2] & ((int)1 << 20)) != 0;
188 HW_AES = (info[2] & ((int)1 << 25)) != 0;
189
190 HW_AVX = (info[2] & ((int)1 << 28)) != 0;
191 HW_FMA3 = (info[2] & ((int)1 << 12)) != 0;
192
193 HW_RDRAND = (info[2] & ((int)1 << 30)) != 0;
194 }
195 if (nIds >= 0x00000007) {
196 cpuid(info, 0x00000007);
197 HW_AVX2 = (info[1] & ((int)1 << 5)) != 0;
198
199 HW_BMI1 = (info[1] & ((int)1 << 3)) != 0;
200 HW_BMI2 = (info[1] & ((int)1 << 8)) != 0;
201 HW_ADX = (info[1] & ((int)1 << 19)) != 0;
202 HW_MPX = (info[1] & ((int)1 << 14)) != 0;
203 HW_SHA = (info[1] & ((int)1 << 29)) != 0;
204 HW_PREFETCHWT1 = (info[2] & ((int)1 << 0)) != 0;
205
206 HW_AVX512_F = (info[1] & ((int)1 << 16)) != 0;
207 HW_AVX512_CD = (info[1] & ((int)1 << 28)) != 0;
208 HW_AVX512_PF = (info[1] & ((int)1 << 26)) != 0;
209 HW_AVX512_ER = (info[1] & ((int)1 << 27)) != 0;
210 HW_AVX512_VL = (info[1] & ((int)1 << 31)) != 0;
211 HW_AVX512_BW = (info[1] & ((int)1 << 30)) != 0;
212 HW_AVX512_DQ = (info[1] & ((int)1 << 17)) != 0;
213 HW_AVX512_IFMA = (info[1] & ((int)1 << 21)) != 0;
214 HW_AVX512_VBMI = (info[2] & ((int)1 << 1)) != 0;
215 }
216 if (nExIds >= 0x80000001) {
217 cpuid(info, 0x80000001);
218 HW_x64 = (info[3] & ((int)1 << 29)) != 0;
219 HW_ABM = (info[2] & ((int)1 << 5)) != 0;
220 HW_SSE4a = (info[2] & ((int)1 << 6)) != 0;
221 HW_FMA4 = (info[2] & ((int)1 << 16)) != 0;
222 HW_XOP = (info[2] & ((int)1 << 11)) != 0;
223 }
224#endif
225}
226void cpu_x86::print() const
227{
228 cout << "CPU Vendor:" << endl;
229 print(" AMD = ", Vendor_AMD);
230 print(" Intel = ", Vendor_Intel);
231 cout << endl;
232
233 cout << "OS Features:" << endl;
234#ifdef _WIN32
235 print(" 64-bit = ", OS_x64);
236#endif
237 print(" OS AVX = ", OS_AVX);
238 print(" OS AVX512 = ", OS_AVX512);
239 cout << endl;
240
241 cout << "Hardware Features:" << endl;
242 print(" MMX = ", HW_MMX);
243 print(" x64 = ", HW_x64);
244 print(" ABM = ", HW_ABM);
245 print(" RDRAND = ", HW_RDRAND);
246 print(" BMI1 = ", HW_BMI1);
247 print(" BMI2 = ", HW_BMI2);
248 print(" ADX = ", HW_ADX);
249 print(" MPX = ", HW_MPX);
250 print(" PREFETCHWT1 = ", HW_PREFETCHWT1);
251 cout << endl;
252
253 cout << "SIMD: 128-bit" << endl;
254 print(" SSE = ", HW_SSE);
255 print(" SSE2 = ", HW_SSE2);
256 print(" SSE3 = ", HW_SSE3);
257 print(" SSSE3 = ", HW_SSSE3);
258 print(" SSE4a = ", HW_SSE4a);
259 print(" SSE4.1 = ", HW_SSE41);
260 print(" SSE4.2 = ", HW_SSE42);
261 print(" AES-NI = ", HW_AES);
262 print(" SHA = ", HW_SHA);
263 cout << endl;
264
265 cout << "SIMD: 256-bit" << endl;
266 print(" AVX = ", HW_AVX);
267 print(" XOP = ", HW_XOP);
268 print(" FMA3 = ", HW_FMA3);
269 print(" FMA4 = ", HW_FMA4);
270 print(" AVX2 = ", HW_AVX2);
271 cout << endl;
272
273 cout << "SIMD: 512-bit" << endl;
274 print(" AVX512-F = ", HW_AVX512_F);
275 print(" AVX512-CD = ", HW_AVX512_CD);
276 print(" AVX512-PF = ", HW_AVX512_PF);
277 print(" AVX512-ER = ", HW_AVX512_ER);
278 print(" AVX512-VL = ", HW_AVX512_VL);
279 print(" AVX512-BW = ", HW_AVX512_BW);
280 print(" AVX512-DQ = ", HW_AVX512_DQ);
281 print(" AVX512-IFMA = ", HW_AVX512_IFMA);
282 print(" AVX512-VBMI = ", HW_AVX512_VBMI);
283 cout << endl;
284
285 cout << "Summary:" << endl;
286 print(" Safe to use AVX: ", HW_AVX && OS_AVX);
287 print(" Safe to use AVX512: ", HW_AVX512_F && OS_AVX512);
288 cout << endl;
289}
294} // namespace FeatureDetector
295#endif