WP26 — löst die Zerlegung in Quanten die Aushungerung?
Stand: 2026-09-01 · echte GPU, echtes Sprachmodell
Nachtrag 2026-09-08 — das Ergebnis unten ist überholt.
Die Antwort dieses Dokuments lautete „nein". Sie beruhte auf einem Lauf, in dem gar nichts zerlegt wurde: der Auftragszustand entstand erst in der Fortsetzung, also nie (Review-Befund F03). Dass „mit" und „ohne Zerlegung" identische Zahlen lieferten, war der Fingerabdruck dieses Fehlers, nicht ein Messergebnis.
Hinzu kam ein zweiter Fehler:
size_quantumrechnete die Dauer eines Quantums rein proportional zur Tokenzahl. Gemessen kostet jeder Auftrag einen festen Sockel von 14–18 ms — bei rund 18 ms Slack ist das der ganze Unterschied. Das Kostenmodell ist jetzt affin (base_cost_us), und die hier eingetragenen 55 Token/s waren um Faktor 4,4 veraltet.Nach Reparatur beider Punkte, zwei Läufe: die Zerlegung bringt 40–41 statt 1–2 Generierungen (9.300 statt 606 Zeichen) und kostet dafür 7 Punkte Detektor-Abdeckung (98 % → 91 %) und ein verdoppeltes Antwortalter (33 → 65 ms), bei null Protected-Deadline-Misses. Das ist keine Aushungerung mehr, sondern ein einstellbarer Kompromiss.
Zahlen und Rohdaten:
../reviews/2026-09-07/gpu/ERGEBNIS.md. Der Text unten bleibt als Beleg des damaligen Standes stehen.
Die Frage
Gate M3 hat bestätigt, was ADR-0012 vorhergesagt hatte: ein nicht unterbrechbarer Block läuft neben einer 33-ms-Periode nie. ADR-0014 zerlegt generative Aufträge in Quanten, deren Größe sich aus dem Slack bis zur nächsten geschützten Ankunft ergibt.
Die Frage ist nicht, ob der Detektor geschützt wird — das ist belegt. Die Frage ist, ob das Sprachmodell dabei überhaupt vorankommt.
Aufbau
| Detektor | RF-DETR 512 px, 30 Hz, protected, Shared Memory |
| Sprachmodell | Qwen3-0.6B, vLLM-Backend, best_effort, 64 Token je Auftrag |
| Kapazität | ein Slot — die Slots modellieren die GPU, nicht den Prozess |
| Messdauer | 30 s je Betriebsart |
Zwei Triton-Server auf einer GPU. Der Versuch, das onnxruntime-Backend in
das vLLM-Image zu transplantieren, scheiterte: die Modelle laden, aber die
Ausführung bricht mit CUDNN_FE failure 7: GRAPH_EXECUTION_FAILED ab. Das
Backend linkt gegen die cuDNN-Version seines eigenen Images. Vision- und
Sprachmodelle brauchen getrennte Server — was auch der Realität entspricht.
Daraus entstand die Konfigurationsoption backend_endpoint je Modell. Die
Kapazitätsrechnung bleibt davon unberührt: zwei Server auf einer Karte teilen
sich weiterhin eine Ausführungseinheit.
Der Aufrufweg unterscheidet sich — notwendigerweise
direkt zu Triton -> decoupled, also ModelStreamInfer
über den Governor -> unär, denn genau das bietet OneTimer an
Das ist keine Unfairness, sondern die Schnittstellenzusage. Generative Backends sind in Triton grundsätzlich decoupled; OneTimer nimmt den Request unär entgegen und übersetzt intern auf den Stream-Aufruf. Ein Client, der auch am Gateway streamen wollte, wird abgelehnt — bewusst, weil gestreamte Requests die Frischelogik umgehen würden (Spec 16.1).
Was ein Quantum kostet
Die entscheidende Messung. ADR-0014 leitet die Quantengröße aus
Budget × Token/Sekunde ab — das unterstellt Kosten proportional zur
Tokenzahl. Gemessen (Qwen3-0.6B, enforce_eager: true, je 5 Läufe):
| Token je Auftrag | Dauer |
|---|---|
| 1 | 23 ms |
| 2 | 38 ms |
| 4 | 77 ms |
| 8 | 147 ms |
| 16 | 288 ms |
| 32 | 580 ms |
| 64 | 1153 ms |
Der feste Sockel je Auftrag ist klein — die Gerade schneidet bei rund 5 ms. Teuer ist das einzelne Token: rund 18 ms.
Das ist die eigentliche Schranke. Bei einer geschützten Periode von 33 ms verbraucht schon das feinstmögliche Quantum — ein Token, 23 ms — siebzig Prozent einer Periode. Eine Zerlegung kann keine Lücken schaffen, die kleiner sind als ihr kleinster Baustein.
Ergebnis
30 s je Betriebsart, Maschine bei Last 1,2, CUDA-Graphen aktiv:
| Betriebsart | Detektor-Abdeckung | AoI p95 | Generierungen | Zeichen |
|---|---|---|---|---|
| direkt zu Triton | 77 % | 36 ms | 70 | 21210 |
| Governor ohne Zerlegung | 98 % | 33 ms | 2 | 606 |
| Governor mit Zerlegung | 98 % | 33 ms | 2 | 606 |
Zwei Aussagen, und sie ziehen in verschiedene Richtungen.
Der Schutz wirkt, und zwar deutlich. Ohne Governor fällt die Wahrnehmung auf 77 % ab, während das Sprachmodell die GPU sättigt. Mit Governor 98 %. Das ist das §1.3-Szenario auf echter Hardware, mit einem echten Detektor und einem echten Sprachmodell — und es reproduziert sich über mehrere Läufe.
Die Zerlegung bringt nichts. Identisch mit und ohne, bei 1802 Veto-Ereignissen des Look-ahead. Der Grund lässt sich aus den gemessenen Kosten ausrechnen:
Detektor: 33 ms Periode, ~19 ms konservative Laufzeit
-> ~14 ms Leerlauf je Periode
Quantum: 13 ms fester Sockel + 4 ms je Token
-> das kleinstmögliche Quantum kostet 17 ms
Das kleinste Quantum ist teurer als die Lücke, in die es passen müsste. Der Look-ahead vetoiert deshalb korrekt, und keine Wahl der Quantengröße ändert daran etwas.
Der Sockel von 13 ms ist der Preis dafür, dass OneTimer außerhalb des Servers sitzt und nur an Requestgrenzen zerlegen kann. Eine kooperative Ausführung innerhalb von vLLM — dessen eigenes Priority Scheduling — hätte ihn nicht. Sie wäre dann aber kein Drop-in-Governor mehr, und das ist die Produktentscheidung aus Spec 5.1.
Was daraus folgt
WP26 ist umgesetzt und gemessen, aber nicht wirksam in dieser Konfiguration. Damit bleibt ADR-0012 offen: der lange Best-Effort-Job läuft auf einem Slot weiterhin praktisch nicht.
Wirksam wäre die Zerlegung erst, wenn eine der drei Größen sich ändert:
- größere Leerlauflücke — längere geschützte Periode oder schnellerer Detektor,
- kleinerer Sockel — Zerlegung innerhalb des Servers statt an Requestgrenzen,
- mehr Kapazität — zwei Slots, dann braucht es die Zerlegung gar nicht.
Die ehrliche Konsequenz für die Positionierung: die Zusage „VLM neben Detektor auf einer GPU" gilt bis auf Weiteres ab zwei Ausführungseinheiten, nicht auf einer.
Messrauschen
Ein Lauf auf derselben Codebasis ergab 52 % statt 98 % für den unveränderten Arm „ohne Zerlegung" — ein Schwung von 46 Punkten ohne Codeänderung, bei erhöhter Systemlast. Die Zahlen oben stammen aus Läufen bei Last unter 1,5 und wurden reproduziert.
Wer diese Messung wiederholt, sollte die Systemlast mitschreiben. Eine Latenzmessung neben anderer Arbeit misst die andere Arbeit.
Drei verworfene Messläufe
Dieser Abschnitt steht hier, weil die Zwischenstände plausibel aussahen und falsch waren.
Lauf 1. „Nur mit Zerlegung erzeugt das Sprachmodell etwas." Sah aus wie der
gesuchte Beweis, war aber ein Artefakt: beide Vergleichsarme riefen ein
decoupled Modell unär auf und scheiterten daran — nicht am Scheduling. Die
Zerlegung war an den Aufrufweg gekoppelt; damit hätte die Zeile „ohne
Zerlegung" auch bei perfektem Scheduling null gezeigt. Behoben durch eine
eigene Konfigurationsangabe decoupled, unabhängig von cooperative.
Lauf 2. Danach erzeugte das Sprachmodell in keinem governten Arm etwas,
bei zurueckgestellt 0 und ausgehungert 0. Vermutet wurde die
Überlast-Zustandsmaschine. Falsch: die Zähler zeigten angenommen 910, also
exakt die Detector-Frames — die Anfragen hatten den Scheduler nie erreicht. Der
Generator rief nun in allen Armen den Stream-Endpunkt auf, und das Gateway
lehnt den ab.
Was daraus zu lernen ist. Ohne die Ablehnungszähler im Bericht war jede Erklärung eine Vermutung. Sie stehen jetzt drin. Eine Messung, die nur das Ergebnis zeigt und nicht, wo die Arbeit geblieben ist, lädt zum Raten ein.
Reproduzieren
# Vision-Server
docker run -d --name onetimer-triton --device nvidia.com/gpu=all \
-p 8000:8000 -p 8001:8001 -v $VISION:/models:ro --ipc=host \
nvcr.io/nvidia/tritonserver:26.06-py3 \
tritonserver --model-repository=/models --allow-client-shm=true
# Sprachmodell-Server
docker run -d --name onetimer-vllm --device nvidia.com/gpu=all \
-p 8010:8000 -p 8011:8001 -v $LLM:/models:ro --ipc=host \
nvcr.io/nvidia/tritonserver:26.06-vllm-python-py3 \
tritonserver --model-repository=/models
taskset -c 8-15 target/release/wp26