Just to add the @Guilherme Bernal reply and share the code.
I made a program to test the class that William posted and it looks like
working. I haven’t fully tested yet as this varies from PC to PC.
(I compiled in MSVC 2013, but should work in GCC as well).
I tested in a Core i5 and the result seems correct (compared with Cpuz).
Stayed like this:
#ifndef HARDWARE_HPP_INCLUDED
#define HARDWARE_HPP_INCLUDED
#include <string>
#ifdef _WIN32
#include <limits.h>
#include <intrin.h>
typedef unsigned __int32 uint32_t;
#else
#include <stdint.h>
#endif
namespace hardware
{
enum TechEAX
{
kFSGSBASE = (1 << 0),
kBMI = (1 << 3),
kHLE = (1 << 4),
kAVX2 = (1 << 5),
kBMI2 = (1 << 8),
kRTM = (1 << 11),
kRDSEED = (1 << 18),
kADX = (1 << 19),
};
enum TechECX
{
kSSE3 = (1 << 0),
kPCLMUL = (1 << 1),
kLZCNT = (1 << 5),
kSSSE3 = (1 << 9),
kFMA = (1 << 12),
kCMPXCHG16B = (1 << 13),
kSSE4_1 = (1 << 19),
kSSE4_2 = (1 << 20),
kMOVBE = (1 << 22),
kPOPCNT = (1 << 23),
kAES = (1 << 25),
kXSAVE = (1 << 26),
kOSXSAVE = (1 << 27),
kAVX = (1 << 28),
kF16C = (1 << 29),
kRDRND = (1 << 30),
kLAHF_LM = (1 << 0),
kABM = (1 << 5),
kSSE4a = (1 << 6),
kPRFCHW = (1 << 8),
kXOP = (1 << 11),
kLWP = (1 << 15),
kFMA4 = (1 << 16),
kTBM = (1 << 21)
};
enum TechEDX
{
kCMPXCHG8B = (1 << 8),
kCMOV = (1 << 15),
kMMX = (1 << 23),
kFXSAVE = (1 << 24),
kSSE = (1 << 25),
kSSE2 = (1 << 26),
kMMXEXT = (1 << 22),
kLM = (1 << 29),
k3DNOWP = (1 << 30),
k3DNOW = (1 << 31)
};
class CPU
{
public:
CPU();
std::string getVendor() const;
bool checkTechnology(TechEAX tech) const;
bool checkTechnology(TechECX tech) const;
bool checkTechnology(TechEDX tech) const;
private:
void load(unsigned value) const;
const uint32_t& EAX() const
{
return regs[0];
}
const uint32_t& EBX() const
{
return regs[1];
}
const uint32_t& ECX() const
{
return regs[2];
}
const uint32_t& EDX() const
{
return regs[3];
}
private:
uint32_t regs[4];
};
}
#endif
#include "hardware.hpp"
namespace hardware
{
CPU::CPU()
{
this->load(0);
}
bool CPU::checkTechnology(TechEAX tech) const
{
this->load(7);
return (EAX() & tech) != 0;
}
bool CPU::checkTechnology(TechECX tech) const
{
this->load(1);
return (ECX() & tech) != 0;
}
bool CPU::checkTechnology(TechEDX tech) const
{
this->load(1);
return (EDX() & tech) != 0;
}
std::string CPU::getVendor() const
{
std::string vendor;
vendor += std::string((const char *)&EBX(), 4);
vendor += std::string((const char *)&EDX(), 4);
vendor += std::string((const char *)&ECX(), 4);
if (vendor == "AMDisbetter!" || vendor == "AuthenticAMD") return "AMD";
if (vendor == "GenuineIntel") return "Intel";
if (vendor == "VIA VIA VIA ") return "VIA";
if (vendor == "CentaurHauls") return "Centaur";
if (vendor == "CyrixInstead") return "Cyrix";
if (vendor == "TransmetaCPU" || vendor == "GenuineTMx86") return "Transmeta";
if (vendor == "Geode by NSC") return "National Semiconductor";
if (vendor == "NexGenDriven") return "NexGen";
if (vendor == "RiseRiseRise") return "Rise";
if (vendor == "SiS SiS SiS ") return "SiS";
if (vendor == "UMC UMC UMC ") return "UMC";
if (vendor == "Vortex86 SoC") return "Vortex";
if (vendor == "KVMKVMKVMKVM") return "KVM";
if (vendor == "Microsoft Hv") return "Microsoft Hyper-V";
if (vendor == "VMwareVMware") return "VMware";
if (vendor == "XenVMMXenVMM") return "Xen HVM";
return vendor;
}
void CPU::load(unsigned value) const
{
#ifdef _WIN32
__cpuid((int *) regs, (int)value);
#else
asm volatile
("cpuid" : "=a" (regs[0]), "=b" (regs[1]), "=c" (regs[2]), "=d" (regs[3])
: "a" (i), "c" (0));
// ECX is set to zero for CPUID function 4
#endif
}
}
#include <iostream>
#include "hardware.hpp"
int main(int argc, char** argv)
{
using namespace hardware;
CPU cpu;
std::cout << "Fabricante: " << cpu.getVendor() << std::endl;
std::cout << " SSE: " << cpu.checkTechnology(kSSE) << std::endl;
std::cout << " SSE2: " << cpu.checkTechnology(kSSE2) << std::endl;
std::cout << " SSE3: " << cpu.checkTechnology(kSSE3) << std::endl;
std::cout << " SSSE3: " << cpu.checkTechnology(kSSSE3) << std::endl;
std::cout << " SSE4.1: " << cpu.checkTechnology(kSSE4_1) << std::endl;
std::cout << " SSE4.2: " << cpu.checkTechnology(kSSE4_2) << std::endl;
std::cout << " SSE4A: " << cpu.checkTechnology(kSSE4a) << std::endl;
std::cout << " AES: " << cpu.checkTechnology(kAES) << std::endl;
std::cout << " AVX: " << cpu.checkTechnology(kAVX) << std::endl;
std::cout << " AVX2: " << cpu.checkTechnology(kAVX2) << std::endl;
std::cin.get();
return 0;
}
Output stayed (for the Intel Core i5 Sandy Bridge):
Fabricante: Intel
SSE: 1
SSE2: 1
SSE3: 1
SSSE3: 1
SSE4.1: 1
SSE4.2: 1
SSE4A: 1
AES: 1
AVX: 1
AVX2: 0
My recommendation (if there is no longer one in this sense), create a FOSS project on github for this purpose, make its original implementation and leave it open to contributions. I used to work in a company that did detection of machines for inventory and the code of the CPUID instructions was something that always had to be maintained with dedication, affection and revised for new architectures. There was a lot of problem, CPUZ staff lib was acquired specifically for memory detection that is more complicated, when this happened, it was considered to abandon CPUID for something that CPUZ lib already offered
– pepper_chico
@Okay. I’ll see if I can do it. I posted here so that the result was close to the question to help in the future, in case someone has the same doubt.
– Lucas Lima