Was kostet die atomare Operation (Vergleich und Austausch oder atomares Addieren / Dekrementieren)? Wie viel Zyklen verbraucht es? Wird es andere Prozessoren auf SMP oder NUMA anhalten oder Speicherzugriffe blockieren? Wird der Nachbestellungspuffer in einer außer Betrieb befindlichen CPU geleert?
Welche Auswirkungen werden auf den Cache haben?
Ich interessiere mich für moderne, beliebte CPUs: x86, x86_64, PowerPC, SPARC, Itanium.
Antworten:
Ich habe in den letzten Tagen nach tatsächlichen Daten gesucht und nichts gefunden. Ich habe jedoch einige Nachforschungen angestellt, bei denen die Kosten für Atomoperationen mit den Kosten für Cache-Fehlschläge verglichen werden.
Die Kosten für das x86-LOCK-Präfix (einschließlich
lock cmpxchg
für atomares CAS) vor PentiumPro (wie im Dokument beschrieben) sind ein Speicherzugriff (wie ein Cache-Fehler), + das Stoppen von Speicheroperationen durch andere Prozessoren, + jegliche Konflikte mit anderen Prozessoren versuchen, den Bus zu verriegeln. Seit PentiumPro wird jedoch für normalen zwischenspeicherbaren Writeback-Speicher (der gesamte Speicher, mit dem eine App arbeitet, sofern Sie nicht direkt mit der Hardware sprechen), anstatt alle Speicheroperationen zu blockieren, nur die relevante Cache-Zeile blockiert (basierend auf dem Link in der Antwort von @ osgx ). .dh der Kern verzögert die Beantwortung von MESI-Freigabe- und RFO-Anfragen für die Leitung bis nach dem Speicherteil des tatsächlichen
lock
Ed-Vorgangs. Dies wird als "Cache-Sperre" bezeichnet und betrifft nur diese eine Cache-Zeile. Andere Kerne können gleichzeitig andere Leitungen laden / speichern oder sogar CASEN.Tatsächlich kann der CAS-Fall, wie auf dieser Seite erläutert, komplizierter sein, ohne Zeitangaben, aber mit einer aufschlussreichen Beschreibung durch einen vertrauenswürdigen Ingenieur. (Zumindest für den normalen Anwendungsfall, in dem Sie vor dem eigentlichen CAS eine reine Last ausführen.)
Bevor wir zu sehr ins Detail gehen, möchte ich sagen, dass eine LOCKed-Operation einen Cache-Fehler + den möglichen Konflikt mit einem anderen Prozessor auf derselben Cacheline kostet, während CAS + die vorhergehende Last (die fast immer erforderlich ist, außer bei Mutexen, bei denen Sie immer sind CAS 0 und 1) können zwei Cache-Fehler kosten.
Er erklärt, dass ein Ladevorgang + CAS an einem einzelnen Speicherort tatsächlich zwei Cache-Fehler kosten kann, z. B. Load-Linked / Store-Conditional (siehe dort für letzteres). Seine Erklärung beruht auf der Kenntnis des MESI-Cache-Kohärenzprotokolls . Es werden 4 Zustände für eine Cacheline verwendet: M (odifiziert), E (xclusive), S (hared), I (nvalid) (und daher heißt es MESI), die nachfolgend bei Bedarf erläutert werden. Das erklärte Szenario ist das folgende:
In allen Fällen kann eine Cacheline-Anforderung von anderen Prozessoren blockiert werden, die die Daten bereits ändern.
quelle
Ich habe einige Profile mit dem folgenden Setup erstellt: Die Testmaschine (AMD Athlon64 x2 3800+) wurde gestartet, in den Langmodus geschaltet (Interrupts deaktiviert) und die interessierende Anweisung wurde in einer Schleife ausgeführt, 100 Iterationen wurden nicht gerollt und 1.000 Schleifenzyklen. Der Schleifenkörper wurde auf 16 Bytes ausgerichtet. Die Zeit wurde mit einem rdtsc-Befehl vor und nach der Schleife gemessen. Zusätzlich wurde eine Dummy-Schleife ohne Befehl ausgeführt (die 2 Zyklen pro Schleifeniteration und 14 Zyklen für den Rest maß) und das Ergebnis vom Ergebnis der Befehlsprofilierungszeit abgezogen.
Die folgenden Anweisungen wurden gemessen:
lock cmpxchg [rsp - 8], rdx
" (sowohl mit Vergleichsübereinstimmung als auch Nichtübereinstimmung),lock xadd [rsp - 8], rdx
",lock bts qword ptr [rsp - 8], 1
"In allen Fällen betrug die gemessene Zeit ungefähr 310 Zyklen, der Fehler betrug ungefähr +/- 8 Zyklen
Dies ist der Wert für die wiederholte Ausführung im selben (zwischengespeicherten) Speicher. Mit einem zusätzlichen Cache-Miss sind die Zeiten erheblich höher. Dies wurde auch mit nur einem der 2 aktiven Kerne durchgeführt, sodass der Cache ausschließlich im Besitz war und keine Cache-Synchronisation erforderlich war.
Um die Kosten eines gesperrten Befehls bei einem Cache-Fehler zu bewerten, habe ich
wbinvld
vor dem gesperrten Befehl einen Befehl hinzugefügt und daswbinvld
Pluszeichenadd [rsp - 8], rax
in die Vergleichsschleife eingefügt . In beiden Fällen betrugen die Kosten ca. 80.000 Zyklen pro Befehlspaar! Im Fall von Sperren betrug der Zeitunterschied etwa 180 Zyklen pro Befehl.Beachten Sie, dass dies der wechselseitige Durchsatz ist. Da es sich bei gesperrten Vorgängen jedoch um Serialisierungsvorgänge handelt, gibt es wahrscheinlich keinen Unterschied zur Latenz.
Fazit: Eine gesperrte Operation ist schwer, aber ein Cache-Fehler kann viel schwerer sein. Außerdem: Eine gesperrte Operation verursacht keine Cache-Fehler. Es kann nur dann Cache-Synchronisationsverkehr verursachen, wenn eine Cacheline nicht ausschließlich im Besitz ist.
Zum Booten des Computers habe ich eine x64-Version von FreeLdr aus dem ReactOS-Projekt verwendet. Hier ist der asm-Quellcode:
quelle
Bei busbasiertem SMP wird durch das atomare Präfix
LOCK
ein Busdraht-Signal aktiviert (eingeschaltet)LOCK#
. Es verbietet anderen CPUs / Geräten auf dem Bus die Verwendung.Ppro & P2 Buch http://books.google.com/books?id=3gDmyIYvFH4C&pg=PA245&dq=lock+instruction+pentium&lr=&ei=_E61S5ehLI78zQSzrqwI&cd=1#v=onepage&q=lock%20instruction%20pentium&f=false Seiten 244-246
quelle