Archive: Get # of cores AND logical processors


Get # of cores AND logical processors
  This is probably what I am looking for: http://msdn.microsoft.com/en-us/library/ms683194.aspx

This is actually way over my head, I don't understand a damn thing about using System plug-in even after reading the readme. I want to get the number of cores when hyperthreading is involved. It should say I have 2 cores/processors and not 4.

CPUDesc was last compiled in 2003, and it's not unicode.


(You can use the CallAnsiPlugin plug-in to execute ansi plugins on unicode NSIS.)


Well, it also counts hyperthreading as a cpu.. even Atom processors are hyperthreaded.


I took the challenge and came up with the following script.


OutFile "cpuinfo.exe"


>!include "LogicLib.nsh"

>!define FALSE 0
>!define TRUE 1

>!define ERROR_INSUFFICIENT_BUFFER 122

>; Size of SYSTEM_LOGICAL_PROCESSOR_INFORMATION on 32-bit systems
>!define SYS_LOG_PROC_INFO_SIZE 24
>; Offset of Relationship in the SYSTEM_LOGICAL_PROCESSOR_INFORMATION structure
>!define RELATIONSHIP_OFFSET 4
>; Enum value of Relationship identifying Processor Core
>!define RELATIONPROCESSORCORE 0

>; Count the number of bits set in given value
>; Parameters: value
>; Returns: number of bits set in given value
>Function countbits
Exch$0
Push$1
Push$2

; Set initial value for number of bits set in $0
StrCpy$1 0

${While} $0 > 0
; Clear least significant bit set
IntOp$2 $0 - 1
IntOp$0 $0 & $2
; Increment number of bits set
IntOp$1 $1 + 1
${EndWhile}

; Return number of bits set
StrCpy$0 $1

Pop$2
Pop$1
Exch$0
FunctionEnd

>; Evaluate processor information
>; Paramaters: buffer, length
>; Returns: number of cores
>Function evalcpuinfo
Exch$0 ; length
Exch
Exch$1 ; buffer
Push$2
Push$3
Push$4
Push$5 ; Processor Cores
Push$6 ; Logical Processors

; Set buffer offset at the end of the buffer
StrCpy$2 $0

; Initialize number of Processor Cores and Logical Processors
StrCpy$5 0
StrCpy$6 0

; Iterate through buffer starting from end
${While} $2 >= ${SYS_LOG_PROC_INFO_SIZE}
; Calculate start address of an element
IntOp$2 $2 - ${SYS_LOG_PROC_INFO_SIZE}
IntOp $3 $1 + $2
; Get ProcessorMask value from element
System
::Call "*$3(i.r4)"
Push $4
IntOp$3 $3 + ${RELATIONSHIP_OFFSET}
; Get Relationship value from element
System::Call "*$3(i.r4)"
${If} $4 == ${RELATIONPROCESSORCORE}
; Increment Processor cores
IntOp$5 $5 + 1
; Determine number of Logical Processor by counting the bits
; set in the value of ProcessorMask
Call countbits
Pop$4
; Sum up Logical Processors
IntOp$6 $6 + $4
${Else}
Pop $4
${EndIf}
${EndWhile}

;Set processor information as return value
StrCpy$0 "Processor Core(s): $5 Logical Processor(s): $6"

Pop $6
Pop$5
Pop$4
Pop$3
Pop$2
Pop$1
Exch$0
FunctionEnd

>; Get processor information
>; Returns: number of Processor Cores and Logical Processors
>Function getcpuinfo
Push$0
Push$1
Push$2
Push$3
Push$4

; GetLogicalProcessorInformation is only available on
; Windows XP SP3 or its successors.

;Initialize buffer and its length
StrCpy$1 0
StrCpy$2 0

; Determine required length of buffer
System::Call "kernel32::GetLogicalProcessorInformation(ir1, *ir2r2) i.r3 ? e"
Pop $4
${If} $3 == ${FALSE}
${If} $4 == ${ERROR_INSUFFICIENT_BUFFER}
; Allocate buffer
System::Alloc $2
Pop$1
${If} $1 != 0
; Get processor information
System::Call "kernel32::GetLogicalProcessorInformation(ir1, *ir2r2) i.r3 ? e"
Pop $4
${If} $3 != ${TRUE}
StrCpy $0 "Error: $4"
${Else}
Push $1 ; buffer
Push$2 ; length
Call evalcpuinfo
Pop$0
${EndIf}
; Deallocate buffer
System::Free $1
${Else}
StrCpy $0 "Error: memory allocation failed!"
${EndIf}
${Else}
StrCpy $0 "Error: $4"
${EndIf}
${Else}
StrCpy $0 "GetLogicalProcessorInformation is not available on your system!"
${EndIf}

Pop $4
Pop$3
Pop$2
Pop$1
Exch$0
FunctionEnd

>Function .onInit
InitPluginsDir
Call getcpuinfo
Pop$0
MessageBox MB_OK "$0"
Quit
FunctionEnd

Section
SectionEnd
>

Works for me, 64-bit Win 7, reports 2 cores/4 logical . Anyone else want to test it out?


I tried on my AMD Turion X2 laptop and it reported correctly, and had someone test his and it reported correctly on his Core i7.

You should wiki it since I am sure other people will find it of use.


"Processor core(s): 1 Logical Processor(s): 2" for my C2D E6750 on Windows Server 2003 SP2 (actual OS).
"GetLogicalProcessorInformation is not available on your system!" for same CPU on Windows 98 SE virtual machine.
"GetLogicalProcessorInformation is not available on your system!" for same CPU on Windows 2000 pro VM. (Is there an alternative here?)
"Processor core(s): 2 Logical Processor(s): 2" for same CPU on Windows Vista VM.
"Processor core(s): 2 Logical Processor(s): 2" for same CPU on Windows 7 pro x64 VM.
"Processor core(s): 2 Logical Processor(s): 2" for same CPU on Windows XP pro x64 VM.

VMs are run on VMWare Workstation. Obviously there are still some kinks that need to be solved, but the help on the SYSTEM_LOGICAL_PROCESSOR_INFORMATION struct is rather confusing... If I'm reading it correctly, Windows Server 2003 and Windows XP Professional x64 Edition should both return the same thing. So maybe it's VMWare that's simulating the two C2D cores as two physical CPUs?


Using unicode anyway, Win 2000 users in this particular application is a very very small minority, the market share of Win 2000 isn't even half a percent. The particular program being packaged does not support 9x/ME/NT.

Every system I tested had Win 7 64-bit.