4 Stimmen

Der Code zur Erkennung der APIC-ID liefert dieselben IDs für verschiedene logische Prozessoren

Ich lasse meinen NT-Dienst auf einem Intel Core2-basierten Win2k3-Rechner laufen, auf dem ich alle logischen CPUs (alle Bits in der Prozessaffinität) durchlaufen muss. Dazu rufe ich GetProcessAffinityMask() auf, um die Systemaffinitätsmaske abzurufen, und schalte dann den Prozess nacheinander auf jeden Prozessor um:

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

Bei jeder Iteration rufe ich Code von hier um die aktuelle APIC-ID des Prozessors abzurufen. Das Problem ist, dass für verschiedene Prozessoren manchmal identische APIC-IDs zurückgegeben werden. Nach der Dokumentation muss jeder Prozessor im System eine identische ID haben.

Ich habe versucht, dieses Problem zu beheben - ich habe überprüft, ob Windows tatsächlich die Affinität ändert:

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

Es wird genau die Affinitätsmaske zurückgegeben, die ich erwarte, aber die APIC-IDs können für verschiedene Prozessoren immer noch dieselben sein.

Gibt es eine Erklärung für diese merkwürdige Situation?

2voto

Eric Punkte 1647

Sie können den Windows-API-Aufruf nicht verwenden, um dies festzustellen.

Erstens wird die APCID auf Intel-CPUs (bei AMD oder anderen bin ich mir nicht sicher) zunächst in einem 8-Bit-Abschnitt des EBX-Registers (Bit 24 - 31), auch bekannt als EBX[31:24], kodiert, nachdem die CPUID mit EAX = 0x1 aufgerufen wurde.

Betrachten Sie den folgenden C/C++-Code mit Inline-Assembler:

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 listet einfach alle verfügbaren Kerne, Kerne innerhalb einer CPU und Hyper-Thread-fähige Kerne pro CPU auf und gibt die Summe dieser Kombinationen zurück. Es hat kein Konzept von physischer CPU vs. Cores innerhalb einer CPU vs. Hyper-Thread-fähigen Cores. Zumindest wird es nicht als solches gemeldet.

1voto

Ana Betts Punkte 72423

Das liegt daran, dass cpuid nicht in MSVC++ inline __asm Anweisungen verwendet werden kann, weil es die Register zerstört (d.h. der Compiler hat eine Variable in eax gespeichert, Sie haben cpuid aufgerufen, was das Register hinter dem Rücken des Compilers verändert hat). Der MSVC++-Compiler hat keine Entsprechung zu GCCs Klamottenliste also wird es nicht funktionieren.

Sie müssen eine alternative Methode verwenden, um die aktuell laufende CPU zu identifizieren, obwohl mir spontan keine gute Methode einfällt...

Editar: Und warum ist Ihnen die APIC-ID so wichtig? Wenn Sie nur denselben Code n-mal auf n Prozessoren sequentiell ausführen wollen, können Sie dann nicht einfach die Affinität einstellen, schlafen, die Affinität erhöhen, schlafen usw.?

1voto

xht Punkte 11

Sie können DPC an die entsprechende CPU senden und im DPC-Produkt arbeiten.

0voto

boiler96 Punkte 1157

In der ersten Iteration der Schleife scheint es, dass Sie die Affinitätsmaske auf 0 gesetzt haben. Die MSDN-Dokumente geben nicht eindeutig an, wie das Verhalten in diesem Fall sein sollte, aber ich würde wetten, dass der Thread in diesem Fall überall ausgeführt werden kann.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X