Zpět na domů

Hierarchie paměti CPU: zpoždění a optimalizace

Kapitola o hierarchii paměti vysvětluje, proč chyby cache dominují v výkonu. Popsány úrovně od registrů po DRAM, linky cache 64 B, lokalita přístupu, prefetcher a protokoly konzistence MESI/RVWMO. Příklady pro desktopy a vestavěné RISC-V systémy.

Zpoždění paměti: od 1 taktu L1 po 200 DRAM
Advertisement 728x90

# Hierarchie paměti v moderních procesorech: od registrů po DRAM

V moderních systémech cache missy vyžadují 100–200 taktů, zatímco hity trvají 1–4 takty. To určuje výkon kódu. Podívejme se na reálný případ: optimalizace ovladače síťového rozhraní na RISC-V s frekvencí 1 GHz. Očekávané zpracování paketů — 2 mil./s při 500 instrukcích na paket (500 ns). Ve skutečnosti dosaženo 200 tis./s.

Profilování odhalilo:

$ perf stat -e cycles,instructions,cache-misses ./driver_test
  Performance counter stats:
    5,000,000 cycles
      500,000 instructions
       45,000 cache-misses

500 tis. instrukcí vyžaduje 500 tis. taktů při IPC=1, ale spotřebováno 5 milionů. Rozdíl — 45 tis. missů × 100 taktů = 4,5 mil. taktů. Výpočty zabraly 10 %, čekání na paměť — 90 %.

Google AdInline article slot

Struktura hierarchie paměti

Paměť je organizována jako hierarchie s klesající rychlostí a rostoucím objemem:

| Úroveň | Typ | Zpoždění | Velikost |

|---------|-----|----------|--------|

Google AdInline article slot

| Registry | 32 registrů | 1 takt | ~128 B |

| Cache L1 | Instrukce/data | 3–4 takty | 32–64 KB |

| Cache L2 | Společný | 12–15 taktů | 256–512 KB |

Google AdInline article slot

| Cache L3 | Sdílený | 40–50 taktů | 2–32 MB |

| DRAM | Hlavní | 100–200 taktů | GB–TB |

Klíčové vlastnosti:

  • Rychlost klesá z 1 na 200 taktů.
  • Objem roste od 128 B po TB.
  • DRAM je 100–200× pomalejší než L1.

V mikrokontrolérech (RISC-V RV32IMC, 100 MHz) je hierarchie zjednodušená:

| Úroveň | Typ | Zpoždění | Velikost |

|---------|-----|----------|--------|

| Registry | 32 registrů | 1 takt | 128 B |

| I-cache L1 | Instrukce | 1 takt | 16 KB |

| D-cache L1/SRAM | Data | 1–2 takty | 8–32 KB |

| Flash | Kód | ~10 taktů | 128 KB–1 MB |

| DRAM | Data | 50–100 taktů | 8–64 MB |

Rozdíly: malé cache, absence L2/L3, flash místo DRAM, omezený objem.

Cache linky a přístup k datům

Cache fungují bloky po 64 bajtech. Přístup k 1 bajtu načte celou linku.

Příklad přístupu k int:

int x = array[0];  // 4 bajty na 0x1000
// Načte se 64 bajtů: 0x1000–0x103F (16 int)

Sekvenční přístup je efektivní:

for (int i = 0; i < 16; i++) {
    sum += array[i];  // 1 miss, 15 hitů
}

Náhodný — ne:

for (int i = 0; i < 16; i++) {
    sum += array[random_index[i]];  // Spousta missů
}

Organizace cache: sady a cesty

Cache je rozdělena na sady (set) a cesty (way). Přímé mapování:

Bity adresy: [Tag | Index | Offset]

Pro 32 KB, 64 B/linka: 512 linek, 9 bitů indexu, 6 bitů offsetu, 17 bitů tagu (32bitová adresa).

Konflikty: pole a[1024] (0x10000) a b[1024] (0x18000) mapují do stejných sad.

Sadu asociativní (N-cestný): sada obsahuje N linek, snižuje konflikty.

Typické parametry:

  • L1: 8-cestný, 32–64 KB.
  • L2: 8–16-cestný, 256–512 KB.
  • L3: 16-cestný, 2–32 MB.

V embedded: přímé nebo 2-cestné, vysoká pravděpodobnost konfliktů.

Lokalita přístupu

Prostorová: sousední adresy.

Dobře:

for (int i = 0; i < n; i++) sum += array[i];

Špatně:

for (int i = 0; i < n; i++) sum += array[random[i]];

Časová: opakovaný přístup.

Dobře:

int temp = array[0];
for (int i = 0; i < 1000; i++) result += temp * i;

Špatně:

for (int i = 0; i < 1000; i++) result += array[i % 10] * i;

Optimální kód (měření maticí):

for (int i = 0; i < N; i++) {
    for (int k = 0; k < N; k++) {
        int r = A[i][k];
        for (int j = 0; j < N; j++) {
            C[i][j] += r * B[k][j];
        }
    }
}

Prefetcher a jeho omezení

Prefetcher předem načítá data podle vzorů.

  • Sekvenční: pro for(i) sum += array[i];
  • Stride: pro sum += array[i*2];

Omezení:

  • Nefunguje na náhodných přístupech.
  • Omezeno na 10–20 linek.
  • Zklamává se střídáním polí.

V mikrokontrolérech — jednoduchý nebo chybí.

Propustnost a vícejádrovost

DDR4-3200: 25,6 GB/s/kanál, dvoukanálový — 51,2 GB/s. L1: ~1000 GB/s.

Embedded: SRAM 1–4 GB/s, DRAM 100–500 MB/s. Držte pracovní sadu v SRAM.

MESI protokol (x86/ARM):

  • M: Modified.
  • E: Exclusive.
  • S: Shared.
  • I: Invalid.

Falešné sdílení:

struct { int c0, c1; } shared;  // Ping-pong

Řešení:

struct { int c0; char pad[60]; int c1; } shared;

RISC-V: slabý model, použijte fence:

sw a0, 0(a1)
fence w, w
sw a2, 0(a3)

Atomární: lr.w/sc.w.

Co je důležité

  • Cache missy dominují: 90 % času na čekání.
  • Linky 64 B: sekvenční přístup dává 15 zdarma hitů.
  • Lokalita (prostorová/časová) — klíč k optimalizaci.
  • Embedded systémy: zjednodušená hierarchie, žádný prefetcher.
  • MESI a padding zabraňují ping-pongu v multi-core.

— Editorial Team

Advertisement 728x90

Číst dál