2016-03-30 13 views
1

Ich habe ein kleines C++ - Programm, das mit MSVC v140 kompiliert wurde, zerlegt und versuche die Zyklen pro Anweisung zu schätzen, um besser zu verstehen, wie Code-Design die Leistung beeinflusst. Ich habe Mike Actons CppCon 2014 Talk auf "Data-Oriented Design and C++" verfolgt, speziell den Teil, den ich verlinkt habe.Schätzung der Zyklen pro Anweisung

Darin weist er diese Zeilen aus:

movss 8(%rbx), %xmm1 
movss 12(%rbx), %xmm0 

Er behauptet dann, dass diese 2 x 32-Bit liest sind wahrscheinlich auf der gleichen Cache-Zeile kostet damit in etwa ~ 200 Zyklen.

Die Intel 64 and IA-32 Architectures Optimization Reference Manual war eine große Ressource, insbesondere "Anhang C - Befehlswartezeit und Durchsatz". Allerdings auf Seite C-15 in "Tabelle C-16. Streaming SIMD Extension Gleitkomma-Anweisungen mit einfacher Genauigkeit" es besagt, dass Movss ist nur 1 Zyklus (es sei denn, ich verstehe, was Latenz bedeutet hier falsch ... Wenn ja, wie lese ich dieses Ding?)

Ich weiß, dass ein theoretical prediction of execution time nie richtig sein wird, aber dennoch ist dies wichtig zu lernen. Wie lauten diese beiden Befehle 200 Zyklen, und wie kann ich lernen, über die Ausführungszeit hinauszugehen, die über dieses Snippet hinausgeht?

Ich habe begonnen, einige Dinge über CPU-Pipelining zu lesen ... vielleicht wird die Mehrheit der Zyklen dort abgeholt?

PS: Ich bin nicht daran interessiert, Hardware Leistungsindikatoren hier zu messen. Ich suche nur, wie man vernünftige Sicht ASM und Zyklen liest.

+1

Haben Sie sich Agner Fogs Arbeit angesehen? http://www.agner.org/optimize/instruction_tables.pdf –

+2

Sie können keine Zyklen mehr zählen. nicht für eine lange Zeit jetzt. Pipelining, Caches, Branch Prädiktion, etc ... Pipelining ist nur ein Fließband wie in einer Fabrik. Sie können 117 Schritte oder Stationen haben, um eine Sache zu bauen, und jeder kann 30 Sekunden dauern, aber das bedeutet, dass Sie theoretisch alle 30 Sekunden einen Artikel produzieren können, nicht einen pro Stunde wegen der Produktionslinie. So schnell kommen sie aus dem Backend heraus. –

+0

Die meisten, wenn nicht alle Befehle eine Uhr zur Ausführung benötigen, können 15 bis 1000 Takte benötigen, um Cache-Misses zu relativ langsamem Dram zu holen, und alle anderen Schritte sin die Pipeline, aber sobald alle Eingaben an der Ausführungseinheit vorhanden sind, es braucht dann eine Uhr für diesen einen Schritt in der Pipeline. Dann all die Dinge, die folgt, speichern die Ergebnisse in Registern oder langsamen Speicher, etc. –

Antwort

2

Wie Sie bereits erwähnt haben, liegt der theoretische Durchsatz und die Latenz eines MOVSS-Befehls bei 1 Zyklus. Sie haben sich das richtige Dokument angeschaut (Intel Optimization Manual). Agner Fog (in den Kommentaren erwähnt) hat in seiner Intruction Tables für Intel-CPUs dieselben Zahlen gemessen (AMD hat eine höhere Latenz).

Dies führt uns zum ersten Problem: Welche spezifische Mikroarchitektur untersuchen Sie? Dies kann selbst für den gleichen Anbieter einen großen Unterschied machen. Agner Fog berichtet, dass MOVSS je nach Quelle und Ziel eine 2-6cy Latenz auf dem AMD Bulldozer hat (Register vs. Speicher). Dies ist wichtig, wenn man die Leistung von Computerarchitekturen betrachtet.

Die 200cy sind höchstwahrscheinlich Cache-Misses, wie bereits in den Kommentaren erwähnt wird. Die Zahlen, die Sie aus dem Optimierungshandbuch für Speicherzugriffsanweisungen erhalten, gehen alle davon aus, dass sich die Daten im Cache der ersten Ebene (L1) befinden. Nun, wenn Sie die Daten nie durch vorherige Anweisungen berührt haben, muss die Cache-Zeile (64 Bytes mit Intel und AMD x86) aus dem Speicher in den Cache der letzten Ebene geladen werden, dort in den Cache der zweiten Ebene, dann in L1 und schließlich in das XMM-Register (innerhalb von 1 Zyklus). Übertragungen zwischen L3-L2 und L2-L1 haben einen Durchsatz (keine Latenz!) Von zwei Zyklen pro Cache-Zeile auf aktuellen Intel-Mikroarchitekturen. Und die Speicherbandbreite kann verwendet werden, um den Durchsatz zwischen L3 und Speicher zu schätzen (z. B. hat eine 2 GHz-CPU mit einer erreichbaren Speicherbandbreite von 40 GB/s einen Durchsatz von 3,2 Zyklen pro Cachezeile). Cache-Zeilen oder Speicherblöcke sind typischerweise die kleinsten Einheits-Caches, und Speicher kann arbeiten, sie unterscheiden sich zwischen Mikroarchitekturen und können sogar innerhalb der Architektur unterschiedlich sein, abhängig von dem Cache-Level (L1, L2 usw.).

Jetzt ist das alles Durchsatz und nicht Latenz, die Ihnen nicht helfen wird abzuschätzen, was Sie oben beschrieben haben. Um dies zu überprüfen, müssten Sie die Anweisungen immer wieder ausführen (für mindestens 1/10s), um zyklusgenaue Messungen zu erhalten. Indem Sie die Anweisungen ändern, können Sie entscheiden, ob Sie Latenzen messen möchten (indem Sie Abhängigkeiten zwischen Anweisungen einfügen) oder den Durchsatz (indem Sie die Anweisungen unabhängig vom Ergebnis früherer Anweisungen eingeben). Um Caches und Speicherzugriffe zu messen, müssten Sie vorhersagen, ob ein Zugriff auf einen Cache erfolgt oder nicht, dies kann unter Verwendung von layer conditions erfolgen.

Ein Tool zur Schätzung der Befehlsausführung (sowohl Latenz als auch Durchsatz) für Intel-CPUs ist die Intel Architecture Code Analyzer, die mehrere Mikroarchitekturen bis hin zu Haswell unterstützt. Die Latenzvorhersagen sind mit der Körnung des Salzes zu treffen, da es viel schwieriger ist, die Latenz als der Durchsatz zu schätzen.

+0

IACA muss im Allgemeinen mit einem Körnchen Salz eingenommen werden. Es geht von keinen Cache-Fehlern aus und hat einige Einschränkungen, wie es Dinge modelliert. IDK, warum Sie sagen, dass es schwieriger ist, die Latenz als der Durchsatz zu schätzen. Fast alle Befehle haben eine feste Latenzzeit, da dies die Arbeit des Out-of-Order-Schedulers erheblich erleichtert (im Hinblick auf die Vermeidung von Write-Back-Konflikten, bei denen ein Ausführungsport versucht, zwei Ergebnisse im selben Zyklus zu erzeugen). Wie auch immer, da IACA keine Cache-Misses simuliert, ist das einzige Problem für die Latenz Ressourcenkonflikte, die ein Ausführen von "insn" verhindern, sobald die Eingaben fertig sind. –

+0

Ihr Recht. Die Latenz innerhalb des Kerns, wenn alle Daten als in L1 verfügbar angenommen werden, ist nicht schwieriger zu schätzen als der Durchsatz. Aber sobald es auf Lasten von anderen Cache-Ebenen oder Speicher ankommt, ist es sehr schwer vorauszusagen, viel weiter weg als der Durchsatz. Dies beruht auf dem Konzept der Latenz, dass eine einzige Verzögerung die Gesamtlatenz erhöht, während eine einzelne Verzögerung den Durchsatz nur bei der Gesamtzahl der Befehle reduziert. Also ja, IACA Vorhersagen müssen immer mit einem Körnchen Salz genommen werden, aber die Art des Durchsatzes macht es milder für Fehler. – como

+0

Sie sagen also, dass IACA-Latenzzahlen mit geringerer Wahrscheinlichkeit der Realität entsprechen als ihre Durchsatzzahlen. Das macht Sinn, solange Sie nicht viele L3-Fehler haben. Die Hauptspeicherlatenz reicht aus, um die Pipeline zu blockieren und den Durchsatz ebenfalls zu beeinflussen, aber * wenn * Speicherlatenz nicht Teil des kritischen Pfads ist, haben möglicherweise auch L2-Fehler in L3 keinen großen Einfluss auf den Durchsatz. –

Verwandte Themen