σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft AcademyRoadmapsSkills
Ctrl K
AO
+1,2 Tsd. Lernende
AnmeldenBeitreten ↗
RoadmapsSkills
AO
+1,2 Tsd. Lernende
Anmelden
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft AcademyRoadmapsSkills
Ctrl K
AO
+1,2 Tsd. Lernende
AnmeldenBeitreten ↗
RoadmapsSkills
AO
+1,2 Tsd. Lernende
Anmelden
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Cache locality-Skill›Modul 1 · Caches von Grund auf›Thema 1.3·~55 Min.Mittelstufe

Assoziativität und Konfliktfehler

Position in der SkillModul 1 von 3 · Thema 3 von 4
1.3 Assoziativität und Konfliktfehler
—Lab-Punkte— / 100XP gesamt—Serie—

5 Min. Lesezeit4 Codebeispiele

  1. 01Die Schwäche eines einzigen Platzes
  2. 02Sätze und Wege
  3. 03Wer verdrängt wird: LRU
  4. 04Zeilen im Abstand einer Zweierpotenz
  5. 05Was Sie bauen werden

In einem Cache mit einem Platz pro Zeile werfen zwei stark genutzte Zeilen, die sich einen Platz teilen, sich immer wieder gegenseitig hinaus. Geben Sie jedem Platz mehrere Wege, und das Problem verschwindet größtenteils, außer die Zeilen Ihrer Tabelle liegen genau 4096 Byte auseinander. Diese Lektion baut einen satzassoziativen Cache und zeigt, wie eine Zeilengröße als Zweierpotenz dazu führen kann, dass 100 % der Lesezugriffe verfehlen.

01

Die Schwäche eines einzigen Platzes

Im direkt abgebildeten Cache des letzten Themas hat jede Speicherzeile genau einen Platz. Nutzt Ihr Programm immer wieder zwei Zeilen, die auf denselben Platz fallen, etwa Zeile 0 und Zeile 8 in einem Cache mit 8 Plätzen, verdrängt jeder Zugriff auf die eine die andere, obwohl die anderen sieben Plätze leer sein können. An der Cache-Größe liegt es nicht: Die Zeilen streiten um einen zu kleinen Platz. Ein solcher Fehlzugriff heißt Konfliktfehler.

02

Sätze und Wege

Die Lösung ist, Plätze zu gruppieren. Plätze werden zu Sätzen zusammengefasst, und jeder Platz in einem Satz ist ein Weg. Eine Speicherzeile gehört zu einem Satz, gefunden über denselben Rest wie zuvor, darf aber in jedem Weg dieses Satzes liegen. Zwei kollidierende Zeilen teilen sich jetzt einen Satz mit Platz für beide. Die Zahl der Sätze folgt aus den Größen:

sets = cache size ÷ (line size × ways)(1)ein 32-KB-Cache mit 64-Byte-Zeilen und 8 Wegen hat 32768 ÷ (64 × 8) = 64 Sätze

Eine Adresse zerfällt jetzt in drei Teile. Der Offset ist das Byte in der Zeile. Der Satzindex sagt, zu welchem Satz die Zeile gehört. Das Tag ist der Rest der Zeilennummer, und der Cache vergleicht es, um zu sehen, ob ein Weg diese Zeile hält. Die Funktion unten teilt eine Adresse für einen Cache mit 64-Byte-Zeilen und 64 Sätzen.

main.pyPython
def split_address(address, line_bytes, n_sets):    line = address // line_bytes    return line // n_sets, line % n_sets, address % line_bytes1print(split_address(74565, 64, 64))
(18, 13, 5)
  1. 1Tag, Satzindex und Offset: Jedes ist eine ganzzahlige Division oder ein Rest der Adresse.

Adresse 74565 ist Byte 5 von Zeile 1165. Zeile 1165 kommt in Satz 13 (1165 modulo 64), und 18 ist, was von der Zeilennummer übrig bleibt, das Tag. Jede Zeile mit Satz 13 konkurriert um die acht Wege dieses Satzes, gleich welches Tag sie hat.

03

Wer verdrängt wird: LRU

Ist ein Satz voll und kommt eine neue Zeile, muss eine Zeile gehen. Die übliche Regel ist LRU: Die am längsten nicht benutzte Zeile wird verdrängt. Wir können jeden Satz als Python-Liste halten, geordnet von der am längsten bis zur zuletzt benutzten.

  1. 1
    Satz bestimmenDie Zeilennummer modulo die Anzahl der Sätze.
  2. 2
    In jedem Weg nachsehenBei einem Treffer die Zeile ans Ende der zuletzt benutzten verschieben.
  3. 3
    Bei Fehlzugriff hinzufügenDie neue Zeile ans Ende der zuletzt benutzten setzen.
  4. 4
    Die älteste verwerfenHält der Satz mehr Zeilen als Wege, die erste entfernen.

Hier ist der ganze Cache. Der Lauf unten liest zwei Zeilen, die Adressen 0 und 256, die in einem 256-Byte-Cache mit 64-Byte-Zeilen kollidieren, erst mit einem Weg und dann mit zwei.

main.pyPython
class SetAssocCache:    def __init__(self, size_bytes, line_bytes, ways):        self.line_bytes = line_bytes        self.ways = ways        self.n_sets = size_bytes // (line_bytes * ways)        self.sets = [[] for _ in range(self.n_sets)]        self.hits = 0        self.misses = 0    def access(self, address):        line = address // self.line_bytes        lines = self.sets[line % self.n_sets]        if line in lines:            lines.remove(line)            lines.append(line)1            self.hits += 1            return True        self.misses += 1        lines.append(line)        if len(lines) > self.ways:            lines.pop(0)2        return Falsefor ways in (1, 2):    cache = SetAssocCache(size_bytes=4 * 64, line_bytes=64, ways=ways)    flags = [cache.access(a) for a in [0, 256, 0, 256, 0, 256]]    print(ways, "way:", flags)
1 way: [False, False, False, False, False, False]
2 way: [False, False, True, True, True, True]
  1. 1Eine treffende Zeile ans Ende zu schieben hält die Liste geordnet: Der erste Eintrag ist immer der am längsten nicht benutzte.
  2. 2Der volle Satz verliert seinen ersten Eintrag, die am längsten nicht benutzte Zeile.

Mit einem Weg verdrängen sich die beiden Zeilen und alle sechs Zugriffe verfehlen. Mit zwei Wegen passen beide Zeilen in ihren Satz: Nach den ersten beiden Kaltstart-Fehlzugriffen trifft jeder Zugriff. Ein zusätzlicher Weg hat alle Konfliktfehler dieses Musters beseitigt.

Warum nicht möglichst viele Wege?

Jeder Weg fügt jedem Lesezugriff einen Tag-Vergleich hinzu, was Zeit und Energie kostet. Level-1-Caches haben oft 8 Wege und größere 12 bis 16, denn darüber hinaus beseitigt jeder weitere Weg nur noch sehr wenige Fehlzugriffe.

04

Zeilen im Abstand einer Zweierpotenz

Jetzt die Falle. Eine Tabelle mit 512 float64-Spalten hat Zeilen von genau 4096 Byte. Eine Spalte zu lesen heißt, die Adressen 0, 4096, 8192 und so weiter zu lesen. In unserem Cache ist der Satzindex die Zeilennummer modulo 64, und 4096 Byte sind genau 64 Zeilen, also hat jede dieser Adressen denselben Satzindex. Der Code gibt den Satz der ersten sechs Zeilen für eine Zeilengröße von 4096 Byte und von 4160 Byte aus, also 4096 plus eine zusätzliche Cache-Zeile.

main.pyPython
n_sets = 64for row_bytes in (4096, 4160):    sets = [(i * row_bytes // 64) % n_sets for i in range(6)]    print(row_bytes, "->", sets)
4096 -> [0, 0, 0, 0, 0, 0]
4160 -> [0, 1, 2, 3, 4, 5]

Bei 4096-Byte-Zeilen streiten alle Schlusskurse einer Spalte um Satz 0. Bei 4160-Byte-Zeilen laufen sie durch die Sätze 0, 1, 2, 3 und so weiter und nutzen den ganzen Cache. Der nächste Code liest 96 Schlusskurse zweimal und misst die Fehlzugriffsrate für 1, 2, 4 und 8 Wege.

main.pyPython
def column_trace(n_rows, row_bytes, passes):    return [i * row_bytes for i in range(n_rows)] * passesdef miss_rates_by_ways(trace, size_bytes, line_bytes, ways_list):    rates = {}    for ways in ways_list:        cache = SetAssocCache(size_bytes, line_bytes, ways)        for address in trace:            cache.access(address)        rates[ways] = cache.misses / len(trace)    return ratesfor row_bytes in (4096, 4160):    print(row_bytes, miss_rates_by_ways(column_trace(96, row_bytes, 2), 32768, 64, [1, 2, 4, 8]))
4096 {1: 1.0, 2: 1.0, 4: 1.0, 8: 1.0}
4160 {1: 0.5, 2: 0.5, 4: 0.5, 8: 0.5}

Die aufgefüllte Tabelle verfehlt nur im ersten Durchlauf: 0,5 aller Lesezugriffe, gleich wie viele Wege. Die ausgerichtete Tabelle verfehlt bei jedem Zugriff, selbst mit 8 Wegen, denn 96 Zeilen brauchen 96 Plätze und der Satz hat 8. Schlimmer noch: LRU verdrängt in einem zyklischen Muster immer die Zeile, die Sie als Nächstes lesen, der zweite Durchlauf findet also nichts. Mehr Wege würden erst helfen, wenn sie die Zahl der Zeilen erreichen.

Zweierpotenzen sind die schlechtesten Zeilengrößen

Eine Zeilengröße, die ein Vielfaches der Satzspanne ist (hier 64 Zeilen, 4096 Byte), legt eine ganze Spalte in einen Satz. Matrizen und Tabellen mit 256, 512 oder 1024 float64-Spalten sind die klassischen Opfer. Jede Zeile um eine Cache-Zeile aufzufüllen, wie bei 4160, kostet 1,6 % Speicher und beseitigt das Problem.

Was die echten Daten sagendie ersten 96 SPY-Schlusskurse, zweimal gelesen
Fehlzugriffsrate, Zeilen 4096 Byte auseinander100%8 Wege, 64 Sätze: jeder Zugriff verfehlt
Fehlzugriffsrate, Zeilen 4160 Byte auseinander50%nur der erste Durchlauf verfehlt
Fehlzugriffsrate der 4096-Byte-Tabelle nach Zahl der Wege, in %
1 Weg100
2 Wege100
4 Wege100
8 Wege100
05

Was Sie bauen werden

Das Labor folgt der Lektion: die Adressaufteilung, der LRU-Cache, die zwei Arten von Spuren, der Vergleich nach Zahl der Wege und die Studie an der echten SPY-Tabelle.

  • Funktion · FrageBaut auf
  • split_address(address, line_bytes, n_sets)Welches Tag, welchen Satz und welchen Offset hat eine Adresse?Die ganzzahlige Division
  • SetAssocCache(size_bytes, line_bytes, ways).access(address)Ist dieser Lesezugriff ein Treffer in einem LRU-Cache mit mehreren Wegen?Sätze von Zeilen in LRU-Reihenfolge
  • conflict_trace(n_lines, line_bytes, n_sets, rounds)Welche Adressen kollidieren alle in einem Satz?Einfache Arithmetik
  • column_trace(n_rows, row_bytes, passes)Welche Adressen berührt das Lesen einer Spalte?Einfache Arithmetik
  • miss_rates_by_ways(trace, size_bytes, line_bytes, ways_list)Wie ändern mehr Wege die Fehlzugriffsrate?SetAssocCache
  • study(bars)Was kosten Zeilen im Abstand von 4096 Byte?column_tracemiss_rates_by_ways

Das Wichtigste

  • Wege beseitigen Konflikte. Ein Satz mit mehreren Wegen lässt kollidierende Zeilen zusammenleben; LRU entscheidet, wer geht, wenn der Satz voll ist.
  • Die Adresse wählt den Satz. Tag, Satzindex und Offset kommen direkt aus der Adresse, das Layout Ihrer Daten entscheidet also, welche Zeilen kollidieren.
  • Meiden Sie Zweierpotenz-Zeilen. Zeilengrößen, die Vielfache der Satzspanne sind, legen eine ganze Spalte in einen Satz; eine Zeile Padding behebt das.
Schnelltest
Ein 32-KB-Cache mit 64-Byte-Zeilen und 8 Wegen. Wie viele Sätze hat er?
Wähle eine Antwort.

Nächstes Thema: Der Cache hält jetzt die richtigen Zeilen, wenn sie nicht kollidieren, aber wie lange bleiben Zeilen nützlich? In Zeitliche Lokalität und Arbeitsmengen messen Sie, wie bald ein Wert wieder gelesen wird, und finden die Cache-Größe, ab der ein Programm hineinpasst.

Lab: Was bewertet wird

6 Aufgaben · 100 Pkt.
  • Tag, Satz und Offset10 Pkt.
  • Ein satzassoziativer LRU-Cache30 Pkt.
  • Kollidierende Zeilen10 Pkt.
  • Eine Spalte lesen10 Pkt.
  • Die Fehlzugriffsrate nach Zahl der Wege15 Pkt.
  • Die Studie mit der SPY-Tabelle25 Pkt.
Explorer · lab-cl-3
▾ lab-cl-3
▾ data
…
bash · im Browser
learner@quantcraft:~/lab-cl-3$
Python noch nicht geladenPythonLn 1, Col 1Spaces: 4UTF-8

Dieses Thema zurücksetzen?

Alles in lab-cl-3 wird auf die Startdateien zurückgesetzt und das Terminal geleert. Ihre aktuelle Lösung geht verloren – das lässt sich nicht rückgängig machen.

Wird zurückgesetzt
  • main.py → Startcode
  • Terminal-Verlauf und Testausgabe
  • Nicht eingereichte Änderungen
Bleibt erhalten
  • Beste Lab-Punktzahl
  • Ihre XP und Ihre Serie
  • Vorlesungsfortschritt und Notizen