Personally for recent Intel cpus (not x86 in general, just Intel) I use the EAX=0Bh
cpuid
leaf. See Wikipedia for some details on what info you get about the cores in the current socket aka package. On a multi-socket system, this might be half or a quarter of the system-wide number of physical / logical cores. Intel has a whitepaper on enumerating CPUs with details on what to check in case of multi-socket systems. This code doesn't do that, it just checks one sub-leaf (ECX=1).
int main()
{
unsigned int eax=11,ebx=0,ecx=1,edx=0;
asm volatile("cpuid"
: "=a" (eax),
"=b" (ebx),
"=c" (ecx),
"=d" (edx)
: "0" (eax), "2" (ecx)
: );
printf("Cores: %d\nThreads: %d\nActual thread: %d\n",eax,ebx,edx);
}
Output:
Cores: 4
Threads: 8
Actual thread: 1
Or, more concisely:
#include <stdio.h>
int main()
{
unsigned int ncores=0,nthreads=0,ht=0;
asm volatile("cpuid": "=a" (ncores), "=b" (nthreads) : "a" (0xb), "c" (0x1) : );
ht=(ncores!=nthreads);
printf("Cores: %d\nThreads: %d\nHyperThreading: %s\n",ncores,nthreads,ht?"Yes":"No");
return 0;
}
Output:
Cores: 4
Threads: 8
HyperThreading: Yes