Associate Logical Processors to Physical Processors

Submit New Article

Last Modified On :   April 10, 2008 1:23 PM PDT
Rate
 



Challenge

Determine which logical processor IDs are sharing the same physical processor. This information serves the purposes of load balancing and licensing strategy.

Given the nature of the shared physical resources in a Hyper-Threading Technology-enabled system, multiple threads vying for the same physical processor resources can potentially degrade or limit overall application performance.

Developers who license applications based on the number of processors must recognize that two logical processors sharing the same physical processor resources do not have the same processing potential as two physical processors. The state information necessary to support each logical processor is replicated while sharing the underlying physical processor resources.


Solution

Use the sample code given here to associate logical processors to physical processors.

The code given below is a small C program that prints out a table containing the operating system's processor affinity ID, APIC ID, the physical processor ID, and the logical processor ID within the physical processor. If there are two logical processor IDs sharing the same physical processor ID, then Hyper-Threading Technology is enabled.

This code must be preceded by code that determines whether Hyper-Threading Technology is supported in the processor, identifies the number of logical processors per physical processor, and retrieves the processor's APIC ID. Those issues are covered in the following separate items:

 

#include <windows.h
#include <stdio.h>
// Be sure to include routines that determine whether Hyper-Threading
// Technology is supported in the processor, identify the number of
// logical processors per physical processor, and retrieve the
// processor's APIC ID here.

void main (void) {
// Check to see if Hyper-Threading Technology is available
if (HTSupported()) {  
// Bit 28 set indicated Hyper-Threading Technology
unsigned char HT_Enabled = 0;
unsigned char Logical_Per_Package;
printf ("Hyper-Threading Technology is available.n");
Logical_Per_Package = LogicalProcessorsPerPackage();
printf ("Logical Processors Per Package: %dn",
Logical_Per_Package);

// Just because logical processors
// does not mean that Hyper-Threading Technology is enabled.
if (Logical_Per_Package > 1) {
HANDLE hCurrentProcessHandle;
DWORD dwProcessAffinity;
DWORD dwSystemAffinity;
DWORD dwAffinityMask;

// Physical processor ID and Logical processor IDs are derived
// from the APIC ID. We'll calculate the appropriate shift
// and mask values knowing the number of logical processors
// per physical processor package.
unsigned char i = 1;
unsigned char PHY_ID_MASK = 0xFF;
unsigned char PHY_ID_SHIFT = 0;

while (i < Logical_Per_Package){
i *= 2;
PHY_ID_MASK <<= 1;
PHY_ID_SHIFT++;
}

// The OS may limit the processors that
// this process may run on.
hCurrentProcessHandle = GetCurrentProcess();
GetProcessAffinityMask(hCurrentProcessHandle,
dwProcessAffinity,
dwSystemAffinity);
// If our available process affinity mask does not equal the
// available system affinity mask, then we may not be able to
// determine if Hyper-Threading Technology is enabled.
if (dwProcessAffinity != dwSystemAffinity)
printf ("This process can not utilize all processors.n");
dwAffinityMask = 1;
while (dwAffinityMask != 0
dwAffinityMask <=
dwProcessAffinity) {
// Check to make sure we can utilize this processor first.
if (dwAffinityMask
dwProcessAffinity){
if (SetProcessAffinityMask(hCurrentProcessHandle,
dwAffinityMask)) {
unsigned char APIC_ID;
unsigned char LOG_ID;
unsigned char PHY_ID;

Sleep(0); // We may not be running on the CPU
// that we just set the affinity to.
// Sleep gives the OS a chance to
// switch us to the desired CPU.

APIC_ID = GetAPIC_ID();
LOG_ID = APIC_ID
~PHY_ID_MASK;
PHY_ID = APIC_ID >> PHY_ID_SHIFT;

// Print out table of processor IDs
printf ("OS Affinity ID: 0x%.8x, APIC ID: %d PHY ID:
%d, LOG ID: %dn",
dwAffinityMask, APIC_ID, PHY_ID, LOG_ID);
if (LOG_ID != 0) HT_Enabled = 1;
}
else {
// This shouldn't happen since we check to make
// sure we can utilize this processor before
// trying to set affinity mask.
printf ("Set Affinity Mask Error Code: %dn",
GetLastError());
}
}
dwAffinityMask = dwAffinityMask << 1;
}
// Don't forget to reset the processor affinity if you use
// this code in an application.
SetProcessAffinityMask(hCurrentProcessHandle,
dwProcessAffinity);
if (HT_Enabled)
printf ("Processors with Hyper-Threading Technology enabled
was detected.n");
else
printf ("Processors with Hyper-Threading Technology enabled
was not detected.n");
}
else
printf ("Processors with Hyper-Threading Technology
is not enabled.n");
}
else {
printf ("Hyper-Threading Technology Processors are not
detected.n");
}
}