latiose88 schrieb:
Gillt Diese settingungs Punkt auch bei l1 und l2 cache oder bezog sich das nur auf den l3 cache?
Ja klar. Wobei ich sagen muss, dass ich das Wort "Sättigungspunkt" nur zur Vereinfachung der Diskussion benutzt habe, normalerweise nutzt man es im Zusammenhang mit Caches nicht, und es ist auch streng genommen falsch. Caches haben eine Hit Rate, diese ist aber auch nicht absolut, sondern immer nur für einen bestimmten Workload gültig. Ein kurzes Stück Code, was nur wenige Daten anspricht, kann auch 100% Hitrate erreichen. Also nimmt man eine Testsuite (z.B. sowas wie SPECInt ) und misst die Hitrate der Suite oder einzelner Tests daraus.
In der Regel haben selbst die recht kleinen L1 Caches bei solchen Messungen Hitraten von weit über 90%. Warum macht man dann überhaupt einen L2 und gar L3 Cache? Der Grund ist einfach die "Miss-Penalty", also die Kosten für einen Cache Miss.
Eine kompletter Miss (also die angeforderte Adresse ist weder im L1 noch im L2 oder L3 enthalten) kann locker viele hundert Taktzyklen kosten, denn selbst das schnellste, übertaktete DDR5 DRAM ist ungeheuer langsam im Vergleich zur CPU.
latiose88 schrieb:
Und wie kann man die Ipc Steigerung erhöhen in dem man noch mehr Einheiten in die CPU steckt so das die CPU noch mehr Befehle abarbeiten kann und so oder auch nur durch den blosen Takt Erhöhung?
Das ist in der Tat die Herausforderung bei Superskalaren CPUs:
Aus Softwaresicht arbeitet eine CPU streng sequenziell, d.h. wenn Du sowas schreibst wie
Code:
LI a0, 5
LI a1, 10
ADD a3,a0,a1
(Das ist jetzt RISC-V Assemblercode, aber das sieht bei Intel oder ARM sinngemäß genauso aus) dann muss natürlich bei dem ADD Befehl a0 den Wert 5 und a1 den Wert 10 enthalten.
Eine Superskalare CPU kann die beiden LI Befehle parallel ausführen, aber mit dem ADD muss sie warten.
Das Beispiel ist jetzt super-praxisfremd, denn natürlich würde ein Compiler gleich
generieren, anstatt zwei konstante Werte zu addieren.
"Echter" Code holt üblicherweise Werte aus dem Arbeitsspeicher in CPU Register.
Die Prozessoren treiben nun einen ziemlich großen Aufwand, um die Befehle in voneinander unabhängige Sequenzen zu sortieren. Und diese unabhängigen Sequenzen kann man ggf. parallel ausführen.
Nehmen wir mal folgenden C-Code an:
C:
forI(i=0;i<100;i++) {
c[i]=a[i]+b[i]
}
und ignorieren mal das moderne CPUs sowas über ihre Vector Befehle (also Intel AVX) machen können:
Der erzeugte Maschinencode würde für den Schleifenrumpf Code erzeugen der a und b in jeweils ein Register lädt, diese dann addiert und dann das Ergebnis nach c schreibt. Also ähnlich wie der Code oben.
Die benutzten Register in den Maschinenbefehlen sind für jeden Schleifendurchlauf die Gleichen. Eine einfache CPU müsste daher jeden Schleifendurchlauf nacheinander abarbeiten.
In Wirklichkeit ist aber jeder Durchlauf für sich unabhängig. Denn z.B. c[0]=a[0]+b[0] ist komplett unabhängig von c[1]=a[1]+b[1], denn sie nutzen komplett unterschiedliche Daten.
Moderne "Out-of-Order" Prozessoren machen sich das zu nutze und nutzen einen Trick namens "Register Renaming": Jeder Schleifendurchlauf bekommt in der CPU drei eigene Register zugewiesen. Dadurch halt man man lauter unabhängige Sequenzen von Befehlen die man dann auf die parallelen Einheiten verteilen kann. Allerdings erhöht das den "Druck" auf z.B. die Caches, die z.B. mehrere parallele Anfragen zum Laden der Operanden (also die a und b gleichzeitig bekommen. Der L1 Cache von Zen3 kann zB. 3 Memory Ops per Cycle, davon maximal 3 loads und 2 Stores.
Moderne CPUs können daher mehrere hundert Befehle "in Flight" halten, die z.B. auf die Memory Operanden warten und dann ausgeführt werden, wenn die Daten verfügbar sind. Der Aufwand für diese gesamte Logik ist halt extrem.
Außerdem muss man dieses Potential auch "mit Arbeit" füttern. Hier kommt eben denn Hyperthreading ins Spiel, damit verdoppelt man quasi den Arbeitsvorrat, aus dem der Befehls-Scheduler sich bedienen kann.
Und man kann sich gut vorstellen, dass es wenn ein Prozessor schon sehr gut ist, es immer schwieriger wird, sich zu steigern. Das sieht man schön bei AMD: Von Zen1 bis Zen3 ging der Innovationszyklus relativ schnell, nun wird es langsamer. Bei Apple und Intel ist es ähnlich.