Ryzen hat keine 16MB L3-Cache ;-)

Flodul

Commander
Mitglied seit
14.12.2016
Beiträge
164
Renomée
1
Ich habe mal einen kleinen Speicherlatenz-Benchmark geschrieben. Hier ist der Source:
https://pastebin.com/bnHQkUx5
Der Benchmark nutzt das übliche Pointer-Chasing um die Parallelisierung der Speicherzugriffe beim Benchmarken durch die Out-of-Order Excecution zu vermeiden. D.h. er folgt einer einfach verketteten Liste von Pointern innerhalb eines Speicherblocks kreuz und quer durch das RAM. Die Blockgrößen bei dem Benchmark wachsen in Zweier-Potenzen von 4kB bis 256MB. Dabei werden Blöcke die größer sind als durch den L1-DTLB abgedeckt werden kann in Sub-Blöcken aufgeteilt die so groß sind wie der DTLB erfassen kann; das dient dazu, dass beim Benchmarken so wenig wie möglich der Effekt des Nachladens der TLBs gemessen wird. Der Benchmark wird für jede Blockgröße mehrfach ausgeführt und das schnellste Ergebnis genommen. Damit wird die Messung genommen wo am wenigsten andere Threads, Interrupts oder DPC auf dem Kern dazwischengefunkt haben. Desweiteren habe ich den Mess-Thread auf den ersten logischen Thread der CPU gepinnt sowie den Prozess und den Thread auf eine erhöhte Priorität gesetzt; das soll auch ein mögliches Dazwischenfunken anderer Threads verhindern.

Der Benchmark ergibt zwei interessante Dinge auf meinem Ryzen 1800X:
1. Die Latenz springt nicht erst von einer Blockgröße von 8MB auf 16MB nach oben, sondern schon bei einer Blockgröße von 4MB auf 8MB. Das legt nahe, dass es in einem CCX zwei Cluster geben muss in die der Cache aufgeteilt ist.
2. Und das ist das interessante: angeblich sollten die physischen Cachezeilen ja über die CCXe interleaved sein, d.h. gerade und ungerade Cachezeilen liegen auf dem einen oder anderen CCX; so zumindest war es z.B. bei Anandtech zu lesen. Das hätte aber den Effekt, dass die L3-Cache-Zugriffe im Durchschnitt den Mittelwert der Latenzen des entfernten und des nahen L3-Teils in den jeweiligen CCXen hätten.
Interessanterweise ist das nicht so. Die Latenz bei einer Blockgröße von 16MB springt auf das Niveau des Hauptspeichers an. D.h. wenn den Pointern durch den Block gefolgt wird fliegt bei der zweiten Hälfte der Iteration der zuvor aus dem Hauptspeicher geladene Block aus dem Cache und die zweite Hälfte wird aus dem Hauptspeicher geladen. Und bei der nächsten Iteration wird die erste wieder geladen.
D.h. der Ryzen hat keinen einheitlichen 16MB L3-Cache der in der Lage ist ein Working-Set von 16MB abzudecken, sondern zwei unabhängige L3-Caches von 8MB; das kann man ganz sicher sagen. Das ist auch technisch die bessere Lösung, denn das Interleaving würde mehr auf die Performance gehen als die Einschränkung auf ein Working-Set von 8MB.
Nur die die Crossbar mit dem hochtrabenden Namen InfinityFabric muss wohl nach dem was man so liest nicht so der Bringer sein. Nach Benchmarks die ich selbst noch nicht nachvollzogen habe soll die nicht schneller sein als der Hauptspeicher, was eine schwache Leistung für eine ansonsten ganz gute CPU ist.

Hier die Ergebnisse des Benchmarks auf meinem 1800X:
4kB 3.9375
8kB 3.9375
16kB 3.79688
32kB 3.86719
64kB 16.5586
128kB 16.5586
256kB 15.0205
512kB 15.6401
1MB 24.8687
2MB 24.8027
4MB 24.7785
8MB 49.2426 (hier die erste Sonderbarkeit, ansich sollte die Latenz im selben CCX konstant bleiben)
16MB 166.989 (hier die zweite, die Latenz geht hoch auf das Niveau des RAMs)
32MB 166.498
64MB 172.739
128MB 175.495
256MB 170.465
Ich habe RDTSC genutzt um die Taktzyklen zu zählen. Das ist nicht ganz genau weil der Ryzen XFR kennt und der Timestamp-Counter immer nur mit den nominalen Takt arbeitet, also bei mir 3,6GHz. Aber das ist nur ein kleiner Shift der vernachlässigbar ist.
 
Zuletzt bearbeitet:
Das ist doch nix Neues und wird doch selbst auf Folien gezeigt das es 2x8MB L3 sind bei den 8 Kernern......
 
Ja, wo steht das, dass das zwei völlig unabhängige L3-Caches sind? D.h. dass der eine Cache in einem CCX nicht für den anderen CCX mitcacht.
Hier z.B.

cpu-z2.png
 
Wer suchet der findet........da müsst ich auch noch mal nach sehen.
ABER deine Ergebnisse hast schon mal irgend wo nieder geschrieben,möglich das es in dem gesuchten Thread war.;)
 
Wenn ich unter Linux /proc/cpuinfo ausgeben lass, dann bekomm auch auch 16MB L3-Cache angegeben.
Und wenn ich CPUID Leave 0x80000006 mache, dann bekomme ich auch 16MB L3-Cache angeben.
So einfach ist das wohl doch nicht.

[EDIT]: Und die Angabe in CPU-Z legt ja nicht das nahe was ich so interessant finde: dass der eine L3-Cache in einem CCX nicht für die Kerne im anderen CCX cachen kann. So wie man immer von den 16MB L3-Cache liest könnte man ja glatt davon ausgehen.
 
Zuletzt bearbeitet:
Aber trotzdem informativ. Bin ja mal gespannt, ob AMD den Infinity-Fabric in Zen2 signifikant verbessert, z.B. Taktleitung am z.B. L3 statt am RAM
 
Und genau,8Kerner und 6 Kernen haben deshalb auch 16MB L3 , 4Kerner nur 8 weil "Eine" komplette Einheit abgeschaltet wird oder nicht vorhanden ist.
 
...4Kerner nur 8 weil "Eine" komplette Einheit abgeschaltet wird oder nicht vorhanden ist.
Hat AMD nicht gesagt, dass die Vierkerner immer eine 2+2 Konfiguration hätten; damit wären 4+0 (oder 3+1) vom Tisch.
 
Einmal ist klar, dass der L3 Cache in zwei Bereiche geteilt ist, zum anderen ist schon länger bekannt, dass der Cache manchmal merkwürdig arbeitet. Zum Teil hat es was damit zu tun, dass der L3 Cache ein Victim Cache des L2 ist. Wobei ich da nicht verstehe, dass es sich nicht eher so verhält als hätte man L3+L2 Cache, sondern eher als hätte man L3-L2 Cache. Ich denke da fehlen noch irgendwelche Dokumentationen von AMD.
 
Einmal ist klar, dass der L3 Cache in zwei Bereiche geteilt ist, ...

Das hab ich ja garnicht infragegestellt, dass das schon bekannt war.
Vielmehr habe ich herausgefunden, dass die L3-Caches völlig unabhängig voneinander arbeiten und dass der L3-Cache eines CCX nicht den des anderen CCX insofern ergänzt als Working-Sets von 16MB möglich wären.

... zum anderen ist schon länger bekannt, dass der Cache manchmal merkwürdig arbeitet.

Er arbeitet kein Stück merkwürdig, sondern anders als man erwartet wenn man liest, dass die Caches einander ergänzen; bei Anandtech war gar zu lesen, dass die Cachezeilen des einen und des anderen CCX interleaved wären. Das ist nicht so und wäre auch nachteilig weil dann die Latenzen im Mittelwert beider Caches lägen.

Zum Teil hat es was damit zu tun, dass der L3 Cache ein Victim Cache des L2 ist.

Das ist von meiner Feststellung völlig unabhängig.

Wobei ich da nicht verstehe, dass es sich nicht eher so verhält als hätte man L3+L2 Cache, sondern eher als hätte man L3-L2 Cache.

Nein, das erstere ist der Fall. Die Kapazitäten vom L3- und L2-Cache ergänzen sich.

Außerdem fand ich so nebenbei auch interessant, dass sich die Latenzen von einem Working-Set von 4MB zu einem von 8MB verdoppeln obwohl beides durch den L3-Cache eines CCX abgedeckt werden sollte.
 
Zuletzt bearbeitet:
Allerdings finde ich es schon irgendwie vorteilhaft, wenn sich 4 Kerne nur 8MB teilen anstatt 8 Kerne ganze 16MB Ist zwar bei Single-threaded doof, aber kann bestimmt Vorteile bei Multi-threaded bieten.
 
Allerdings finde ich es schon irgendwie vorteilhaft, wenn sich 4 Kerne nur 8MB teilen anstatt 8 Kerne ganze 16MB Ist zwar bei Single-threaded doof, aber kann bestimmt Vorteile bei Multi-threaded bieten.

Logisch, aber die IF-Crossbar zwischen den CCXen könnte wirklich besser sein.
 
Zuletzt bearbeitet:
Nein, das erstere ist der Fall. Die Kapazitäten vom L3- und L2-Cache ergänzen sich.

Das schlägt sich aber nicht in den Ergebnissen wieder, welche bereits ab ~6 MB deutlich abkacken und nicht erst ab 8.5 MB.
 
Das schlägt sich aber nicht in den Ergebnissen wieder, welche bereits ab ~6 MB deutlich abkacken und nicht erst ab 8.5 MB.

Woher hast Du das?
Die Benchmarks die ich kenne messen Durchsatz und Latenz in Zweier-Potenzen. Einer der Zwischenschritte misst wäre selten.
Dass beides abfällt könnte übrigens damit zu tun haben, dass wie ich gemessen habe die Latenz von einem Working-Set von 4MB auf eins von 8MB schon auf die Hälfte abfällt. Das schließt aber nicht aus, dass sich L2- und L3-Cache ergänzen. Ich hab auch noch eine eigene AVX-optimierte Variante des STREAM-Triad-Benchmarks geschrieben, wo der Durchsatz von 4MB- auf 8MB-Blockgröße von 80GB/s auf 30GB/s abfällt. Das passt auch dazu.
 
Zuletzt bearbeitet:
Woher hast Du das?
Die Benchmarks die ich kenne messen Durchsatz und Latenz in Zweier-Potenzen. Einer der Zwischenschritte misst wäre selten.
Dass beides abfällt könnte übrigens damit zu tun haben, dass wie ich gemessen habe die Latenz von einem Working-Set von 4MB auf eins von 8MB schon auf die Hälfte abfällt. Das schließt aber nicht aus, dass sich L2- und L3-Cache ergänzen. Ich hab auch noch eine eigene AVX-optimierte Variante des STREAM-Triad-Benchmarks geschrieben, wo der Durchsatz von 4MB- auf 8MB-Blockgröße von 80GB/s auf 30GB/s abfällt. Das passt auch dazu.

Siehe zum Beispiel diesen Test. Vielleicht hat sich das mit dem letzten Microcode Update geändert, aber ich würde eher mal mit z.B. 1 MB Abständen testen, also vor allem 4, 5, 6, 7, 8, 9, 10 fände ich interessant.

Edit: Bild:

ghLQINb.png
 
Vielleicht hat sich das mit dem letzten Microcode Update geändert, aber ich würde eher mal mit z.B. 1 MB Abständen testen, also vor allem 4, 5, 6, 7, 8, 9, 10 fände ich interessant.

Ne, da der Sprung aber schon vor dem Erreichen der L3-Größe eines CCX erreicht wird sagt das nichts darüber aus wie das zwischen 8MB und 8,5MB weitergeht.
Auf jeden Fall weist obige Grafik darauf hin was ich bereits sagte: der L3-Cache in einem CCX muss zweigeteilt sein und beim Überschreiten des Working-Sets von 4MB fällt die Performance ab.

Aber ist ja nen geiler Test den Du da anführst. das bemerkenswerte finde ich folgends:
dj4s45m73w5a4a72p.png

Da sieht man, dass es wenig bringt wenn Threads auf die CCXe geteilt laufen, aber manchmal wie bei Battlefield 1 sehr viel, wenn die auf einem CCX laufen. Irre.
 
Zuletzt bearbeitet:
Ein Pferd läuft nicht auf vier Beinen, sondern auf vier Pfo(s)ten!
Ein Ryzen hat keine 16MByte, sonder nur 8Mbyte, also die Hälfte dessen was unter unified Cache verstanden wird...
Naja, die KI wird es schon lösen, sind ja nur einfache hin und her Bewegungen, just like the rabbit! 8)
 
Ich habe mal einen kleinen Speicherlatenz-Benchmark geschrieben. Hier ist der Source:
https://pastebin.com/bnHQkUx5
[...]
Erstmal Glückwunsch zu deinem Elan und Danke für die Ergebnisse. Es ist sehr interessant und vielleicht ein Hinweis auf das hier- und da nicht so tolle Abschneiden der ersten Zen-Iterarion.
Ich fände es aber auch gut, nicht nur 1,2,4,8 MByte zu nutzen, sondern auch Zwischenwerte. Warum: Ryzen ist in meinen Augen eine Art altes Multisockel-System "on-a-chip". Du hast zwei Kernkomplexe, die irgendwie miteinander kommunizieren müssen und insbesondere die Cache-Kohärenz aufrecht erhalten müssen. Damit dabei der "Verwaltungsaufwand" nicht explodiert, gab es bei den Sockel F-Opterons (dunkle K10-Zeit) Filter, die sich jedoch einen Teil des L3-Caches reserviert haben. Anstatt 6 MB L3-Cache hatte man dann nur noch 5 MB zur Verfügung. Das ist jetzt eine pure Spekulation, aber es könnte sowas auch bei Ryzen geben, so dass wir eigentlich (7+1)+(7+1) MB L3-Cache haben. Mit 8 MB oder 16 MB bist du dann natürlich immer gerade in der nächst höheren Cache-/Speicherebene.
Um diese gewagte Spekulation das zu überprüfen, wäre es ganz gut, wenn man auch Zwischenwerte hätte.
Nebenbei fehlt auch noch eine Vergleichsmessung an einem i7-Sonstwas von Intel, man kann ja auch bei solchen Sachen Programmierfehler bzw. Compilerfehler nicht ausschließen.
Ich besitze derlei Hardware nicht mehr, aber wenn du noch die Entwicklungsumgebung und die Architektur (x86/amd64) Preis gibst, kann das hier vielleicht jemand für dich überprüfen. (Oder du stellst eine Binary bereit.)

Allerdings finde ich es schon irgendwie vorteilhaft, wenn sich 4 Kerne nur 8MB teilen anstatt 8 Kerne ganze 16MB Ist zwar bei Single-threaded doof, aber kann bestimmt Vorteile bei Multi-threaded bieten.
Sorry, dass ist Blödsinn. Sobald du "richtige" Software schreibst, bei dem die 8 Kerne / 16 Threads gemeinsam an einem Problem ackern, brauchst du diesen riesen L3-Cache. Sonst könnte ich auch ein NUMA-System nehmen. Nur irgendwie muss Intel seine Mondpreise ja rechtfertigen. *g*
Wenn ich jetzt nur Boinc im Sinn habe, ist deine Aussage aber sicher zutreffend. ;)
 
Ich fände es aber auch gut, nicht nur 1,2,4,8 MByte zu nutzen, sondern auch Zwischenwerte.

Das wäre größtenteils unsinnig bei Set-assoziativen Caches mit einer Set Größe die eine Zweierpotenz ist.
Lediglich der Zwischenschritt von 8,5MB wäre interessant.

Warum: Ryzen ist in meinen Augen eine Art altes Multisockel-System "on-a-chip". Du hast zwei Kernkomplexe, die irgendwie miteinander kommunizieren müssen und insbesondere die Cache-Kohärenz aufrecht erhalten müssen.

Nein, das wäre unsinnig, denn die Caches ergänzen sich wie gesagt nicht.

Ich besitze derlei Hardware nicht mehr, aber wenn du noch die Entwicklungsumgebung und die Architektur (x86/amd64) Preis gibst, kann das hier vielleicht jemand für dich überprüfen. (Oder du stellst eine Binary bereit.)

MSVC++ 2017, AMD64. Is aber egal welcher Compiler und welche Architektur; die Testschleife macht in jedem Fall das selbe und bzgl. des generierten Codes der Testschleife dürfte es keinen Unterschied geben.
 
Außerdem fand ich so nebenbei auch interessant, dass sich die Latenzen von einem Working-Set von 4MB zu einem von 8MB verdoppeln obwohl beides
durch den L3-Cache eines CCX abgedeckt werden sollte.

Möglicherweise hast Du da nur die TLB-Größe gemessen, da gibts generell immer weniger Einträge als für die komplette Cachegröße nötig wären. War damals beim Bulldozer ein größeres Thema, der hatte nur TLBs für magere 128 kb und das bei ebenfalls 2 MB L2. War damals ebenfalls mickrig. Piledriver hat das dann verdoppelt, so dass immerhin 256 kB gesichert waren, siehe:

http://www.planet3dnow.de/photoplog/images/54308/1_RMMA-D-Cache.png

aus:


http://www.planet3dnow.de/vbulletin/threads/408737-AMD-FX-Vishera

4 von 8 MB wären somit eigentlich ganz ordentlich, immerhin nutzbare 50%, ggü. 25% beim BDv2.

Frage ist aber natürlich, was Dein Algo genau macht, am einfachsten wird sein, wenn Du ihn auf nem BD-System laufen lassen könntest und dort die Ausgabe studierst. Wenn Du dort nur 128/256 kB messen kannst, wäre es das selbe.
 
Danke für die Ergebnisse.

Guck mal auf Seite 14 der Mike Clark Präsentation auf der HotChips 28 (Kann leider noch keinen Link auf das PDF setzen):

A CPU complex (CCX) is four cores connected to an L3 Cache.

The L3 Cache is 16-way associative, 8MB, mostly exclusive of L2.

The L3 Cache is made of 4 slices, by low-order address interleave.

Every core can access every cache with same average latency.

Es könnte also sein, dass dein Benchmark-Code gerade nicht das average trifft wenn du jenseits der 4MB Workingset arbeitest.


Noch was anderes, dass auch eine große Rolle spielt: Beide CCX tauschen per InfinityFabric Cache-Kohärenz-Informationen aus. Nun ist der Fabric-Clock = MemClk.
Wenn man also langsames RAM verwendet steigt damit die Latenz der Fabric... Indirekt sinkt dadurch auch der CC Durchsatz. Von da her am besten immer nur zwei "schnelle" Single Rank DIMMS verwenden. Bei Dual-Rank oder 4-fach Bestückung schaltet der MemoryController runter.

Wenn von euch jemand Details zur InfinityFabric hat immer gerne her damit! Bisher kenn ich nur das Blockschaltbild auf wikichip.
Da sieht man eh nur die Verbindungen die eigentlich klar sind. Interessant wäre vor allem wie die Protokollseite aussieht.
Verwendet AMD da was HT basiertes, oder gehts doch in Richtung Directory?
Was für Features hat das Control-Protokoll (QoS, Priorities, Time-Slots,...)?
 
Möglicherweise hast Du da nur die TLB-Größe gemessen, da gibts generell immer weniger Einträge als für die komplette Cachegröße nötig wären.

Hab ich doch in meinem Eingangsposting beschrieben wie ich das umgangen hab: ich hab die verkettete Liste kreuz und quer durch einen Block geführt der von dem L1-DTLB abgedeckt werden kann ehe ich zum nächsten Block gesprungen bin. Damit sollten die Kosten für das Nachladen der L1-DTLBs nahezu Null sein.

War damals beim Bulldozer ein größeres Thema, der hatte nur TLBs für magere 128 kb und das bei ebenfalls 2 MB L2. War damals ebenfalls mickrig. Piledriver hat das dann verdoppelt, so dass immerhin 256 kB gesichert waren, siehe:

Das ist garnicht so kritisch. Ryzen hat pro Kern auch nur 64 voll-assoziative L1-DTLB-Einträge. Und die werden noch von zwei Threads geteilt.

--- Update ---

Es könnte also sein, dass dein Benchmark-Code gerade nicht das average trifft wenn du jenseits der 4MB Workingset arbeitest.

Es gibt nicht *das* Average da das je nach Algorithmus unterschiedlich ist.

Noch was anderes, dass auch eine große Rolle spielt: Beide CCX tauschen per InfinityFabric Cache-Kohärenz-Informationen aus. Nun ist der Fabric-Clock = MemClk.
Wenn man also langsames RAM verwendet steigt damit die Latenz der Fabric... Indirekt sinkt dadurch auch der CC Durchsatz. Von da her am besten immer nur zwei "schnelle" Single Rank DIMMS verwenden. Bei Dual-Rank oder 4-fach Bestückung schaltet der MemoryController runter.

Kannste drehen und wenden wie Du willst; die Performance der IF ist Schrott.
 
Zuletzt bearbeitet:
@Flodul
Wie schaut den die "logical Processor to Cache Map" aus bei Coreinfo.exe (Microsoft)?

bsp.
Code:
Logical Processor to NUMA Node Map:
****  NUMA Node 0

No NUMA nodes.

Logical Processor to Cache Map:
*---  Data Cache          0, Level 1,   32 KB, Assoc   8, LineSize  64
*---  Instruction Cache   0, Level 1,   32 KB, Assoc   2, LineSize  64
*---  Unified Cache       0, Level 2,    2 MB, Assoc  16, LineSize  64
-*--  Data Cache          1, Level 1,   32 KB, Assoc   8, LineSize  64
-*--  Instruction Cache   1, Level 1,   32 KB, Assoc   2, LineSize  64
-*--  Unified Cache       1, Level 2,    2 MB, Assoc  16, LineSize  64
--*-  Data Cache          2, Level 1,   32 KB, Assoc   8, LineSize  64
--*-  Instruction Cache   2, Level 1,   32 KB, Assoc   2, LineSize  64
--*-  Unified Cache       2, Level 2,    2 MB, Assoc  16, LineSize  64
---*  Data Cache          3, Level 1,   32 KB, Assoc   8, LineSize  64
---*  Instruction Cache   3, Level 1,   32 KB, Assoc   2, LineSize  64
---*  Unified Cache       3, Level 2,    2 MB, Assoc  16, LineSize  64

Nichts desto trotz ist der L3 eines CCX in zwei "slice a 4MB" aufgeteilt.
Was passiert wenn du mehrere Instansen laufen lässt z.B. auf Core 0,2,4,6,8 ?
 
Zurück
Oben Unten