Ein September-2026-Systems-Paper beginnt mit einem Ergebnis, das so manche CXL-Marketingdeck beschwichtigen sollte: Steckt man ein unmodifiziertes, generisches CXL-SSD in einen LLM-Prefix-Caching-Stack, ist es rund 3× langsamer als lokales DRAM und nicht schneller als eine normale NVMe-SSD — und der sequenzielle Standard-Prefetcher, den man zur Reparatur greifen würde, lässt die mittlere Time-to-First-Token (TTFT) nahezu unverändert, während er irrelevante NAND-Reads durchführt1. Das Paper — Bridging LLM Serving and CXL-SSDs with Chunk-Aware KV Cache Management (Chung, Noh, Kim und Kollegen, Sogang University mit Samsung Electronics und ETRI, arXiv:2609.26828, cs.AR, eingereicht am 20. September 2026) — verdient dann seine konstruktive Hälfte: LM-CXD, ein auf LLM-Prefix-Caching spezialisiertes CXL-SSD, das die semantische Lücke zwischen der Serving-Engine (die weiß, welche KV-Chunks als nächstes konsumiert werden) und dem Gerät (das deren Platzierung und Bewegung kontrolliert) schließt — mittlere TTFT um bis zu 2,6× über dem Standard-CXL-SSD mit compute-asynchronem Prefetching gesenkt, um 4,03× mit lageweisem Prefetching, im Schnitt innerhalb von 1,5× zu lokalem DRAM1.
Das Negative-Ergebnis ist der tragende Teil, denn es trennt sauber zwei Behauptungen, die CXL-Marketing gern verschmilzt. Behauptung eins: Der Block-I/O-Pfad ist für KV-Retrieval teuer, unabhängig vom darunterliegenden Medium — CPU-Cache-Konkurrenz, Host-DRAM-Staging-Kopien, Syscall-Bookkeeping. Behauptung zwei: CXLs byte-adressierbares, memory-semantisches Interface entfernt diese Kosten. Das Paper belegt Behauptung eins mit einem schönen Experiment (eine Ramdisk, die DRAM hinter dem Block-Interface hält, bleibt 1,8× langsamer als direktes DRAM — mit keinem einzigen NAND im System) und widerlegt dann die naive Lesart von Behauptung zwei: Den Block-Pfad zu entfernen macht ein CXL-SSD für diese Workload nicht schneller als eine NVMe-SSD, weil die verbleibenden Kosten — NAND-Latenz und geräteseitiges Thrash in einer begrenzten DRAM-Region — von Adressierbarkeit überhaupt nicht adressiert werden1.
Dieser Guide geht den ganzen Stack in Arithmetik durch: die Interface-Kosten-Dekomposition, die Silizium-Realität von CXL- gegen PCIe-Bandbreite, warum Chunk-Granularitäten und NAND-Granularitäten kollidieren, warum jeder Prefetcher ohne Engine-Wissen spekulieren und verlieren muss, und die lageweise Pipelining-Schranke, die entscheidet, ob sich NAND-Latenz wirklich unter Rechenzeit verstecken lässt. Jede aus dem Paper zitierte Zahl wurde gegen den vollständigen HTML-Text verifiziert, nicht gegen das Abstract2.
1. Das Problem: Prefix-Caching ist aus dem DRAM herausgewachsen, und der Block-Pfad ist der Grund, warum SSDs wehtun
Moderner LLM-Traffic — RAG-Kontexte, Multi-Turn-Chat, agentische Loops — sendet Präfixe von zig- bis hunderttausenden Tokens wieder und wieder. Prefix-Caching nutzt die für diese Präfixe berechneten KV-Caches wieder, um redundantes Prefill zu überspringen, und Systeme wie LMCache erweitern den Cache über den GPU-Speicher hinaus in Host-DRAM und Storage3. Aber Host-DRAM ist teuer und durch Speicherkanäle und DIMM-Kapazität begrenzt, also landet die kalte Ebene in Produktionstacks auf NAND-basierten NVMe-SSDs. NAND exponiert diese Kapazität nur über das Block-Interface, und die Charakterisierung der Paper-Autoren einer Prefix-Reuse-Workload (Qwen3-4B auf vLLM mit LMCache, 128k-Präfix, 32-Token-Chunks, vier Storage-Konfigurationen) führt die verschlechterte TTFT auf genau drei Kosten zurück1:
- CPU-Cache-Konkurrenz. Block-I/O läuft auf Host-Threads, die sich den Last-Level-Cache (LLC) mit den Inferenz-Threads teilen — für völlig andere Zwecke. Isoliert man die L3-Partition der I/O-Threads mit Intel Cache Allocation Technology (CAT), werden bis zu 44% der P99-TTFT zurückgewonnen — ein großer, schwanzlastiger Preis für etwas so Banales wie Syscalls im Page-Cache4.
- Host-DRAM-Staging. Das Block-Interface zwingt jeden Chunk durch das Host-DRAM, bevor die GPU ihn lesen kann, denn die GPU kann nur aus gepinnten, in den Adressraum gemappten Seiten DMAen. Mit VTune gemessen: Auf einer Ramdisk steigen Schreibzugriffe von 6% auf 33% des DRAM-Traffics, das DRAM ist pro Retrieval 3,6× so lange beschäftigt. Eine Pinned-DRAM-Baseline mit 1,34 s mittlerer TTFT fällt auf 5,27 s auf ext4-über-brd, und ext4 zu entfernen gewinnt nur 0,2 s der 3,9-s-Lücke zurück — die Staging-Kopie ist der dateisystemunabhängige Teil1.
- Die NAND-Latenz selbst. NAND durch DRAM zu ersetzen (die Ramdisk) schließt im Steady-State 61% der TTFT-Lücke der SSD zu direktem DRAM — gut die Hälfte der SSD-Verlangsamung ist also das Medium, der Rest das Interface.
Die ersten zwei Kosten sind Eigenschaften des Interfaces, nicht des Mediums. Das ist der erste dauerhafte Befund des Papers: Eine Ramdisk — pures DRAM, über den Block-Pfad serviert — bleibt 1,8× langsamer als direktes DRAM. Und die naheliegenden Fluchtwege scheitern aus strukturellen Gründen. Host-seitiges Prefetching überlappt NAND-Latenz, reint aber die DRAM-Kapazitätsspannung: Man nutzt SSDs, weil Host-DRAM begrenzt ist, doch vorgeladene Chunks müssen vor dem Konsum wieder Host-DRAM belegen. GPUDirect Storage (GDS) umgeht CPU und Host-DRAM, kann aber die Block-Orientierung des Pfads nicht entfernen: cuFileRead legt jeden Chunk in einem VRAM-Staging-Puffer ab, aus dem load_and_reshape-Kernel ihn in vLLMs paged-KV-Layout umformatieren und kopieren — zwei GPU-seitige Kopien pro Chunk, die mit Modellgewichten und heißem KV um VRAM konkurrieren, während die NAND-Latenz auf dem kritischen Pfad der Anfrage bleibt5.
2. Warum byte-adressierbar nicht schneller bedeutet: das Silizium darunter
CXL ist ein cache-kohärenter Interconnect, aufgebaut auf PCIe-Infrastruktur. Ein CXL-Type-3-Gerät exponiert Host-managed Device Memory (HDM) über das CXL.mem-Protokoll, gemappt in den physischen Adressraum des Hosts, angesprochen mit ordinary Load/Store-Instruktionen6. Ein CXL-SSD bolt das auf eine SSD-Architektur: Controller, On-Device-DRAM (die DRAM-Region, die Hits mit Speicherlatenz serviert) und NAND-Flash hinter einem Flash-Translation-Layer1.
Hier ist die Arithmetik, die das Marketing überspringt. Ein PCIe-5.0-x16-Link trägt grob 64 GB/s roh pro Richtung; nach 128b/130b-Kodierung, Paket-Overhead und der Tatsache, dass ein CXL.mem-Read ein Round Trip ist (Request plus Daten plus dHDM-Kohärenz-Maschinerie), landet die effektive sustained Bandbreite für Memory-Semantic-Loads von einem Type-3-Gerät deutlich darunter — typischerweise in der Klasse von 30–50 GB/s pro Link, meist geteilt mit anderem Traffic am selben Root Complex. Ein aggregiertes Host-DRAM-System auf einem modernen Dual-Socket-Server liefert ein Vielfaches davon über seine Kanäle. Die Decke CXL-angehängten Speichers ist also nicht DRAM-Tempo; sie ist PCIe-Tempo — dieselbe Mauer, vor der NVMe sitzt. Und unter der DRAM-Region zahlt ein CXL-SSD-Miss einen CXL.io/FTL-Round-Trip plus NAND-tR — in der Größenordnung von Zehn-Mikrosekunden für konventionelles TLC und niedrigen einstelligen Mikrosekunden für das Z-NAND, das das Paper modelliert7.
Deshalb ist „byte-adressierbar" eine Programmiermodell-Eigenschaft, keine Performance-Eigenschaft:
- Der DMA-Tribut ist derselbe Link. Ob der Quellpuffer der GPU gepinntes Host-DRAM oder ein per cudaHostRegister gemapptes CXL-Gebiet ist — der Host-zu-GPU-Transfer durchquert dieselbe PCIe-Hierarchie. Adressierbarkeit entfernt die Staging-Kopie, nicht den Transfer.
- Cache-Line-Traffic überquert trotzdem den Link. Ein zufälliger Cache-Line-Pull aus dem Geräte-DRAM kostet ein volles CXL.mem-Transaktionspaar (Request-Line, Return-Line, mit Kohärenzzustand). Burstige KV-Fills mit 2-MiB-Hugepage-Granularität amortisieren das gut; ein mis-getriebener, pointer-chasender Retrieval-Tun es nicht.
- Konkurrenz verschwindet nicht, sie verlagert sich. Mit dem Block-Pfad verschwinden die I/O-Threads — aber unter Last konkurriert jeder CXL-SSD-Read weiter um den geteilten Link, die Bandbreite der Geräte-DRAM-Region und die NAND-Kanäle des FTL.
Die nächste Zelle kostet den ganzen Retrieval-Pfad für ein realistisches Einzel-Retrieval aus — 18 GiB KV (ein 128k-Token-Präfix für Qwen3-4B: 36 Layers, GQA mit 8 KV-Heads à 128 Dimensionen, BF16, in 56-Token-Chunks) — unter jedem Backend, als Wallclock und als gelieferte GB/s. Die Bandbreitenwerte sind stilisierte runde Zahlen, vertretbar für einen Single-Socket-Server mit einem x16-GPU-Link; die Stufenstruktur jedes Pfads ist der Punkt, direkt aus der Charakterisierung des Papers übernommen.
import random
# Interface-cost arithmetic for one 128k-token KV retrieval (Qwen3-4B shape:
# GQA 8 KV heads x 128 head dim, BF16, 36 layers, 56-token LMCache chunks).
# Stylized bandwidths; ratios, not absolute times, are the point.
random.seed(260926828)
TOK, LAYERS, CHUNK_TOK = 131072, 36, 56
KV_TOK_LAYER = 2 * 8 * 128 * 2 # K+V bytes per token per layer
CHUNK_B = CHUNK_TOK * KV_TOK_LAYER * LAYERS # bytes per KV chunk
NCHUNK = TOK // CHUNK_TOK
PAYLOAD = NCHUNK * CHUNK_B
B_HOST, B_PCIE = 40e9, 20e9 # host DRAM rw, host<->GPU link (every path pays this)
B_NVME, B_GDS = 7e9, 12e9 # NVMe steady read, GDS NVMe->VRAM DMA
B_VRAM = 40e9 # VRAM-internal copy bandwidth (load_and_reshape)
SYS_US = 15e-6 # per-chunk block-path kernel/bookkeeping charge
base = PAYLOAD / B_PCIE # the DMA toll no path avoids
rows = [
("pinned host DRAM", [(1, B_PCIE)]),
("ramdisk (brd+ext4)", [(1, B_HOST), (1, B_PCIE)]),
("local NVMe O_DIRECT", [(1, B_NVME), (1, B_PCIE)]),
("GDS NVMe -> VRAM", [(1, B_GDS), (1.35, B_VRAM)]),
("CXL-SSD, DRAM hit", [(1, B_PCIE)]),
("CXL-SSD, NAND miss", [(1, B_NVME), (1, B_PCIE)]),
]
print(f"payload {PAYLOAD/2**30:.2f} GiB in {NCHUNK} chunks of {CHUNK_B/2**20:.2f} MiB "
f"(multi-hugepage: {CHUNK_B/2**20 > 2})")
print(f"{'path':26s} {'stages':>6s} {'wall ms':>9s} {'deliv GB/s':>10s} {'vs pinned':>9s}")
for name, stages in rows:
t = sum(PAYLOAD * f / b for f, b in stages) + SYS_US * (NCHUNK if "NVMe" in name or "ramdisk" in name else 0)
print(f"{name:26s} {len(stages):5d} {t*1000:9.1f} {PAYLOAD/t/1e9:9.2f} {t/base:9.2f}x")
# Why byte-addressable != faster, mechanically:
# 1) the DMA toll is the same PCIe link for pinned DRAM and CXL-mapped memory;
# 2) block paths add host-DRAM staging passes (writes 6% -> 33% of DRAM traffic
# in the paper, DRAM busy 3.6x as long per retrieval);
# 3) I/O shares the LLC -- isolating the I/O partition with Intel CAT recovers
# up to 44% of P99 TTFT in the paper. Overlapped degradation, stylized:
print("\nretrieval overlapped with decode, LLC partitioning off (stylized):")
for drop in (0.30, 0.44):
t = PAYLOAD / (B_PCIE * (1 - drop))
print(f" effective DMA -{int(drop*100)}% -> {PAYLOAD/t/1e9:5.2f} GB/s ({t/base:4.2f}x slow-down)")Output eines echten Laufs (Python 3, Seed 260926828):
payload 18.00 GiB in 2340 chunks of 7.88 MiB (multi-hugepage: True)
path stages wall ms deliv GB/s vs pinned
pinned host DRAM 1 966.1 20.00 1.00x
ramdisk (brd+ext4) 2 1484.3 13.02 1.54x
local NVMe O_DIRECT 2 3761.6 5.14 3.89x
GDS NVMe -> VRAM 2 2297.5 8.41 2.38x
CXL-SSD, DRAM hit 1 966.1 20.00 1.00x
CXL-SSD, NAND miss 2 3726.5 5.19 3.86x
retrieval overlapped with decode, LLC partitioning off (stylized):
effective DMA -30% -> 14.00 GB/s (1.43x slow-down)
effective DMA -44% -> 11.20 GB/s (1.79x slow-down)Drei Lesarten, alle passend zur gemessenen Struktur des Papers. Die Ramdisk-Zeile reproduziert den 1,8×-Block-Interface-Aufschlag, den das Paper misst (hier 1,54× — derselbe Mechanismus: ein zusätzlicher voller Payload-Durchlauf durchs Host-DRAM plus Per-Chunk-Kernel-Overhead, abzüglich des LLC-Konkurrenz-Terms, den die Wallclock-Spalte dieses Toys serialisiert wegfallen lässt). Die NVMe-Zeile reproduziert die ~3×-Gesamtstrafe der SSD mit dominantem NAND-Bandbreiten-Term. Und die zwei CXL-Zeilen sind die These dieses Artikels in einer Tabelle: Ein Hit in der DRAM-Region ist so schnell wie gepinntes Host-DRAM — die Staging-Kopie ist wirklich weg —, aber ein Miss ist exakt so langsam wie NVMe, denn es ist derselbe NAND hinter demselben FTL, und nichts an CXL.mem ändert tR. Adressierbarkeit verschiebt die Hit-Verzweigung der Kostenkurve auf DRAM-Tempo und lässt die Miss-Verzweigung unberührt. Ob man die gute Verzweigung bekommt, hängt ganz davon ab, was das Gerät in seiner DRAM-Region hält — und genau dort scheitern Standardgeräte.
3. Das CXL-SSD-Paradox: ein besseres Interface, keine bessere TTFT
Das Experiment in § 4.1 des Papers sollte man sich merken. Die Autoren lassen die Multi-Turn-Q&A-Workload gegen eine Standard-CXL-SSD-Implementierung laufen — dieselben 2-MiB-Hugepages und derselben Clock-Eviction, die auch das eigene Gerät des Papers nutzt, LMCache-Asynchrones-Laden aktiviert, kein geräteseitiges Prefetching — und gegen dasselbe Gerät mit Cylons Standard-Next-n-Sequenz-Prefetch-Politik, n = 4 Seiten pro DRAM-Miss8. Ergebnis: Das CXL-SSD ohne Spezialisierung verbessert die Performance über die SSD-Baseline nicht; die P99-TTFT regrediert über die der SSD hinaus; und Next-n lässt die mittlere TTFT nahezu unverändert, manche Turns werden schlechter. Der Zählervergleich ist präzise: Next-n stellt 19.198 Async-Loads aus, aber die Evictions steigen von 369.104 auf 387.840 und die NAND-Reads von 1.494.131 auf 1.504.029 — Prefetching erzeugte NAND-Traffic und Evictions, statt sie zu sparen1.
Warum macht ein Prefetcher es schlechter? Weil der gesamte CXL-SSD-I/O durch die begrenzte DRAM-Region muss und die Platzierungspolitik eines Standardgeräts nicht weiß, was kommt. Sechzehn parallele Sessions teilen sich eine 16-GiB-Region, während jede GiB-große Präfixe braucht — das heißt Thrash: Chunks werden wiederholt zwischen DRAM und NAND evictet und neu geladen. Next-n kann nicht helfen, weil es mis-getrieben und spekulativ ist: Es muss erst einen DRAM-Miss erleiden, um überhaupt zu triggern, rät die nächsten sequenziellen Seiten anhand der Adresse, und wenn sein Tipp zu spät oder falsch kommt, zahlt es einen Extra-Miss und verbrennt NAND-Bandbreite für Seiten, die niemand wollte. Der Teufelskreis, den das Paper benennt, ist strukturell: Mis-getriebenes Prefetching muss den Miss erleiden, den es zu verhindern versucht1.
Und hier ist die Granularitäts-Kollision, die Spekulation aussichtslos macht. LMCache-Einheit ist der Chunk — je nach Modell 32 bis 128 Tokens, bei diesen Shapes rund 8–40 MiB KV-Bytes —, während die Geräteeinheit die 2-MiB-Hugepage ist, selbst eine Ausrichtung über 4-KiB-OS-Seiten, abgebildet auf NAND-Seiten (Dutzende KiB) gruppiert in Erase-Blocks (typisch Hunderte KiB bis wenige MiB). Ein Lageweis-Lesezugriff will eine Layer über viele Chunks — weder seitenförmig noch chunkförmig. Ein Gerät, das nur Seiten sieht, kann keine der beiden Zugriffsformen servieren und schon gar nicht vorhersagen: KV-Reuse folgt der Baumstruktur der Präfixe — Systemprompt, abgerufene Dokumente, Gesprächshistorie — nicht dem Adresslayout eines flachen Arrays. Die Serving-Engine kennt die Form dieses Baums zur Prefix-Lookup-Zeit, bevor sich ein Byte bewegt. Das Gerät sieht sie nie. Diese Asymmetrie — nicht das Fehlen von Prefetching — ist die Lücke.
Die nächste Zelle reproduziert die DRAM-Regions-Dynamik unter drei Politiken mit der Übersubskription des Papers: 16 parallele Sessions, die pro Turn ihr wachsendes Präfix erneut berühren, gegen eine Region, die nur einen Bruchteil des Working Sets fasst. „Stock" ist mis-getrieben; „Next-n" spekuliert auf Chunk+1-Adressen; die Hint-Politik ist ein Stand-in für LM-CXDs Fensterung — die Engine sagt dem Gerät, welche Chunks die nächsten Turns brauchen werden, und vorgeladene Fenster sind gegen Eviction gepinnt, bis sie konsumiert sind.
import random
# Felt-NAND-latency accounting for one CxS turn: does the DRAM region hold a
# session's chunks when the engine reaches for them? Region 16 GiB = 4096
# chunk slots; 16 concurrent sessions, each turn re-touching the full
# accumulated prefix and appending 390 new chunks. CLOCK eviction, no GC.
random.seed(260926828)
SLOTS = 4096
SYS = 200
NEW_PER_TURN = 390
N_SESS, N_TURN = 16, 6
def prefix_len(turn): # chunks a turn t session must read
return SYS + NEW_PER_TURN * (turn + 1)
def run(policy, windows=2, wsize=350):
resident = {} # cid -> True, dict preserves CLOCK order
pin = set()
st = dict(on_demand=0, resident_hit=0, wasted_fetch=0, nand=0, evict=0)
def clock_evict():
while len(resident) >= SLOTS:
v = next(iter(resident))
if v in pin:
resident[v] = resident.pop(v)
continue
del resident[v]; st["evict"] += 1
return
def fetch(cid, pin_it=False):
if cid in resident:
resident[cid] = resident.pop(cid)
return
st["nand"] += 1
clock_evict()
resident[cid] = True
if pin_it: pin.add(cid)
for turn in range(N_TURN):
for s in range(N_SESS):
base = 1000000 + s * 100000
need = [ *range(SYS), *range(base, base + prefix_len(turn) - SYS) ]
if policy == "stock":
for cid in need:
if cid not in resident:
st["on_demand"] += 1
fetch(cid)
elif policy == "next-n": # speculative: grab the next chunk address
for cid in need:
if cid not in resident:
st["on_demand"] += 1
fetch(cid)
nxt = cid + 1
if nxt not in need and nxt not in resident:
fetch(nxt); st["wasted_fetch"] += 1
else: # windowed engine hints, pinned windows
for w in range(windows):
for cid in need[w * wsize:(w + 1) * wsize]:
fetch(cid, pin_it=True)
for cid in need:
if cid in resident:
st["resident_hit"] += 1
else:
st["on_demand"] += 1
fetch(cid)
pin.clear()
return st
print(f"region {SLOTS} chunk slots; per-turn demand per session grows "
f"{prefix_len(0)} -> {prefix_len(N_TURN-1)} chunks")
print(f"{'policy':22s} {'on-demand':>9s} {'pre-hit':>8s} {'NAND':>8s} {'wasted':>7s} {'evict':>7s}")
for name, pol in (("stock (miss-driven)", "stock"), ("next-n (speculative)", "next-n"),
("windowed hints+pin", "hints")):
st = run(pol)
print(f"{name:22s} {st['on_demand']:9d} {st['resident_hit']:8d} {st['nand']:8d} {st['wasted_fetch']:7d} {st['evict']:7d}")Output eines echten Laufs (Python 3, Seed 260926828):
region 4096 chunk slots; per-turn demand per session grows 590 -> 2540 chunks
policy on-demand pre-hit NAND wasted evict
stock (miss-driven) 137040 0 137040 0 132944
next-n (speculative) 137040 0 137166 126 133070
windowed hints+pin 84800 65440 131240 0 127144Die Signatur entspricht Tabelle 2 des Papers exakt in der Form. Next-n addiert NAND-Reads (137.166 gegenüber 137.040) und Evictions (133.070 gegenüber 132.944) — über gar nichts tun hinaus; alles verbraucht für Fehlraten (126 verschwendete Fetch-Chunk-Ereignisse in diesem Toy; im Papier rund zwanzigtausend Async-Loads, die null Hit-Rate-Verbesserung kauften und negativ thrashten). Die Fenster-Hint-Politik verwandelt 65.440 der On-Demand-Misses des Standardgeräts in vorbereitete, gepinnte Hits — Chunks liegen vor dem Zugriff der Engine in der DRAM-Region — mit weniger NAND-Reads und weniger Evictions insgesamt, denn sie holt nie nach, was niemand konsumiert, und evictet nie, was im Flug gepinnt ist. Diese Verwandlung — Miss-vor-Bedarf in Hit-vor-Bedarf — ist die ganze Performance-Geschichte von LM-CXD. Das Toy zeigt auch seine ehrliche Grenze: Der Working Set passt weiterhin nicht, also kann selbst Hint-Prefetching die NAND-Reads nicht auf null drücken — die verbleibenden 84.800 On-Demand-Reads im Toy entsprechen dem Befund des Papers, dass „am Schwanz weiterhin Hunderte Millisekunden bleiben, sodass die Überlappungsfenster beider Methoden NAND nicht vollständig verstecken".
4. LM-CXD: den Co-Designpreis ausrechnen, Eigenschaft für Eigenschaft
Der Move des Papers: das CXL-SSD nicht länger als generisches Speichergerät behandeln, sondern den KV-Chunk zur Einheit machen, die das Gerät indiziert, bewegt, über Fortschritt berichtet und zur GPU transferiert. Drei Eigenschaften, jede schließt einen spezifischen gemessenen Fehlschlag1:
Eigenschaft 1: Chunk-Identität wird I/O. LMCache Prefix-Lookup berechnet für jede Anfrage bei Ankunft ohnehin Chunk-Hashes — so findet es das längste gecachte Präfix. LM-CXDs gemeinsame Strukturen (Prefix-Lookup-Tabelle von Chunk-Hash zu Ort, Pin-Map zum Schutz im Flug befindlicher Fenster vor Clock-Eviction, Free-Queue fürs Chunk-Löschen, eine Prefetch-Queue von Chunk-Hashes und ein Prefetch-Plan-Pool fürs Lageweise) leben in einer reservierten Region des Geräte-DRAM, les- und schreibbar für LMCache und den Gerätecontroller ohne Syscalls, Interrupts oder Kopien. LM-CXD löst Chunk-Hashes gegen den eigenen Index auf, überspringt Chunks, die schon in der DRAM-Region liegen, und stellt die NAND-Reads selbst aus — Chunk-Matching auf Host-Seite kostet unter Compute-Asynchronem Prefetching (CAP) 6–7 Mikrosekunden pro Chunk, gegen 160 Mikrosekunden pro Chunk, die das Standardgerät fürs Kopieren verbraucht1.
Eigenschaft 2: Die Engine handelt nach Gerätefortschritt. LM-CXD protokolliert Dispatch- und Abschluss-Zustand pro Session im Geräte-DRAM. LMCache pollt ihn, admittiert eine Session, sobald ihre ersten zwei Fenster Chunks disponiert sind (nicht abgeschlossen), und DMAet fertige Chunks zur GPU, während die Session in vLLMs nicht-blockierendem WAITING_FOR_REMOTE_KV-Zustand wartet — unter der Rechnung anderer Sessions. Das ist die bidirektionale Hälfte: Hints fließen Engine-zu-Gerät, Fortschritt Gerät-zu-Engine, und die Admission wartet nicht länger auf den Abschluss von Loads, die sie überlappen kann. Promotions werden pro Scheduler-Schritt gedeckelt mit einer bedingungslosen Promotion, damit der Dispatcher zwischen Admissions ablaufen kann.
Eigenschaft 3: Geräte-DRAM ist der Quellpuffer der GPU. Die DRAM-Region ist per cudaHostRegister gepinntes Memory; DMA zieht Chunks direkt vom Geräte-DRAM in den VRAM ohne Host-Staging. Die Fenster-Disziplin (ein Pin-Budget pro Rank, dimensioniert nach Region, Rang-Anzahl und Workload; zwei Fenster vorgeladen; das nächste Fenster startet erst, wenn ein anderes entpinnt) macht Prefetching erst in einer Region möglich, die keinen ganzen Präfix halten kann — das dritte Design-Prinzip des Papers, NAND-Latenz unter begrenztem Geräte-DRAM verstecken, konkret gemacht.
Dann zwei Prefetch-Methoden, jede in ihr Workload-Regime gepasst. CAP terminiert Fenster-Prefetch hinter Lookup-Hints, während andere Sessions rechnen — die Benchmark-Antwort für paralleles Multi-Turn-Serving. Lageweises Prefetching geht weiter: Es verfolgt einen Plan pro Anfrage, konvertiert Chunks von Chunk-Major nach Layer-Major in einer eigenen Staging-Area des Geräte-DRAM und nutzt einen Strided-cudaMemcpy3DAsync-Deskriptor, so dass der DMA selbst den Layout-Wechsel ausdrückt (zwei Kopien pro Layer statt zwei pro Chunk). Ein konstanter n-tiefer Lookahead-Puffer lässt NAND-Reads der Layer-Konsumation vorauslaufen; das Paper läuft mit Prefetch-Grad 7 auf Qwen3-VL-32B.
5. Die lageweise Pipelining-Schranke
Ob lageweises Prefetching sich auszahlt, ist pure Überlappungs-Arithmetik: Schafft die NAND-zu-DRAM-Bewegung der nächsten Layers den Abschluss innerhalb der Per-Layer-Rechenzeit der GPU auf diesem Modell bei dieser Präfixlänge? Die Schranke ist per-Layer-Transferzeit gegen per-Layer-Rechenzeit; die benötigte Lookahead-Tiefe ist ihr Quotient; liegt der Quotient über eins, versteckt kein Pipelining der Welt das NAND und der Schwanz bleibt. Die nächste Zelle rechnet das für drei der evaluierten Modelle des Papers mit ihren Präfixen durch. Das Rechenmodell ist der Standard-Prefill-Attention-Envelope (4-Schranke) bei 35% MFU auf dem BF16-Peak von 362 TFLOP/s eines L40S — stilisiert, aber die strukturelle Schlussfolgerung braucht nur Richtigkeit in der Richtung, weil Transfer- und Rechentermen mit Präfixlänge so unterschiedlich skalieren.
import random
# Layerwise pipelining arithmetic: can NAND->DRAM movement for layer L+1..L+k
# hide under the GPU's compute for layer L? Uses the paper's evaluated models
# (Table 4): Qwen3-4B (36 layers), Qwen3-VL-32B (64 layers, layerwise
# prefetch degree 7), Llama-3.1-70B (80 layers). GQA 8 KV heads x 128 head
# dim, BF16. NAND: 16-channel Z-NAND, tR = 3 us -- parallel-array bound.
random.seed(260926828)
KVH, DIM, BYTES = 8, 128, 2
NAND_BW = 6.0e9 # effective sustained NAND->DRAM region read
CXL_DMA = 18e9 # device-DRAM -> VRAM strided cudaMemcpy3DAsync
GPU_TFLOP = 362e12 # L40S BF16 dense peak
MFU = 0.35 # realized fraction on attention prefill work
MODELS = [
("Qwen3-4B @128k", 36, 131072, 56),
("Qwen3-VL-32B @64k", 64, 65536, 32),
("Llama-70B @16k", 80, 16384, 128),
]
def layer_bytes(prefix_tok, layers):
return 2 * KVH * DIM * BYTES * prefix_tok # one layer, K+V
for name, layers, tok, csize in MODELS:
lb = layer_bytes(tok, layers)
t_xfer = lb / NAND_BW # NAND -> device DRAM, one layer
t_dma = lb / CXL_DMA # device DRAM -> VRAM, one layer
flops = 4 * tok * tok * KVH * DIM
t_compute = flops / (GPU_TFLOP * MFU)
degree_needed = t_xfer / t_compute # lookahead k so k >= t_xfer/t_c
total_chunk = layer_bytes(tok, layers) * layers
t_serial = layers * (t_xfer + t_dma + t_compute)
t_pipe = layers * max(t_compute, t_xfer + t_dma / degree_needed)
t_ideal = layers * t_compute
print(f"{name}: layer {lb/2**20:6.1f} MiB t_xfer {t_xfer*1e3:7.2f} ms "
f"t_dma {t_dma*1e3:6.2f} ms t_compute {t_compute*1e3:8.2f} ms")
print(f" full-prefix layer KV {(lb*layers)/2**30:6.2f} GiB "
f"lookahead needed {degree_needed:5.2f} layers "
f"pipelined/serial speedup {t_serial/t_pipe:4.2f}x vs compute-only {t_pipe/t_ideal:4.2f}x")
print("\nQwen3-VL-32B, full 64k prefix retrieval vs pipelined layerwise:")
name, layers, tok, _ = MODELS[1]
lb = layer_bytes(tok, layers)
t_xfer, t_dma = lb / NAND_BW, lb / CXL_DMA
t_c = 4 * tok * tok * KVH * DIM / (GPU_TFLOP * MFU)
t_serial_all = layers * (t_xfer + t_dma + t_c)
print(f" serial (retrieve, then compute): {t_serial_all*1e3:8.0f} ms")
for deg in (1, 4, 7):
t_pipe = layers * max(t_c, (t_xfer + t_dma) / deg)
print(f" layerwise degree {deg}: total {t_pipe*1e3:7.0f} ms "
f"({t_pipe/t_c/layers:4.2f}x pure compute, {t_serial_all/t_pipe:4.2f}x vs serial)")Output eines echten Laufs (Python 3, Seed 260926828):
Qwen3-4B @128k: layer 512.0 MiB t_xfer 89.48 ms t_dma 29.83 ms t_compute 555.40 ms
full-prefix layer KV 18.00 GiB lookahead needed 0.16 layers pipelined/serial speedup 1.21x vs compute-only 1.00x
Qwen3-VL-32B @64k: layer 256.0 MiB t_xfer 44.74 ms t_dma 14.91 ms t_compute 138.85 ms
full-prefix layer KV 16.00 GiB lookahead needed 0.32 layers pipelined/serial speedup 1.43x vs compute-only 1.00x
Llama-70B @16k: layer 64.0 MiB t_xfer 11.18 ms t_dma 3.73 ms t_compute 8.68 ms
full-prefix layer KV 5.00 GiB lookahead needed 1.29 layers pipelined/serial speedup 1.68x vs compute-only 1.62x
Qwen3-VL-32B, full 64k prefix retrieval vs pipelined layerwise:
serial (retrieve, then compute): 12704 ms
layerwise degree 1: total 8886 ms (1.00x pure compute, 1.43x vs serial)
layerwise degree 4: total 8886 ms (1.00x pure compute, 1.43x vs serial)
layerwise degree 7: total 8886 ms (1.00x pure compute, 1.43x vs serial)Lies die Tabelle wie die Messungen des Papers. Qwen3-4B bei 128k hat 555 ms Rechenzeit pro Layer, um 119 ms Bewegung dahinter zu verstecken — trivial überlappbar, Lookahead-Tiefe 0,16, das Pipelining erreicht Computebindung (1,00× der puren Rechenzeit). Qwen3-VL-32B bei 64k genauso: Tiefe 0,32 gegen 60 ms Bewegung unter 139 ms Rechnung. Llama-3.1-70B bei nur 16k Tokens ist die warnende Zeile: 15 ms Bewegung gegen 8,7 ms Rechnung, benötigte Lookahead-Tiefe 1,29 — der Schwellenfall. Genau das ist die gemessene Anomalie des Papers: Llama-70Bs lageweise Gewinne sind die kleinsten (1,74× mittlere TTFT-Verbesserung gegen 4,03× bei Qwen3-VL-32B), sein ferner P99-Schwanz bleibt in den NAND-Warte-CDFs innerhalb von 1,3× am Standardgerät, wo die anderen Modelle 2,9–4,8× gewinnen, und seine P99-TTFT im Turn 3 schießt auf Standardniveau zurück — denn bei 16k bietet die Per-Layer-Rechnung die geringste Überlappungszeit, und „die wenigen, die zu spät ankommen, haben die geringste Per-Layer-Rechenzeit, sich dahinter zu verstecken". Dieselbe Physik, in beide Richtungen: Präfix 4× kürzer und Layerzahl 25% höher als bei Qwen3-VL-32B — das kippt das Vorzeichen des Budgets.
Der Gleichstand von Grad 1/4/7 im zweiten Block lehrt die Schranke selbst: Passt die Bewegungspipeline für die nächste Layer in die Rechenzeit der aktuellen bei Grad 1 (benötigte Tiefe 0,32 ist kleiner als 1), kaufen zusätzliche Lookahead-Grade nichts — der Grad 7 des Papers auf diesem Modell ist Spielraum, keine Notwendigkeit, und die echte, vom Papier identifizierte Grenze sind die DRAM-Kosten der Lookahead-Puffer (rund 9 GiB für die 64k-Präfix-Modelle, die mehr als die Hälfte der 16-GiB-Region verdrängen — der tatsächliche Preis des Lageweisen, nicht die Prefetch-Maschinerie).
6. Was der Co-Design real kauft, gemessen
Über fünf Modelle (Qwen3-4B, Ministral-8B, Qwen3-Coder-30B-A3B, Qwen3-VL-32B, Llama-3.1-70B — alle GQA) auf dem CxS-Multi-Turn-Benchmark (16 Sessions, 6 Turns) und einer agentischen Coding-Trace (AIPerf, 48 Sessions, 128k–160k-Präfixe): TTFT sinkt um 2,51× und 2,6× im Schnitt unter CAP für Qwen3-4B und Ministral-8B; 4,03× für Qwen3-VL-32B lageweise; 1,74× für Llama-70B; gesamt im Schnitt innerhalb von 1,5× zu lokalem DRAM1. Die mittlere gefühlte NAND-Zeit pro Anfrage fällt von 139–920 ms (Standard, über die vier Modelle) um mindestens 3× am Median und 2,5–4,1× am P90 unter LM-CXD — mit ehrlichen verbleibenden Schwänzen im Bereich Hundert-Millisekunden. Auf der agentischen Trace ist die mittlere TTFT fast identisch mit dem Standardgerät (der meiste dieses KV bleibt per Reuse-Häufigkeit heiß in der DRAM-Region) und der Gewinn ein um 17% niedrigerer P90 — Chunk-bewusstes Prefetching zahlt sich exakt dort aus, wo Reuse sporadisch ist, und nirgendwo sonst.
Die DRAM-Regions-Sensitivitätstabelle ist die sauberste Preisstellung der semantischen Lücke: Bei 8/16/32 GiB Region liegt die Standard-CXL-SSD bei 6,26/6,53/1,98 s TTFT, LM-CXD hält 2,78/2,40/1,90 s. Das Standardgerät ist hochgradig regionsgrößenempfindlich (3×-Schwankung); LM-CXD bewegt sich über den Sweep hinweg unter 1,5× und schlägt bei 8 GiB das Standardgerät bei 16 GiB um 2,3×. Der Lifecycle-Split zeigt warum: Queue-und Prefill-Zeiten des Standardgeräts steigen bei kleinen Regionen beide um rund dreifach, während LM-CXD auf Dispatch admittiert und gepinnte Fenster kopiert, also wächst sein Anstieg allein in die Queue. Der Gemeinsame-Strukturen-Overhead ist in der anderen Richtung vernachlässigbar — 22 MiB, 0,13% einer 16-GiB-Region, für alles, was CAP braucht1.
7. Anti-Hype: Was dieses Paper nicht belegt
Nichts davon läuft auf kommerziellem Silizium. Es ist keine CXL-SSD käuflich zu haben; LM-CXD läuft auf einer modifizierten NVMeVirt-Plattform (Page-Fault-abgefangenes DRAM mit injiziertem Z-NAND-Timingmodell, NUMA-Knoten-Speicher als CXL-Stellvertreter), validiert gegen den Cylon-Emulator auf bimodaler Latenz und Per-Miss-Breakdown (übereinstimmende ≈6,2 Mikrosekunden Gerätezeit; der Rest ist Cylons KVM/QEMU-Exit-Overhead, keine Gerätephysik)8. Jede absolute Zahl erbt Emulationsfehler; übertragbar sind die Mechanismus-Behauptungen.
Die 1,5×-Lücke zu DRAM ist eine Untergrenze mit bekannten Ursachen. Selbst voll spezialisiert bleibt Geräte-DRAM begrenzt, NAND-Reads bleiben im Schwanz, und LM-CXDs Queue-Zeit-Komponente verschwindet nicht — bei 32-GiB-Regionen konvergieren die beiden Geräte laut Paper, und LM-CXDs Prefill erreicht das Niveau von lokalem DRAM, die Queue-Zeit bleibt als Rest. Chunk-bewusstes Design verengt die Lücke; es schließt sie nicht.
Co-Design schneidet in beide Richtungen. LM-CXDs bidirektionales Interface kostet Host-Bookkeeping (1,2–2,4% eines Retrieves — klein, aber nicht null), die Lookahead-Puffer verdrängen bei 64k-Präfixen mehr als die Hälfte der Chunk-Region, und Lageweise ist ein Nettoverlust für klein-Präfixige, schnell dekodierende Modelle (Qwen3-4B: +1,40 s Prefill, um 0,51 s Queue-Wartung zu sparen). Der paper-eigene Modellvergleich zeigt keine einzelne Prefetch-Methode, die überall gewinnt — CAP für paralleles Serving, Lageweise für große Einzel-Session-Lasten — was die übliche Signatur eines echten Systems ist statt eines Benchmark-Artefakts.
KV-Cache-Regenerierbarkeit ist tragend. LM-CXD verwirft lebende Chunks aus erassten NAND-Lines, statt sie zu relokieren — kein Garbage Collection —, denn KV kann immer neu berechnet werden. Das ist ein Prefix-Caching-spezifischer Freibrief; das Design generalisiert nicht auf Storage, dessen Daten einen Erasure überleben müssen1.
Byte-Adressierbarkeit bleibt das richtige Primitiv — aus dem richtigen Grund. Die richtige Lesart des Negativ-Ergebnisses ist nicht „CXL-SSDs sind sinnlos", sondern „Adressierbarkeit ist notwendig, aber nicht hinreichend". Jeder Pfad, der das Block-Interface berührte, ließ 1,8× auf dem Tisch; es zu entfernen lohnte sich vor jedem Chunk-Bewusstsein — ein DRAM-Hit auf LM-CXDs Region ist Pinned-DRAM-schnell. Erst dann zahlt die semantische Arbeit ihre 2,6–4,03×.
Für Praktiker destilliert sich die Checkliste auf: (1) Heiße Präfixe zuerst in schlichtes DRAM halten — die Standard-CXL-SSD verliert um 3× gegen lokales DRAM, selbst LM-CXD konzediert 1,5×; (2) wenn eine NAND-Ebene unvermeidlich ist und CXL-SSDs materialisieren, hilft nichts Generisches — chunk-sichtbare Interfaces fordern, fensteriges gepinntes Prefetching, Dispatch-progrediente Admission und lageweise Konvertierung; (3) das Geräte-DRAM-Budget explizit planen und das Per-Layer-Transfer-gegen-Rechenzeit-Verhältnis bei den eigenen Präfixlängen prüfen, bevor irgendjemandem 4× versprochen werden.
Fußnoten
Footnotes
-
Chung, Hyunsun; Noh, Taewan; Kim, Minji; Hwang, Joo-Young; Kim, Hong-Yeon; Kim, Youngjae — Bridging LLM Serving and CXL-SSDs with Chunk-Aware KV Cache Management, arXiv:2609.26828v1, cs.AR, eingereicht am 20. September 2026, Sogang University mit Samsung Electronics und ETRI (vollständiger HTML-Text v1 verifiziert: Standard-CXL-SSD ≈3× langsamer als lokales DRAM, nicht schneller als NVMe; Next-n-Prefetch async_loads 19.198 gegen 0, Evictions 387.840 gegen 369.104, NAND-Reads 1.504.029 gegen 1.494.131; Ramdisk 1,8× langsamer als direktes DRAM, Schreibzugriffe 6%→33% des DRAM-Traffics, DRAM 3,6× so lange beschäftigt; CAT gewinnt bis zu 44% der P99-TTFT zurück; Ramdisk 5,27 s gegen gepinnt 1,34 s TTFT, ext4-Rest 0,2 s von 3,9 s; NAND: 61% der SSD-Lücke durch DRAM-Mediumstausch geschlossen; LM-CXD TTFT bis zu 2,6× CAP / 4,03× lageweise über Standard-CXL-SSD, im Schnitt innerhalb von 1,5× zu lokalem DRAM; Per-Chunk-Matching 6–7 μs gegen 160 μs Standard-Kopie; mittlere gefühlte NAND-Zeit 139–920 ms, am Median ≥3× und am P90 2,5–4,1× gesenkt, Llama-70B-P99 innerhalb von 1,3×, Median 8,7× bei 16k; agentisch 17% niedrigerer P90; DRAM-Region 8/16/32 GiB Standard 6,26/6,53/1,98 s gegen LM-CXD 2,78/2,40/1,90 s Mittel, 2,3× bei 8 gegen 16 GiB, gemeinsame Strukturen 22 MiB = 0,13%; lageweise Lookahead-Puffer ~9 GiB bei 64k-Präfixen, Llama 2,5 GiB; Bookkeeping 1,2–2,4% eines Retrieves; Llama lageweise +1,40 s Prefill gegen −0,51 s Queue bei 64k; 16 GiB DRAM + 384 GiB NAND = 400-GiB-Gerät; Evaluation 5 GQA-Modelle, CxS c=4/s=4/16 Sessions/6 Turns, 4× L40S, Xeon Gold 6548Y+ Dual-Sockel, 614 GB DDR5, Samsung PM9D3a NVMe, vLLM v0.16.0 + LMCache v0.3.13): https://arxiv.org/abs/2609.26828 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 ↩13
-
Verifikationsnotiz: Alle tragenden Zahlen oben wurden aus dem vollständigen HTML-Text von arXiv:2609.26828v1 abgeleitet, abgerufen am 25. September 2026 (curl-gespeichert und Tag-gefiltert), nicht aus dem Abstract oder dem Briefing dieses Artikels. Die drei Code-Zellen sind originale Illustrationen, dimensioniert auf die Modelle des Papers; ihre Ausgaben sind die byte-exakten Ergebnisse realer Läufe unter Python 3 mit Seed 260926828, ausgeführt über /usr/bin/python3; die Zellen berechnen die Interface-Kosten-, DRAM-Regions-Residenz- und lageweise Pipelining-Mechanik, und ihre stilisierten Bandbreiten-/FLOP-Konstanten sind in der Zelle deklariert. ↩
-
Liu, Yuhan; et al. — LMCache: an Efficient KV Cache Layer for Enterprise-Scale LLM Inference, arXiv:2510.09665: das Serving-Schicht-System, dessen Prefix-Lookup Token-Chunks hasht, das längste gecachte Präfix findet und Reuse über GPU, Host-DRAM und Storage verwaltet — jene Komponente, deren Chunk-Wissen LM-CXD ins Gerät verlagert: https://arxiv.org/abs/2510.09665 ↩
-
Nguyen, Khoa Tan — Introduction to Cache Allocation Technology in the Intel Xeon Processor E5 v4 Family: der LLC-Partitionierungsmechanismus, mit dem das Paper Block-I/O-Threads von Inferenz-Threads isoliert und so die Cache-Konkurrenz-Komponente der Block-Pfad-Strafe isoliert: https://www.intel.com/content/www/us/en/developer/articles/technical/introduction-to-cache-allocation-technology.html ↩
-
NVIDIA — GPUDirect Storage-Dokumentation: direktes DMA von NVMe in VRAM, im Paper mit Nsight Systems auf 1022 KV-Chunks profiliert — der Pfad, der CPU und Host-DRAM entfernt und dennoch jeden Chunk für load_and_reshape in einen VRAM-Puffer stellt, die Kosten des Block-Interfaces also in die GPU verlagert statt sie zu beseitigen: https://docs.nvidia.com/gpudirect-storage/ ↩
-
Compute Express Link Consortium — CXL Specification, Revision 4.0, Version 1.0: der cache-kohärente Interconnect-Standard über PCIe-Infrastruktur; Type-3-Geräte exponieren Host-managed Device Memory über das CXL.mem-Protokoll, gemappt in den physischen Adressraum des Hosts — der Memory-Semantic-Mechanismus, dessen Bandbreitedecke der PCIe-Link bleibt, auf dem er fährt, und dessen Misses den FTL-Round-Trip plus tR auf dem darunterliegenden NAND zahlen: https://computeexpresslink.org/cxl-specification/ ↩
-
Z-NAND-Timingparameter, die das Paper aus früheren CXL-SSD-Studien übernimmt (Samsung SZ1735, 16-Kanal-SLC): tR = 3 Mikrosekunden, tPROG = 100 Mikrosekunden, tBERS = 1 ms — die DRAM-nahe NAND-Reader-Latenz, die die Miss-Verzweigung eines CXL-SSD weit unter die von TLC hebt, und dennoch jene Verzweigung bleibt, in der die komplette restliche Latenz lebt: https://www.techpowerup.com/ssd-specs/samsung-sz1735-800-gb.d2275 ↩
-
Yoon, D.; Idden, H.; Liu, J.; Inceisci, B.; Noh, S. H.; Li, H. — Cylon: Fast and Accurate Full-System Emulation of CXL-SSDs, FAST 26: der State-of-the-Art-Emulator, dessen bimodale Latenzverteilung die Plattform des Papers reproduziert, und dessen konfigurierbare Next-n-Prefetch-Politik die Generic-Prefetcher-Baseline lieferte; ebenso Kim, S.; et al. — NVMeVirt (FAST 23), die Software-defined-NVMe-Plattform, die zur CXL-SSD-Emulation des Papers modifiziert wurde: https://www.usenix.org/conference/fast26 ↩ ↩2