2009-09-14 4 views
4

Я запускаю свою службу NT на машине Win2k3 на базе Intel Core2, где мне нужно перебирать все логические процессоры (все биты в сродстве к процессу). Для этого я называю GetProcessAffinityMask(), чтобы получить маску системы сродства, а затем переключить процесс на каждый процессор, в своей очереди:Код для определения идентификатора APIC возвращает те же идентификаторы для разных логических процессоров

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; 
} 

На каждой итерации я призываю code from here для получения текущего процессора 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 идентификаторы еще могут быть одинаковыми для разных процессоров.

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

ответ

1

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

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

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

+0

Если бы это было так, не было ли это воспроизводимым на всех машинах? Я компилирую один раз и запускаю на нескольких машинах, и только пара из них демонстрирует это поведение, все остальные работают должным образом. – sharptooth

+0

Хммм, да, это было бы ... Лучше всего выкинуть WinDbg и расследовать дальше. Я также помню законные ошибки Intel об этом, что мы должны были работать в ОС, поэтому было бы возможно, что вы нашли его, если он на 100% воспроизводится на определенных машинах.Являются ли эти относительно новые процессоры? –

+0

'cpuid' не может использоваться в встроенной сборке, но существует [' __cpuid'] (http://msdn.microsoft.com/en-us/library/hskdteyh.aspx), который отлично работает с назначением регистра компилятора , –

0

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

+0

На самом деле, не является ли идентификатором процессора всегда 0 в этом коде? Он начинает 0, а затем процессорID << = 1 должен привести к 0, правильно? – boiler96

+0

Очень верно - я неправильно привел код. Фактически это начинается с 1. – sharptooth

+0

Тогда я подозреваю ваш код обнаружения APIC ID. Мы можем это увидеть? – boiler96

1

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

1

вы можете опубликовать DPC на deffent cpu и выполнить операцию в DPC producre.