c++ - supports - procesadores amd compatibles con sse2
¿Cómo verificar si una CPU admite el conjunto de instrucciones SSE3? (5)
¿Es válido el siguiente código para verificar si una CPU admite el conjunto de instrucciones SSE3?
El uso de la función IsProcessorFeaturePresent()
aparentemente no funciona en Windows XP (consulte http://msdn.microsoft.com/en-us/library/ms724482(v=vs.85).aspx ).
bool CheckSSE3()
{
int CPUInfo[4] = {-1};
//-- Get number of valid info ids
__cpuid(CPUInfo, 0);
int nIds = CPUInfo[0];
//-- Get info for id "1"
if (nIds >= 1)
{
__cpuid(CPUInfo, 1);
bool bSSE3NewInstructions = (CPUInfo[2] & 0x1) || false;
return bSSE3NewInstructions;
}
return false;
}
Creé una reproducción de GitHub que detectará la compatibilidad de la CPU y el sistema operativo para todas las principales extensiones de ISA x86: https://github.com/Mysticial/FeatureDetector
Aquí hay una versión más corta:
Primero necesita acceder a la instrucción CPUID:
#ifdef _WIN32
// Windows
#define cpuid(info, x) __cpuidex(info, x, 0)
#else
// GCC Intrinsics
#include <cpuid.h>
void cpuid(int info[4], int InfoType){
__cpuid_count(InfoType, 0, info[0], info[1], info[2], info[3]);
}
#endif
Entonces puedes ejecutar el siguiente código:
// Misc.
bool HW_MMX;
bool HW_x64;
bool HW_ABM; // Advanced Bit Manipulation
bool HW_RDRAND;
bool HW_BMI1;
bool HW_BMI2;
bool HW_ADX;
bool HW_PREFETCHWT1;
// SIMD: 128-bit
bool HW_SSE;
bool HW_SSE2;
bool HW_SSE3;
bool HW_SSSE3;
bool HW_SSE41;
bool HW_SSE42;
bool HW_SSE4a;
bool HW_AES;
bool HW_SHA;
// SIMD: 256-bit
bool HW_AVX;
bool HW_XOP;
bool HW_FMA3;
bool HW_FMA4;
bool HW_AVX2;
// SIMD: 512-bit
bool HW_AVX512F; // AVX512 Foundation
bool HW_AVX512CD; // AVX512 Conflict Detection
bool HW_AVX512PF; // AVX512 Prefetch
bool HW_AVX512ER; // AVX512 Exponential + Reciprocal
bool HW_AVX512VL; // AVX512 Vector Length Extensions
bool HW_AVX512BW; // AVX512 Byte + Word
bool HW_AVX512DQ; // AVX512 Doubleword + Quadword
bool HW_AVX512IFMA; // AVX512 Integer 52-bit Fused Multiply-Add
bool HW_AVX512VBMI; // AVX512 Vector Byte Manipulation Instructions
int info[4];
cpuid(info, 0);
int nIds = info[0];
cpuid(info, 0x80000000);
unsigned nExIds = info[0];
// Detect Features
if (nIds >= 0x00000001){
cpuid(info,0x00000001);
HW_MMX = (info[3] & ((int)1 << 23)) != 0;
HW_SSE = (info[3] & ((int)1 << 25)) != 0;
HW_SSE2 = (info[3] & ((int)1 << 26)) != 0;
HW_SSE3 = (info[2] & ((int)1 << 0)) != 0;
HW_SSSE3 = (info[2] & ((int)1 << 9)) != 0;
HW_SSE41 = (info[2] & ((int)1 << 19)) != 0;
HW_SSE42 = (info[2] & ((int)1 << 20)) != 0;
HW_AES = (info[2] & ((int)1 << 25)) != 0;
HW_AVX = (info[2] & ((int)1 << 28)) != 0;
HW_FMA3 = (info[2] & ((int)1 << 12)) != 0;
HW_RDRAND = (info[2] & ((int)1 << 30)) != 0;
}
if (nIds >= 0x00000007){
cpuid(info,0x00000007);
HW_AVX2 = (info[1] & ((int)1 << 5)) != 0;
HW_BMI1 = (info[1] & ((int)1 << 3)) != 0;
HW_BMI2 = (info[1] & ((int)1 << 8)) != 0;
HW_ADX = (info[1] & ((int)1 << 19)) != 0;
HW_SHA = (info[1] & ((int)1 << 29)) != 0;
HW_PREFETCHWT1 = (info[2] & ((int)1 << 0)) != 0;
HW_AVX512F = (info[1] & ((int)1 << 16)) != 0;
HW_AVX512CD = (info[1] & ((int)1 << 28)) != 0;
HW_AVX512PF = (info[1] & ((int)1 << 26)) != 0;
HW_AVX512ER = (info[1] & ((int)1 << 27)) != 0;
HW_AVX512VL = (info[1] & ((int)1 << 31)) != 0;
HW_AVX512BW = (info[1] & ((int)1 << 30)) != 0;
HW_AVX512DQ = (info[1] & ((int)1 << 17)) != 0;
HW_AVX512IFMA = (info[1] & ((int)1 << 21)) != 0;
HW_AVX512VBMI = (info[2] & ((int)1 << 1)) != 0;
}
if (nExIds >= 0x80000001){
cpuid(info,0x80000001);
HW_x64 = (info[3] & ((int)1 << 29)) != 0;
HW_ABM = (info[2] & ((int)1 << 5)) != 0;
HW_SSE4a = (info[2] & ((int)1 << 6)) != 0;
HW_FMA4 = (info[2] & ((int)1 << 16)) != 0;
HW_XOP = (info[2] & ((int)1 << 11)) != 0;
}
Tenga en cuenta que esto solo detecta si la CPU admite las instrucciones. Para ejecutarlos realmente, también necesita tener soporte para el sistema operativo.
Específicamente, se requiere soporte del sistema operativo para:
- x64 instrucciones. (Necesita un sistema operativo de 64 bits).
- Instrucciones que usan los registros (
ymm
) de AVX 256ymm
. Vea la respuesta de Andy Lutomirski sobre cómo detectar esto. - Instrucciones que utilizan los registros de máscara (AVX512) de 512 bits
zmm
y máscara. La detección del soporte del sistema operativo para AVX512 es la misma que con AVX, pero utilizando el indicador0xe6
lugar de0x6
.
Después de buscar en Google, también encontré las soluciones de Intel:
void cpuid(uint32_t eax, uint32_t ecx, uint32_t* abcd) {
#if defined(_MSC_VER)
__cpuidex((int*)abcd, eax, ecx);
#else
uint32_t ebx, edx;
# if defined( __i386__ ) && defined ( __PIC__ )
/* in case of PIC under 32-bit EBX cannot be clobbered */
__asm__("movl %%ebx, %%edi /n/t cpuid /n/t xchgl %%ebx, %%edi" : "=D" (ebx),
# else
__asm__("cpuid" : "+b" (ebx),
# endif
"+a" (eax), "+c" (ecx), "=d" (edx));
abcd[0] = eax; abcd[1] = ebx; abcd[2] = ecx; abcd[3] = edx;
#endif
}
int check_xcr0_ymm()
{
uint32_t xcr0;
#if defined(_MSC_VER)
xcr0 = (uint32_t)_xgetbv(0); /* min VS2010 SP1 compiler is required */
#else
__asm__("xgetbv" : "=a" (xcr0) : "c" (0) : "%edx");
#endif
return ((xcr0 & 6) == 6); /* checking if xmm and ymm state are enabled in XCR0 */
}
También tenga en cuenta que GCC tiene algunas características intrínsecas especiales que puede usar (vea: http://gcc.gnu.org/onlinedocs/gcc/X86-Built-in-Functions.html ):
if (__builtin_cpu_supports("avx2"))
// ...
Si pones esto junto con la información anterior, todo saldrá bien.
En un Mac OS esto funciona:
sysctl -a | grep machdep.cpu.features
En mi máquina produce esto:
machdep.cpu.features: FPU VME DE PSE TSC MSR PAE MCE CX8 APIC SEP MTRR PGE MCA CMOV PAT PSE36 CLFSH DS ACPI MMX FXSR SSE SSE2 SS HTT TM PBE SSE3 PCLMULQDQ DTES64 MON DSCPL VMX EST TM2 SSSE3 FMA CX16 TPR PDCM SSE4.1 SSE4.2 x2APIC MOVBE POPCNT AES PCID XSAVE OSXSAVE SEGLIM64 TSCTMR AVX1.0 RDRAND F16C
Como puede ver con las instrucciones escritas en negrita, SSE3 y muchas otras instrucciones SIMD son compatibles.
La respuesta de Mysticial es un poco peligrosa: explica cómo detectar el soporte de la CPU pero no el soporte del sistema operativo. Debe usar _xgetbv para verificar si el sistema operativo ha habilitado el estado extendido requerido de la CPU. Vea here para otra fuente. Incluso gcc ha cometido el mismo error. La carne del código es:
bool avxSupported = false;
int cpuInfo[4];
__cpuid(cpuInfo, 1);
bool osUsesXSAVE_XRSTORE = cpuInfo[2] & (1 << 27) || false;
bool cpuAVXSuport = cpuInfo[2] & (1 << 28) || false;
if (osUsesXSAVE_XRSTORE && cpuAVXSuport)
{
unsigned long long xcrFeatureMask = _xgetbv(_XCR_XFEATURE_ENABLED_MASK);
avxSupported = (xcrFeatureMask & 0x6) == 0x6;
}
Para agregar a la respuesta de Abhiroop: en Linux, puede ejecutar este comando de shell para descubrir las características compatibles con su CPU
cat /proc/cpuinfo | grep flags | uniq
En mi máquina esto imprime
flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single retpoline kaiser fsgsbase bmi1 hle avx2 smep bmi2 erms invpcid rtm rdseed adx xsaveopt