用于检测APIC ID的代码为不同的逻辑处理器返回相同的ID

我在基于Intel Core2的Win2k3机器上运行我的NT服务,在那里我需要迭代所有的逻辑CPU(所有的进程关联位)。 为此,我调用GetProcessAffinityMask()来检索系统关联掩码,然后依次将进程切换到每个处理器:

DWORD systemMask; GetProcessAffinityMask( ... &systemMask ); DWORD processorId = 1; while( systemMask != 0 ) { SetProcessAffinityMask(... processorId ); Sleep( 1 ); // to be sure that it shifts to that processor systemMask >>= 1; processorId <<= 1; } 

在每次迭代中,我从这里调用代码来检索当前的处理器APIC ID。 问题是,对于不同的处理器,它有时会返回相同的APIC ID。 根据文档,系统中的每个处理器必须具有相同的ID。

我试着debugging这个 – 检查Windows是否真的改变了亲和力

  while( systemMask != 0 ) { SetProcessAffinityMask(... processorId ); Sleep( 1 ); // to be sure that it shifts to that processor DWORD tempAffinity; GetProcessAffinityMask( ... &tempAffinity ); // run APIC id detection code here systemMask >>= 1; processorId <<= 1; } 

它完全返回我期望的亲和性掩码,但对于不同的处理器,APIC ID仍然可以相同。

有没有解释这个奇怪的情况?

这是因为cpuid不能在MSVC ++内联__asm语句中使用,因为它会破坏寄存器(即编译器在eax中存储了一些变量,您称为cpuid,这会改变编译器后面的寄存器)。 MSVC ++编译器没有等同于GCC的clobber列表 ,所以它不会工作。

你需要使用另一种方法来识别当前正在运行的CPU,虽然我的头顶,我想不出一个好的…

编辑:另外,你为什么关心APIC ID? 如果你所要做的只是在n个处理器上按顺序执行相同的代码n次,你不能只设置亲和性,睡眠,增加亲和性,睡眠等。

您不能使用Windows API调用来确定这一点。

首先,Intel CPU上的APCID(不确定AMD或其他)在EAX = 0x1的CPUID调用之后,最初在EBX寄存器(位24-31)(又名EBX [31:24])的8位部分进行编码。

考虑使用内联汇编的以下C / C ++代码:

 unsigned int cpu_eax; unsigned int cpu_ebx; unsigned int cpu_ecx; unsigned int cpu_edx; unsigned int apic_id; __asm { mov eax, 0x1 cpuid mov [cpu_eax], eax mov [cpu_ebx], ebx mov [cpu_ecx], ecx mov [cpu_edx], edx } apic_id = ( cpu_ebx & 0xFF000000) >> 24; 

GetProcessAffinityMask只是枚举所有可用的内核,一个CPU内核以及每个CPU具有超线程能力的内核,并返回这些组合的总和。 它没有物理CPU与CPU内核和超线程核心的概念。 至少它不这样报告。

您可以将DPC发布到defent cpu并在DPC producre中进行操作。

在循环的第一次迭代中,似乎将亲和度掩码设置为0. MSDN文档没有明确指定在这种情况下的行为,但是我敢打赌它会让线程在这种情况下的任何地方运行。