Код для определения идентификатора APIC возвращает одинаковые идентификаторы для разных логических процессоров - PullRequest
4 голосов
/ 14 сентября 2009

Я запускаю свою службу NT на компьютере с процессором Intel Core2 Win2k3, где мне нужно перебирать все логические процессоры (все биты в соответствии процессов). Для этого я вызываю 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 процессора. Проблема в том, что для разных процессоров он иногда возвращает идентичные идентификаторы APIC. Согласно документации каждый процессор в системе должен иметь идентичный идентификатор.

Я попытался отладить это - проверил, действительно ли 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 могут быть одинаковыми для разных процессоров.

Есть ли объяснение этой странной ситуации?

Ответы [ 4 ]

2 голосов
/ 04 февраля 2011

Вы не можете использовать вызов Windows API для определения этого.

Во-первых, APCID на процессорах Intel (не уверен в AMD или других) изначально кодируется в 8-битной секции регистра EBX (бит 24–31), то есть EBX [31:24] после вызова CPUID с EAX. = 0x1.

Рассмотрим следующий код 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 просто перечисляет все доступные ядра, ядра внутри ЦП и ядра с поддержкой многопоточности на ЦП и возвращает общее количество этих комбинаций. Он не имеет представления о физическом процессоре и ядрах в процессоре и ядрах с поддержкой гиперпотоков. По крайней мере, он не сообщает об этом как таковой.

1 голос
/ 12 декабря 2011

вы можете отправить DPC в защищенный процессор и выполнить операцию в DPC.

1 голос
/ 15 сентября 2009

Это потому, что cpuid нельзя использовать в встроенных операторах MSVC ++ __asm, потому что он перехватывает регистры (то есть компилятор хранит некоторую переменную в eax, вы назвали cpuid, который изменил регистр за спиной компилятора). Компилятор MSVC ++ не имеет эквивалента списку GCC , поэтому он не будет работать.

Вам нужно использовать альтернативный метод, чтобы идентифицировать работающий в данный момент процессор, хотя из головы не могу вспомнить хороший ...

Редактировать: Кроме того, почему вас волнует идентификатор APIC? Если все, что вам нужно сделать, это выполнить один и тот же код n раз на n процессорах последовательно, разве вы не можете просто установить сходство, режим сна, сходство приращения, режим сна и т. Д .?

0 голосов
/ 19 сентября 2009

В первой итерации цикла выясняется, что вы устанавливаете маску сходства на 0. В документах MSDN четко не указано, как должно быть поведение в этом случае, но я бы поспорил, что поток будет работать везде в этом случае.

...