2017-03-17 4 views
1

Wenn ein CPU-Kern einen Schreibpuffer verwendet, kann der Ladevorgang den letzten Speicher an den referenzierten Speicherort aus dem Schreibpuffer umleiten, ohne zu warten, bis er im Cache angezeigt wird. Aber, wie es in A Primer on Memory Consistency and Coherence, wenn die CPU ehrt TSO-Speichermodell geschrieben, dannWarum kann ein Ladevorgang einen von einem anderen Thread auf demselben Core geschriebenen Wert nicht aus einem Schreibpuffer umgehen?

... Multithreading stellt einen subtilen Schreibpuffer Problem für TSO. TSO Schreibpuffer sind logisch privat für jeden Threadkontext (virtueller Kern). Daher sollte bei einem Multithread-Kern ein Threadkontext niemals aus dem Schreibpuffer eines anderen Threadkontexts umgehen. Diese logische Trennung kann mit pro-Thread-Kontext-Schreibpuffern implementiert werden, oder häufiger durch die Verwendung eines gemeinsamen Schreibpuffers mit Einträgen durch Thread-Kontext-IDs, die nur umgehen, wenn Tags übereinstimmen.

Ich kann die Notwendigkeit dieser Beschränkung nicht erfassen. Könnten Sie mir bitte ein Beispiel geben, wenn Sie zulassen, dass ein Thread einen Schreibpuffereintrag umschreibt, der von einem anderen Thread auf demselben Kern geschrieben wurde, der zur Verletzung des TSO-Speichermodells führt?

+0

Ich stimme, diese Frage als Off-Topic zu schließen, weil es um Computer-Prozessor-Design geht, nicht um Programmierung. –

+1

OP hat die Frage passend markiert, ich würde sagen, es ist eine gültige Frage, also schließe sie nicht. –

+0

Ich denke, es ist da, da Daten im Speicherpuffer nicht durch das Kohärenzprotokoll laufen, was es einem anderen Thread ermöglicht, Schreibvorgänge früh zu sehen, bevor sie global sichtbar gemacht werden, könnte eine Verletzung sein. Stellen Sie sich eine Situation mit vier Threads vor, bei der zwei Threads den gleichen Speicherort ändern und zwei andere versuchen, sie zu lesen. [Mein Wissen ist ein wenig rostig auf Schreibpuffer, ich ziehe mir die Haare, um zu verstehen, was mit den Schreibvorgängen im obigen Szenario passiert, vermutlich muss man noch einmal überarbeitet werden] –

Antwort

1

Das klassische Beispiel dafür, wie TSO unterscheidet sich von sequenziellen Konsistenz (SC) ist:

(Dieses Beispiel 2.4 ist hier - http://www.cs.cmu.edu/~410-f10/doc/Intel_Reordering_318147.pdf)

thread 0  |  thread 1 
--------------------------------- 
write 1-->[x] | write 1-->[y]  
a = read [x] | b = read [y]  
c = read [y] | d = read [x]  

Beide Adressen speichern 0 zunächst. Die Frage ist: wäre c = d = 0 ein gültiges Ergebnis? Wir wissen, dass a und b die Speicher vor ihnen weiterleiten müssen, da sie mit den Adressen der lokalen Speicher übereinstimmen und wahrscheinlich aus dem lokalen Thread-Speicherpuffer weitergeleitet werden. C und d werden jedoch möglicherweise nicht kontextübergreifend weitergeleitet, sodass sie möglicherweise weiterhin den alten Wert anzeigen.

Die interessante gotcha hier ist, dass, da jeder Thread beobachtet beide speichert, und leitet die lokale, und das Ergebnis von a = 1, c = 0 würde bedeuten, dass t0 sahen, dass die Speicherung zu [x] zuerst auftritt. Ein Ergebnis von b = 1, d = 0 würde bedeuten, dass t1 zuerst den Speicher für [y] sah. Die Tatsache, dass dies aufgrund der Speicherpufferweiterleitung möglich ist, würde die sequenzielle Konsistenz unterbrechen, da es erfordert, dass alle Kontexte in der gleichen globalen Reihenfolge der Speicher übereinstimmen. Stattdessen entschied sich x86 für ein schwächeres TSO-Modell, das diesen Fall zulässt.

Forwarding Stores global ist praktisch unmöglich, da gepufferte Geschäfte nicht unbedingt verpflichtet sind, was bedeutet, dass sie sogar auf dem falschen Weg einer Falschvorhersage sein können. Eine lokale Weiterleitung ist in Ordnung, da ein Flush auch alle Lasten, die von ihnen weitergeleitet werden, eliminiert, aber in mehreren Kontexten haben Sie das nicht. Ich habe auch Arbeit gesehen, die versucht, Geschäfte außerhalb des Kerns zu puffern, aber das ist wegen Latenz und Bandbreite nicht sehr praktisch. Für weitere Informationen, hier ist eine aktuelle Arbeit, die relevant sein kann - http://ieeexplore.ieee.org/abstract/document/7783736/

+0

Danke für die Erklärung. Ich dachte, dass ein Schreibpuffer, der ein Teil des Speichersystems ist, nur im Ruhestand befindliche Anweisungen enthält und alle spekulativen Speicher in einigen internen CPU-Puffern auf früheren Stufen gehandhabt werden. – undermind

+0

Wenn die Store-Load-Weiterleitung nur für im Ruhestand befindliche Speicher zulässig war, müsste jede mit einem früheren Speicher übereinstimmende Last angehalten werden. Es würde die Bestellung vereinfachen, aber die Leistung fürchterlich verschlechtern. Wenn Sie die Weiterleitung von spekulativen Speichern zulassen, spielt es keine Rolle, in welcher Struktur sie gespeichert sind. Logischerweise ist es nur ein weiterer Puffer für Speicher. Übrigens gibt es Designs, bei denen der Speicherpuffer sowohl spekulative als auch nicht-spekulative Speicher enthält, aber dann müssen die nicht-spekulativen auch sabotierbar sein. – Leeor

+0

Gute Antwort, aber es adressiert nicht wirklich das spezifische Problem, das OP zitiert, das, warum warum Lasten von einem Thread auf einem logischen Kern zu einem anderen Thread auf dem gleichen Kern umgeht (was auf Hardwareebene "natürlich" sein würde) isn Im TSO erlaubt. Sie haben darauf hingewiesen, dass die Umgehung von einem Kontext in einen anderen Probleme mit der spekulativen Ausführung hat, was wahr ist, aber vermutlich gelöst werden könnte (zB indem nur Speicher weitergeleitet werden, die nicht spekulativ sind, oder Ressourcen auf dem anderen Kern auf mis gespült werden) -Spekulation). – BeeOnRope

Verwandte Themen