Sign in to follow this  
mark ds

Has anyone got a simple cpuid class to share?

Recommended Posts

OK, so cpuid isn't the hardest thing in the world to use...

But has anyone got a pre-built c++ class (or even straight c code) which gets the number of CPUs, number of cores, and (in the case of intel) whether or not hyperthreading is enabled? CPU frequency would be usefull too, but not overly important, as would various SSE capabilities.

I know, I'm lazy! But this must have written a gazillion times already!

Thank you kindly!

Share this post


Link to post
Share on other sites
here
[url="http://lmgtfy.com/?q=c%2B%2B+cpu+information"]http://lmgtfy.com/?q=c%2B%2B+cpu+information[/url]

Share this post


Link to post
Share on other sites
[quote name='mark ds' timestamp='1339195800' post='4947515']
I know, I'm lazy! But this must have written a gazillion times already!
[/quote]
I'm afraid I'll have to agree with that. The LMGTFY link is quite right.

On the top of the search results:
* how to use the __CPUID to do what you asked
* how to use WMI to do what you asked
* how to pull from the registry entry HKLM\Hardware\Description\[i]System\CentralProcessor\[/i] to do what you asked.

Three ways to do it in the top five search results, each with code examples.

Share this post


Link to post
Share on other sites
Thanks for the replies.

FWIW, I know how to use cpuid and the Windows functions, but I'm trying to get the most important information in a non OS specific manner.

The trouble with cpuid is that most libs actually report the wrong number of logical processors - my i7 920 is reported as having 16 logical processors, which according to intel docs is actually the maximum number of logical cores representable in a given core technology.

The correct way is the query all the cache information and find different levels of shared cache, although I think there may be another 'hack' using bits 14 to 31 in 0x4H. I was interested to see if there was a definitive way that's universally accepted. Edited by mark ds

Share this post


Link to post
Share on other sites
Th correct answer is, don't use __cpuid.

__cpuid only gives the processor caps, not what is actuallu enabled. For that, you MUST use the OS services.

In the worst case scenario, Hypertherading may be disabled in the BIOS, and certain physical cores may be disbaled by the OS. Which means that __cpuid is not a valid way of checking cpu caps.

So to conlcude, use the OS service to understand the actual environment you're in. Edited by mark ds

Share this post


Link to post
Share on other sites
Unfortunately I've even seen the OS (Windows, not sure which version) lie about this.
I believe any code that does not look at the APIC IDs (this apparently including libcpuid, after a quick browse) is completely broken in that respect. Intel has long said APIC IDs are not necessarily contiguous (0..#enabled-1). However, even the package/core/logical fields extracted with their recommended algorithm are not contiguous - you might see coreID = {0,1,6,7}.

Here's my best attempt at getting it right, successfully tested on some interesting hardware (up to 64 processors) -
[url="http://trac.wildfiregames.com/browser/ps/trunk/source/lib/sysdep/arch/x86_x64/topology.cpp"]http://trac.wildfire...64/topology.cpp[/url]

Share this post


Link to post
Share on other sites
[quote name]Jan Wassenberg [/quote]

Thank you very much! I'll enjoy going through the source. A quick question... does this take into account someone disabling HT in the BIOS, or someone disabling cores in the OS?

I'm now using GetLogicalProcessorInformation(), which (in theory) should give me the actual processor caps. Is your version a better way of determining this? Edited by mark ds

Share this post


Link to post
Share on other sites
Yes, those cases (as well as restricted process affinity) would be detected - if a core/logical processor isn't running/available, its APIC ID will not be counted.
Unfortunately I don't remember which of the Windows functions returned inaccurate information. I would advise against the use of GetLogicalProcessorInformation, though - its interface is just about as complex as digging through the APIC IDs and it cannot be relied upon to differentiate logical processors vs cores.

Share this post


Link to post
Share on other sites
Thanks Jan

This is what I have come up with, which seems to work very well...

[source lang="java"]void CProcessor::getCaps( void )
{
int cpuInfo[4] = { 0 }; // EAX EBX ECX EDX return from __cpuid

affinityMask = NULL;
physicalCores = 0;
hyperThreading = false;
MMX = false;
SSE = false;
SSE2 = false;
SSE3 = false;
SSSE3 = false;
SSE41 = false;
SSE42 = false;
AVX = false;
AES = false;
memset( cpuBrandString, 0, sizeof( cpuBrandString ) );
memset( cpuString, 0, sizeof( cpuString ) );

//Get cpu caps from cpuid

// cpu string GenuineIntel or AuthenticAMD
__cpuid( cpuInfo, 0 );
*(int*) ( cpuString + 0 ) = cpuInfo[1];
*(int*) ( cpuString + 4 ) = cpuInfo[3];
*(int*) ( cpuString + 8 ) = cpuInfo[2];

__cpuid( cpuInfo, 1 );
SSE3 = ( cpuInfo[2] >> 0 ) & 0x1;
SSSE3 = ( cpuInfo[2] >> 9 ) & 0x1;
SSE41 = ( cpuInfo[2] >> 19 ) & 0x1;
SSE42 = ( cpuInfo[2] >> 20 ) & 0x1;
AES = ( cpuInfo[2] >> 25 ) & 0x1;
AVX = ( cpuInfo[2] >> 28 ) & 0x1;
MMX = ( cpuInfo[3] >> 23 ) & 0x1;
SSE = ( cpuInfo[3] >> 25 ) & 0x1;
SSE2 = ( cpuInfo[3] >> 26 ) & 0x1;

// cpu brand string
__cpuid( cpuInfo, 0x80000002 );
*(int*) ( cpuBrandString + 0 ) = cpuInfo[0];
*(int*) ( cpuBrandString + 4 ) = cpuInfo[1];
*(int*) ( cpuBrandString + 8 ) = cpuInfo[2];
*(int*) ( cpuBrandString + 12 ) = cpuInfo[3];
__cpuid( cpuInfo, 0x80000003 );
*(int*) ( cpuBrandString + 16 ) = cpuInfo[0];
*(int*) ( cpuBrandString + 20 ) = cpuInfo[1];
*(int*) ( cpuBrandString + 24 ) = cpuInfo[2];
*(int*) ( cpuBrandString + 28 ) = cpuInfo[3];
__cpuid( cpuInfo, 0x80000004 );
*(int*) ( cpuBrandString + 32 ) = cpuInfo[0];
*(int*) ( cpuBrandString + 36 ) = cpuInfo[1];
*(int*) ( cpuBrandString + 40 ) = cpuInfo[2];
*(int*) ( cpuBrandString + 44 ) = cpuInfo[3];

for( int i = 0; i < 47; i++ ) // removing extra spaces in returned string
{
if( cpuBrandString[i] == ' ' && cpuBrandString[i+1] == ' ' )
{
for( int j = i; j < 47; j++ )
{
cpuBrandString[j] = cpuBrandString[j+1];
}

i--;
}
}


// get processor affinity mask for each physical core

DWORD bufferSize = 0;
SYSTEM_LOGICAL_PROCESSOR_INFORMATION *buffer;

GetLogicalProcessorInformation( NULL, &bufferSize ); // get buffer size required

buffer = new SYSTEM_LOGICAL_PROCESSOR_INFORMATION[bufferSize / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION)];

GetLogicalProcessorInformation( buffer, &bufferSize ); // get actual processor data

for( unsigned int i = 0; i < ( bufferSize / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) ); i++ ) // count total physical cores
{
if( buffer[i].Relationship == RelationProcessorCore ) // for each realtionship returned which relates to a processor core
{
physicalCores++;
}
}

affinityMask = (unsigned long*) new unsigned long[physicalCores];
physicalCores = 0;

for( unsigned int i = 0; i < ( bufferSize / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) ); i++ ) // set affinity bitmask for each core (1 bit set for non-hyperthreading, 2 bits for each hyperthreadings virtual core)
{
if( buffer[i].Relationship == RelationProcessorCore )
{
affinityMask[physicalCores] = (unsigned long) buffer[i].ProcessorMask;
physicalCores++;
}
}

hyperThreading = (affinityMask[0] % 2) != 0;
}
[/source]

I get two relevent variables:

phisicalCores (4 for a quad core etc)
affinityMask[physicalCores] (which contains 2 bits set for hyperthreading, 1 for non-hyperthreading)

It turned out that GetLogicalProcessorInformation was dead easy to use!

I need to create a series of worker threads, 1 per physical core. So I just create physicalCores threads, with an affinity mask set to affinityMask[n]. Dead simple!

Thanks for everyones help. Edited by mark ds

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this