The Assembly Method
To retrieve CPU information, you must use the CPUID (Central Processing Unit Identification) instruction. You can test whether your CPU supports this instruction like this:
bool CPUID_supported()
{
__try {
_asm {
xor eax, eax
cpuid
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
return false;
}
return true;
}
The following steps must be taken to get processor information:
- Establish that the processor has support for CPUID.
- Execute CPUID function 0, which returns the processor vendor string and the highest standard function supported.
- If step 2 indicates that the highest standard function is at least 1, execute CPUID function 1, which returns the standard feature flags in the EDX register.
- If bit 23 of the standard feature flags is set to 1, MMX technology is supported. MMX instruction support is the basic minimum processor feature required to support other instruction extensions.
- Optionally, if bit 25 of the standard feature flags is set, the processor has streaming SIMD extensions (SSE) capabilities. Further qualification of SSE is done by checking for OS support. SSE support might be present in the processor, but not usable due to a lack of OS support for the additional architected registers.
- Execute CPUID extended function 80000000h. This function returns the highest extended function supported in EAX. If EAX=0, there is no support for extended functions.
- If the highest extended function supported is at least 8000_0001h, execute CPUID function 80000001h. This function returns the extended feature flags in EDX.
- If bit 31 of the extended feature flags is set to 1, the 3DNow! instructions are supported.
- If the vendor string contains "AuthenticAMD", continue on to the next step.
- If bit 30 of the extended feature flags is set to 1, the additions to the 3DNow! instruction set are supported.
- If bit 22 of the extended feature flags is set to 1, the new multimedia enhancement instructions that augment the MMX instruction set are supported.
All this is put in CPUAssembly class presented below.
The Registry Method
Windows keeps processor information in the Registry. For each processor present in the system there is a Registry key, called, 0, 1, etc. in
HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor
If you have a single processor, there is only key 0. The values under this key are:
| Value |
Description |
| ~MHz |
Speed in MHz |
| Component Information |
Processor information |
| Configuration Data |
Configuration data |
| FeatureSet |
bit flags for supported features |
| Identifier |
Contains family, model, and stepping |
| ProcessorNameString |
Processors name |
| Update Status |
Update status |
| VendorIdentifier |
Vendor name |
Similarly, for each floating point processor there is a key named 0, 1, etc. in
HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\FloatingPointProcessor
See the CPURegistry class below.
The Platform SDK Method
You must have Platform SDK installed on your computer to use this method.
Windows System Information section of Platform SDK provides functions to retrieve or set system information. GetSystemInfo() and IsProcessorFeaturePresent() can be used to find processor related information.
The GetSystemInfo() function returns information about the current system and uses SYSTEM_INFO structure which contains information about the current computer system. This includes the architecture and type of the processor, the number of processors in the system, the page size, and other such information. See MSDN for more.
The IsProcessorFeaturePresent() function determines whether the specified processor feature, such as MMX, SEE, or 3DNow is supported by the current computer.
Putting All Together
To show how each method can be used to retrieve processor information, I have created three classes CPUAssembly, CPURegistry, and CPUPlatformSDK. All of them are derived from an abstract class called ICPUInfo:
class ICPUInfo
{
public:
virtual bool QueryCPUInfo() = 0;
virtual unsigned __int64 GetSpeed() const;
std::string FormatSpeed(unsigned __int64 speed) const;
virtual unsigned int GetSpeedMHz()const = 0;
virtual std::string GetCPUName() const = 0;
virtual std::string GetVendorName() const;
std::string GetCPUName(std::string vendor, short int family,
short int model, short int family_ex,
short int model_ex) const;
virtual short int GetCPUFamily() const = 0;
virtual short int GetCPUModel() const = 0;
virtual short int GetCPUStepping() const = 0;
virtual bool IsMMXSupported() const = 0;
virtual bool IsSSESupported() const = 0;
virtual bool IsSSE2Supported() const = 0;
virtual bool Is3DNowSupported() const = 0;
};
QueryCPUInfo() retrieves the processor information and must be call first. If this method returns false, processor information could not be retrieved. Call the other methods only if the returned value is true.
GetSpeed() returns the speed of CPU. The assembly and Platform SDK implementations use the same method for speed measurement, and the returned value is in Hz.
unsigned __int64 ICPUInfo::GetSpeed() const
{
unsigned __int64 start, stop;
unsigned __int64 nCtr, nFreq, nCtrStop;
QueryPerformanceFrequency((LARGE_INTEGER *)&nFreq);
_asm _emit 0x0F
_asm _emit 0x31
_asm mov DWORD PTR start, eax
_asm mov DWORD PTR [start+4], edx
QueryPerformanceCounter((LARGE_INTEGER *)&nCtrStop);
nCtrStop += nFreq;
do
{
QueryPerformanceCounter((LARGE_INTEGER *)&nCtr);
}while (nCtr < nCtrStop);
_asm _emit 0x0F
_asm _emit 0x31
_asm mov DWORD PTR stop, eax
_asm mov DWORD PTR [stop+4], edx
return (stop-start);
}
GetSpeedMHz() returns the speed in MHz.
FormatSpeed() returns the CPU's speed in normalized format. Eg: 166MHz, 1.39GHz.
GetCPUName() returns the name of the processor.
GetVendorName() returns the name of processor vendor, which is 12 bytes long.
GetCPUFamily() returns the family number, a 4-bits value.
GetCPUModel() returns the model number, a 4-bits value.
GetCPUStepping() returns the processor revision number.
IsMMXSupported() returns true if MMX instruction set is present.
IsSSEupported() returns true if SSE (Streaming SIMD Extensions) instruction set is present.
IsSSE2Supported() returns true if SSE2 instruction set is present.
Is3DNowSupported() returns true if 3DNow! instruction set is present.
A simple example with all the three classes is presented below:
void PrintCPUInfo(ICPUInfo* info)
{
if(!info->QueryCPUInfo())
return;
cout << "Name:\t\t" << info->GetCPUName() << endl;
cout << "Speed:\t\t" << info->GetSpeedMHz() << "MHz" << endl;
cout << "Vendor:\t\t" << info->GetVendorName() << endl;
cout << "Family:\t\t" << info->GetCPUFamily() << endl;
cout << "Model:\t\t" << info->GetCPUModel() << endl;
cout << "Stepping:\t" << info->GetCPUStepping() << endl;
cout << "Features" << endl;
cout << "\tMMX:\t" << (info->IsMMXSupported() ? "yes" : "no")
<< endl;
cout << "\t3DNow:\t" << (info->Is3DNowSupported() ? "yes" : "no")
<< endl;
cout << "\tSSE:\t" << (info->IsSSESupported() ? "yes" : "no")
<< endl;
cout << "\tSSE2:\t" << (info->IsSSE2Supported() ? "yes" : "no")
<< endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
ICPUInfo* reg = new CPURegistry;
cout << "----- REGISTRY METHOD -------" << endl;
PrintCPUInfo(reg);
delete reg;
ICPUInfo* sdk = new CPUPlatformSDK;
cout << "----- PLATFORM SDK METHOD -------" << endl;
PrintCPUInfo(sdk);
delete sdk;
CPUAssembly* assembly = new CPUAssembly;
cout << "----- ASSEMBLY METHOD -------" << endl;
PrintCPUInfo(assembly);
delete assembly;
return 0;
}
See the attached files for more details.
References
See these links for further references and related topics:
Comments
There are no comments yet. Be the first to comment!