8274 lines
537 KiB
Markdown
8274 lines
537 KiB
Markdown
# Inferenz-Parität: Gesamtabgleich und Arbeitsliste
|
||
|
||
Stand: 2026-09-05. Arbeitsgrundlage, **keine Freigabe der Performance-Parität**.
|
||
|
||
## Sicherheitsunterbrechung 2026-09-09: WindowServer-Watchdog
|
||
|
||
Der direkte Lauf `cargo test --release qwen_mtplx -- --include-ignored
|
||
--test-threads=1` ist **nicht als bestanden belegt**. Der WindowServer-Bericht
|
||
von 18:13:56 +0200 identifiziert den Testprozess PID 47594 anhand der UUID
|
||
`2D808BE5-E020-377D-B945-CF7D23FC7BD3` mit 99,07 GiB Footprint. Aktiv war
|
||
`mtplx_connected_sparse_moe_matches_reference`, CPU-Tensorerzeugung in
|
||
`pattern_scaled`. WindowServer hing im Metal-/IOGPU-/AGX-Pfad und wurde nach
|
||
121 Sekunden ohne Check-in vom Watchdog beendet. Ein Zusammenhang mit diesem
|
||
Test ist sehr wahrscheinlich; der genaue Grund des Speicheranstiegs und ein
|
||
bestimmter fehlerhafter GPU-Kernel sind dadurch noch nicht bewiesen.
|
||
|
||
Die Schutzüberwachung von `model-eval` wurde durch den direkten Cargo-Aufruf
|
||
umgangen. Serielle Ausführung ist kein Speicherlimit. Historische direkte
|
||
GPU-Testbefehle in diesem Dokument sind daher keine sicheren Wiederholungsbefehle.
|
||
|
||
Der zusätzliche Rust-Launcher `test-supervisor` verwendet dieselbe ausgelagerte
|
||
`proc_pid_rusage`-Messung wie `model-eval` (`src/process_resources.rs`). Er startet
|
||
das **vorher gebaute Testbinary direkt**, prüft alle 100 ms Footprint und
|
||
Lifetime-Peak, beendet bei fehlender Prozessmessung und überwacht Start sowie
|
||
ausbleibende Ausgabe statt der Gesamtlaufzeit. Grenzen sind explizit; für die
|
||
isolierte Fehlerdiagnose zunächst 8192 MiB und 15 Sekunden Start/Fortsetzung.
|
||
Er ist kein Cargo-/Build-Supervisor: Speicherwerte gelten für den Testprozess,
|
||
nicht beliebige von einem Build erzeugte Prozessbäume. Ausgabe ist nur
|
||
Testfortschritt, kein Nachweis tatsächlich fortschreitender GPU-Arbeit.
|
||
|
||
Vorbereitung ohne GPU-Ausführung:
|
||
|
||
```sh
|
||
cargo build --release --offline --bin test-supervisor -j 1
|
||
cargo test --release --offline --bin ds4-server --no-run -j 1
|
||
```
|
||
|
||
Danach ausschließlich den vom Build ausgegebenen tatsächlichen Testbinary-Pfad
|
||
an `test-supervisor 8192 15 15 TEST_BINARY
|
||
mtplx_connected_sparse_moe_matches_reference` übergeben. Keine parallelen
|
||
GPU-Läufe. Die Speichergrenze ist ein extern geprüftes Abbruchbudget, keine
|
||
Garantie gegen kurzfristiges Überschießen oder einen nicht unterbrechbaren
|
||
Treiberfehler. Die unten genannten Leistungsmessungen werden nicht durch diese
|
||
diagnostischen Grenzen oder Instrumentierung ersetzt.
|
||
|
||
Der betroffene Test meldet vor Gewichtsaufbau, nach Aufbau, nach Verifikation
|
||
und nach Freigabe Prozess-Footprint, Metal-Allokation sowie aktive/gecachte
|
||
Allocator-Bytes. Cache, Kernel, Power und Chunkgröße bleiben unverändert.
|
||
Zusätzlich ist bei Bedarf der vorhandene `DS4_METAL_TRACE_ALLOCS`-Pfad nutzbar.
|
||
|
||
Fortsetzung:
|
||
|
||
- Wächter ohne GPU verifizieren: Speicherabbruch, Start-/Fortsetzungsabbruch,
|
||
Exitfehler und erfolgreiche Fortsetzung über die Timeoutfenster hinaus.
|
||
CPU-Selbsttest am 2026-09-09 bestanden (1 Test, fünf Szenarien, 1,66 s).
|
||
- Erst danach den Speicheranstieg mit isoliertem, überwachtem MoE-Test messen;
|
||
anhand der vier Grenzwerte aktive Puffer, Cache und übrigen Footprint trennen.
|
||
- Belegte Ursache im Besitz-/Freigabepfad beheben und Referenzsemantik prüfen.
|
||
Kein Cache-Leeren oder künstliches Verkleinern als Ersatz für die Diagnose.
|
||
- Vollständige Qwen-Integration und P16 bleiben offen, ebenso die gesamte
|
||
Abnahme aller drei Modelle mit/ohne spekulatives Decoding innerhalb 2 %.
|
||
|
||
### Reproduktion und belegte Ursache, 2026-09-09
|
||
|
||
Rohdaten: `local-eval-results/moe-memory-20260909.UvC1wv/`.
|
||
Der Sandbox-Versuch (`test.*.log`) scheiterte vor Ausführung mit „Metal device
|
||
not available“; alle folgenden Metal-Tests liefen mit freigegebenem Metal-Zugriff
|
||
und dem externen Wächter. Kein Modell wurde geladen oder heruntergeladen.
|
||
|
||
- Vor Korrektur (`gpu.*.log`): der einzelne ursprüngliche MoE-Test erreicht
|
||
nach 1,606 s den Speicherabbruch, gemessener Footprint 9.037.880.280 Bytes
|
||
bei einem Budget von 8.589.934.592 Bytes. Das zeigt auch das mögliche
|
||
Überschießen zwischen den 100-ms-Abfragen. Bereits der alte Encoderpfad
|
||
akkumuliert Metal-Speicher; der kanonische Allocator ist noch nicht aktiv.
|
||
- Zusätzliche vorhandene Allokationsspur (`trace.*.log`, 1-GiB-Budget):
|
||
Rust/native Tensor-Freigaben bringen den Tensor-Livezähler auf null, während
|
||
`MTLDevice.currentAllocatedSize` weiter wächst. Kein fehlendes Rust-`drop`,
|
||
kein MTPLX-Allocator-Cache und kein einzelner großer Kernel ist hierfür nötig.
|
||
- Minimaler Test `mtplx_tensor_cpu_access_releases_native_storage`, **ohne
|
||
GPU-Dispatch** (`cpu-red.*.log`): acht 1-MiB-Allokationen pro Zugriffsart.
|
||
Schreiben, Lesen und `contents` halten jeweils exakt 8.388.608 Bytes über
|
||
die Tensor-Freigabe hinaus. Anlegen/Freigeben ohne Zugriff, Views,
|
||
Allocation-Identität und Heap-Abfrage halten jeweils 0 Bytes zurück.
|
||
|
||
Ursache: `MTLBuffer.contents` liefert einen Interior-Pointer. Der mit ARC
|
||
kompilierte Objective-C-Bridgecode erzeugt dafür `objc_retainAutorelease`;
|
||
die zusätzliche Referenz bleibt auf einem Rust-Thread ohne passenden Pool-Drain
|
||
erhalten. Der erzeugte Maschinencode der drei Zugriffe wurde geprüft.
|
||
Der gepinnte MTPLX-Unterbau ruft `Buffer::raw_ptr()` dagegen über Metal-C++
|
||
auf (`mlx/backend/metal/allocator.cpp:25`) und hat diesen ARC-Zusatz nicht.
|
||
Clang dokumentiert genau diese implizite Lebensdauerverlängerung und ihre
|
||
Vermeidung durch einen präzise lebenden starken Empfänger:
|
||
[ARC Interior pointers](https://clang.llvm.org/docs/AutomaticReferenceCounting.html#interior-pointers).
|
||
|
||
Korrektur in `native/metal/ds4_metal.m`: gemeinsamer
|
||
`ds4_gpu_tensor_cpu_data`-Zugriff mit `objc_precise_lifetime` für die temporäre
|
||
`MTLBuffer`-Referenz. Der ausdrücklich gehaltene Tensor bleibt Eigentümer des
|
||
Speichers. `contents`, Read, Write und mittelbar Fill benutzen denselben Pfad.
|
||
Keine neue Pool-Schleife, keine GPU-Synchronisation, kein Cache-Leeren und keine
|
||
Änderung von Kernel, Power, Chunkgröße oder Referenz-Testformen. Die Brücke
|
||
wird auch im Produkt/UI verwendet, nicht nur unter `cfg(test)`.
|
||
|
||
Nach Korrektur:
|
||
|
||
- Identischer Minimaltest (`cpu-green.*.log`) bestanden: alle sieben
|
||
Zugriffsarten jeweils **0 Bytes** zurückgehaltener Metal-Speicher.
|
||
Im Maschinencode fehlt nun `objc_retainAutorelease` in den drei Zugriffen;
|
||
das davon verschiedene `objc_retainAutoreleasedReturnValue` bleibt korrekt.
|
||
- Ursprünglicher MoE-Test (`fixed.*.log`), unverändertes 8-GiB-/15-s-Budget:
|
||
**440 exakte Referenzvergleiche**, 220 je Encoder, abgeschlossen in 13,322 s.
|
||
Peak-Footprint 4.839.182.320 Bytes (4,51 GiB). Nach jedem der 220 alten
|
||
Encoderfälle genau 1.769.472 Bytes Metal-Basisbelegung. Im kanonischen
|
||
Encoder nach Freigabe 0 aktive Allocator-Bytes; am Ende 3.202.034.186 Bytes
|
||
regulärer Cache. Dieser Cache wurde nicht künstlich geleert.
|
||
- Originalquellprüfung bestanden: 17 Körper, 41 Custom-Einstiegspunkte,
|
||
22 Runtime-Einheiten / 203 Einstiege plus dynamische QSA-Quellen stimmen
|
||
mit dem gepinnten Export überein.
|
||
- Alle drei Puffer-Eigentumstests bestanden (`ownership.*.log`, 0,08 s):
|
||
Completion hält Allokationen ohne Data-Donation zu verändern, leere
|
||
Tensoren/Views behalten ihre Identität, CPU-Zugriffe behalten keinen Speicher.
|
||
Release-Testbuild, warnings-denied Clippy für App und Tests sowie
|
||
`cargo fmt --all -- --check` und `git diff --check` bestanden.
|
||
|
||
Dies behebt die reproduzierte Retention, ist aber **keine** abgeschlossene
|
||
UI-Responsiveness- oder 2%-Performance-Abnahme. Ein vollständiger neuer
|
||
UI-/Harness-/Golden-Master-Vergleich und die übrige Qwen-Portierung bleiben offen.
|
||
|
||
## Verbindliche Auftragspräzisierung vom 2026-09-06
|
||
|
||
Die bisherige Auswahl einzelner Optimierungen anhand von Mikrobenchmarks wird
|
||
beendet. Der Nutzer verlangt für Qwen einen vollständigen MTPLX-Port, keine
|
||
Sammlung ähnlich wirkender Rust-/Metal-Optimierungen. Diese Präzisierung hat
|
||
Vorrang vor früheren Auswahl- und Rücknahmebegründungen in diesem Dokument.
|
||
|
||
- **Kernel-Identität:** Die im gepinnten MTPLX-Qwen-Pfad tatsächlich verwendeten
|
||
Metal-Kernel übernehmen, einschließlich der von dessen gepinnten Abhängigkeiten
|
||
bereitgestellten Kernel. Gleiche Typen, Layouts, Spezialisierungen, Geometrien,
|
||
Rundungs-/Reduktionsfolgen und Dispatch-Bedingungen. Eigenständige MPP-QMM-
|
||
Implementierungen sind kein Ersatz für die von MTPLX aufgerufenen Kernel,
|
||
auch wenn einzelne Ausgabehashes passen. Nur erforderliche ABI-/Binding-
|
||
Anpassungen separat ausweisen; keine stillen algorithmischen Änderungen.
|
||
- **Rust-Funktionsidentität:** Modellaufbau, Materialisierung/Fusion, Graphfolge,
|
||
PLE-Streaming, Cache-/State-Lebenszyklus, Scheduling, Sampler, MTP-Draft/Verify/
|
||
Commit/Repair sowie EOS/Cancel und Fortsetzung vollständig nachbilden. Dazu
|
||
gehören alle für das vorhandene Modell erreichbaren Form- und Fallbackzweige,
|
||
nicht nur die von drei Beispielprompts zufällig ausgeführten Pfade.
|
||
- **Zusammenhängende Umsetzung:** P01–P12 sind Abdeckungs- und Portierungsaufgaben,
|
||
keine optionalen Optimierungskandidaten. Zuerst deren vollständige Referenz-
|
||
Zuordnung und Umsetzung samt Korrektheits-/State-Tests. Anschließend den
|
||
integrierten Stand gegen MTPLX auf Gesamtlaufzeit, Durchsatz und Verzögerungen
|
||
prüfen. Kein erneuter Performance-Auswahlzyklus nach jedem Kernel.
|
||
- **Rücknahmen:** Ein isoliert fehlender Geschwindigkeitsgewinn ist kein
|
||
Rücknahmegrund für einen korrekten Referenzport. Nur belegte harte Regressionen
|
||
rechtfertigen eine begründete Rücknahme; der betroffene Referenzbestandteil
|
||
bleibt dann ausdrücklich unerledigt. Ein Eigenbau-Experiment zurückzunehmen
|
||
beweist nicht, dass die entsprechende MTPLX-Implementierung verzichtbar ist.
|
||
- **Abnahme:** Erst vollständige funktionale und Kernel-Abdeckung, dann P16 mit
|
||
den vereinbarten vollständigen Chats und Referenzvergleichen. DeepSeek/GLM
|
||
behalten antirez/ds4 als Golden Master und bleiben Teil des Gesamtziels.
|
||
|
||
Insbesondere werden die früheren negativen Einzelversuche zu P07 (Gate/Up-
|
||
Fusion), P09 (Matmul-Layouts) und P11 (lazy Target-Verteilungen) **nicht** als
|
||
Freistellung von der entsprechenden MTPLX-Funktionalität verwendet. Historische
|
||
Messbelege bleiben erhalten, entscheiden aber nicht über den Umfang des Ports.
|
||
|
||
### Quellzuordnung für die zusammenhängende Qwen-Portierung
|
||
|
||
Dies sind geprüfte Einstiegspunkte, noch keine vollständige Kernel-Abdeckung.
|
||
Für jeden Bereich ist die transitive Zuordnung bis zum tatsächlichen Kernel
|
||
einschließlich aktivierter Laufzeit-/Formbedingungen zu schließen. Ein Import
|
||
allein oder ein gesetztes Flag gilt nicht als Dispatch-Nachweis.
|
||
|
||
| Bereich / bestehender Task | MTPLX-Einstieg | Verbindlicher Umfang |
|
||
| --- | --- | --- |
|
||
| Modell / Laden / Typen · P01/P09 | `models/qwen4_exp.py`: `TextModel`, `Qwen4ExpTextModel`, Sanitize-Fusionen | Gewichte, BF16-Aktivierungen, FP32-Zustände, zusammengeführte Projektionen, Views und Lebensdauer |
|
||
| Hyper-Connections · P09 | `GatedResidual`, `kernels/hyper_connection_v3.py`, `hyper_connection.py` | R1/R2, vorbereitete Quantisierung, Prefill- und Fallbackpfade, nicht nur Decode |
|
||
| Affine / Gather / Sorted Matmul · P07/P09 | `_FusedGDNInProj`, `_FusedGateUpSwitchGLU`, `_FusedGateUpMLP`; deren tatsächlich aufgerufene Quantized-Matmul-Kernel | QMV/QMM/NAX/Split-K, Gather/Sort/Unsort, gemeinsame Gate/Up-Projektionen, Typ-/Formgrenzen |
|
||
| GDN · P06 | `GatedDeltaNet.__call__`, `kernels/gdn_step_fused.py`, `gdn_conv_norm.py`, `gdn_out_fused.py`; `gated_delta_update` aus der gepinnten Abhängigkeit | Vollständige Branchfolge, Conv-/Delta-Zustände, Capture-Tape, Norm/Gate, Prefill/Decode/Verify |
|
||
| MoE / Shared Expert · P07 | `SparseMoeBlock`, `_FusedGateUpSwitchGLU`, `_FusedGateUpMLP`, `kernels/moe_glu_decode.py` | Router, Top-k, Sortschwelle, fusionierte Decode-/Verify- und Prefillpfade, Shared-Expert-Kombination |
|
||
| QSA / KV / Attention · P08 | `Attention`, `QSAIndexer`, `QSACache`, QSA-Kernelmodule und tatsächlich selektierter Attention-Backendpfad | Cache-Layout, Pooling/Indexer/Top-k/Masken, Dense-/Sparse-/Gather-/Flashzweige, Kontextgrenzen |
|
||
| PLE · P10 | `NGramTable`, `_SidecarGather`, `NGramEmbedding`, `PLELayer` | Hashing, Vorab-Staging, LRU/Bypass, Gather-/IO-Reihenfolge, Faltung und History |
|
||
| Serving / Sampling / MTP · P02–P05/P11/P12 | `server/openai.py`, `sampling.py`, Modell-Capture und aufgerufene Generator-/Backendmodule | Tokenisierung, laufender Chat, RNG/Verteilungen, Draft/Verify, Commit/Repair, Cache, Submission und Abschluss |
|
||
|
||
Der bestehende Rust-Pfad in `src/engine/metal/qwen.rs` und die Kernel in
|
||
`metal/qwen38.metal` sind gegen diese gesamte Kette zu ersetzen/anzugleichen.
|
||
Die Referenz bleibt MTPLX; seine verwendeten Bibliothekskernel sind Bestandteile
|
||
dieser Referenzausführung, kein Wechsel zu einem anderen Golden Master.
|
||
|
||
### Portierungsstand: unveränderte Kernelkörper und direkte Bindung
|
||
|
||
2026-09-06: `metal/mtplx_qwen.metal` enthält erstmals direkt extrahierte,
|
||
unveränderte MTPLX-Kernelkörper, nicht nachgeschriebene Äquivalente.
|
||
`tools/mtplx-kernel-source.py` prüft den sauberen Referenzcommit und erzeugt
|
||
die deterministische Übersetzungseinheit. `--check` vergleicht die gesamte Datei;
|
||
ein gewöhnlicher Rust-Test schützt zusätzlich die neun eingebetteten Körperhashes.
|
||
Nur Einstiegspunkt-ABI und Templatespezialisierungen sind außerhalb der Körper
|
||
ergänzt. BF16 ist physisch BF16, der RMS-/Delta-Zustand bleibt wo vorgesehen FP32.
|
||
|
||
| MTPLX-Körper | Eingebundene Spezialisierungen | Korrektheitsbeleg | Produktgraph |
|
||
| --- | --- | --- | --- |
|
||
| `hyper_connection._SOURCE` | BF16, Injection0/1 | Zeilen1/4/8, Ausgabehashes exakt | Umstellung offen |
|
||
| `hyper_connection_v3._SRC_R1` / `_SRC_R2` | BF16, RMS FP32 | Gekoppelte R1/R2-Ausgabe exakt | Umstellung offen |
|
||
| `gdn_conv_norm._SRC` | BF16 | q/k/v und Folgezustand exakt | Umstellung offen |
|
||
| `gdn_conv_norm._SRC_ROWS` | BF16, S2–6 | Alle fünf Breiten, q/k/v und Folgezustand exakt | Umstellung offen |
|
||
| `gdn_step_fused._SRC` | BF16, Rekurrenz FP32 | Zwei aufeinanderfolgende Schritte einschließlich beider Folgezustände bitgenau | Umstellung offen |
|
||
| `gdn_out_fused._SRC` | Gruppen32/64, x BF16/FP32, Quantparameter BF16 | Alle vier Kombinationen bitgenau, synthetische gültige Q4-Packs | Umstellung offen |
|
||
| `mlx_lm 0.31.3/models/gated_delta.py` · skalare Rekurrenz | BF16 q/k/v/beta, FP32 g/Zustand; mit/ohne Maske | S1/4/7/32/2048, Ausgabe und FP32-Folgezustand bitgenau | Umstellung offen |
|
||
|
||
Die Metal-Bibliothek lädt diese 17 Einstiegspunkte. Die neue direkte Bridge
|
||
bindet geordnete Ein-/Ausgabepuffer ohne eigenes Qwen-Argumentlayout, Typcasts,
|
||
automatische Geometrieänderung oder zusätzliche Flushes. Ihre Bindungs-/Grid-
|
||
Konvention wurde gegen den
|
||
[gepinnten CustomKernel-Dispatcher](https://raw.githubusercontent.com/ml-explore/mlx/v0.32.2/mlx/backend/metal/custom_kernel.cpp)
|
||
geprüft; das ist MTPLXs benutzte Runtime, kein anderes Modell-Orakel.
|
||
R1/R2 samt Packvorbereitung bleiben im Test nachweislich in einem Command Buffer.
|
||
Der vorhandene Stage-Profiler verwendet für alte/neue Aufrufe dieselbe
|
||
Erfassungsfunktion. Allgemeine Submission-/Ressourcenparität P05 bleibt offen.
|
||
|
||
`tools/mtplx-kernel-fixtures.py` ruft die tatsächlichen MTPLX-Funktionen mit
|
||
modellfreien deterministischen Eingaben auf. Die 29 geprüften Fälle mit 65
|
||
Ausgabehashes stehen in
|
||
`tests/fixtures/mtplx-custom-kernels.jsonl`. GPU-Test und CPU-Quellhash-Test
|
||
bestanden; keine Benchmarks oder vollständigen Modellläufe. Apache-Lizenz und
|
||
NOTICE mitgeliefert; Attribution im CLI und verlinkt in den Modelleinstellungen.
|
||
|
||
**Keine Fertigmeldung:** Der Inferenzgraph ruft derzeit weiterhin die alten
|
||
Kernel auf; die direkte ABI wird bisher vom Korrektheitstest genutzt. Die
|
||
zusammenhängende Umstellung der Aktivierungen und Graphaufrufe auf BF16 sowie
|
||
die übrigen MTPLX-Kernel und Rust-Funktionen sind weiterhin umzusetzen. Kein
|
||
FP32/BF16-Konvertierungsadapter wurde als vermeintlich fertiger Port eingeführt.
|
||
Diese Grundlage ist keine Performance- oder Gesamtparitätsabnahme.
|
||
|
||
Die Rekurrenzquelle stammt aus MTPLXs tatsächlich installiertem `mlx-lm 0.31.3`,
|
||
SHA256 `79c8376a51c694b03e54d2f996ced6ea6c8c42868b8571529f97334db165a3e1`.
|
||
Der Exporter wertet ausschließlich die String-/F-String-AST aus, nicht den
|
||
Python-Modellcode. Die tatsächlich generierte Referenzsignatur wurde separat
|
||
mit `verbose=True` geprüft: Skalar `T` als `constant int32_t&`, Grid32×128×48,
|
||
Threadgroup32×4×1. Ihre MIT-Lizenz ist mitgeliefert. Der FP32-Zustand wird im Test
|
||
nicht auf BF16 reduziert; die bisherigen 19 Fixture-Zeilen blieben unverändert.
|
||
|
||
Für die folgenden Matmul-Ports ist nun auch die **exakte Runtime-Quelle0.32.2**
|
||
lokal vorhanden: `local-eval-results/mtplx-runtime-0.32.2`, Commit
|
||
`1f8e74e3f12f31365464a6867c6579f0e9b29d85`. `quantized.h` stimmt byteweise mit
|
||
dem installierten Referenzheader überein. Die ältere Navigation über die lokale
|
||
0.32.3-Kopie ist keine Portierungsfreigabe. Der unveränderte Upstream-Generator
|
||
`make_compiled_preamble.sh` scheitert innerhalb und außerhalb der Sandbox an der
|
||
fehlenden separaten Metal-Toolchain; die Metal-Laufzeitkompilierung funktioniert.
|
||
Keine Toolchain installiert, kein Host-C/C++-Backend gebaut, keine Modelle geladen.
|
||
Die Runtime enthält außerdem ihre vorhandene `mlx.metallib`; deren Nutzung oder
|
||
quellidentische Neuerzeugung war zu diesem Zeitpunkt noch offen. Der folgende
|
||
Abschnitt dokumentiert die inzwischen geprüfte direkte Shader-Nutzung.
|
||
|
||
### Runtime-Shader und verbundener BF16-GDN-Abschnitt
|
||
|
||
Die installierte Runtime wurde nicht nur anhand der Versionsnummer eingeordnet:
|
||
`get_quantized_kernel` in ihrer tatsächlichen `libmlx.dylib` ruft direkt
|
||
`Device::get_kernel` für die vorgefertigte Standardbibliothek auf (Disassembly
|
||
bei0xd8af40). Das entspricht `nojit_kernels.cpp` der gepinnten0.32.2-Quelle.
|
||
Die dort vorhandene Shader-Datei ist deshalb **byteidentisch** als
|
||
`metal/mtplx-runtime-0.32.2.metallib` übernommen; SHA256
|
||
`dc59d1cceb1a5c7e578232e6e41e28e2c73c9463ac6dbc3886c3ee17ffc270ed`,
|
||
182351120Bytes. Kein C/C++-Backend wird eingebunden. Lizenztext und Herkunft
|
||
stehen in `metal/MLX-LM-LICENSE.txt` und `metal/MTPLX-RUNTIME.txt`.
|
||
Die vorhandene Ressourcenverpackung nimmt die Datei mit auf; die Metal-Bridge
|
||
lädt sie erst beim ersten entsprechenden Dispatch. Keine Toolchain-Installation.
|
||
|
||
`src/engine/metal/qwen_mtplx.rs` enthält jetzt die direkten Rust-Aufrufe für
|
||
kontiguierliche, nicht gebatchte BF16-Affine-Projektionen auf dem M5Max:
|
||
|
||
- Referenzgrenzen33/25/13 nach Matrixdimension, QMV-Quad, normale/schnelle QMV,
|
||
QMV-Wide inklusive Referenz-Tiling statt einer eigenen Zeilenheuristik.
|
||
- QMM, NAX und Split-K einschließlich **BF16**-Teilresultaten und den originalen
|
||
ein-/zweistufigen Reduktionskerneln. Integerparameter über `setBytes`, explizite
|
||
3D-Threadgroups; keine CPU-Reduktion oder Typkonvertierung.
|
||
- 78 gegen tatsächliche `mx.quantized_matmul`-Aufrufe erzeugte Fälle bitgenau:
|
||
Bits4/8, Gruppen32/64, Randgrößen, Variantengrenzen, beide Reduktionsstufen,
|
||
NAX-/Steel-Pfade und 2048Zeilen. Diese Runtime-Aufrufe sind Bestandteile der
|
||
MTPLX-Referenz, keine Änderung des Modell-Orakels.
|
||
- Verbundener GDN-Decode-Abschnitt: fusionierte Eingangsprojektion → originaler
|
||
GDN-Step → Ausgangsprojektion, native BF16-Views und getrennte neue Conv-/Delta-
|
||
Zustände. Zwei Folgeschritte stimmen vollständig mit dem tatsächlichen
|
||
`GatedDeltaNet.__call__` aus MTPLX überein. Der Referenztest prüft ausdrücklich
|
||
dessen Live-State-Branch; Kaltstart/Prefill/Verify sind damit nicht abgenommen.
|
||
Jeder Rust-Schritt verbleibt nachweislich in einem Command Buffer.
|
||
|
||
Die direkte Bridge hält Datenbindung und Pipeline-Bool-Konstanten getrennt,
|
||
prüft ungültige/überlappende Bindungen und verwendet die bestehenden Metal-
|
||
Command- und Profiling-Funktionen. Temporäre Projektions-/Split-Puffer bleiben
|
||
im Rust-Ergebnis bis zum Abschluss des Command Batches erhalten.
|
||
|
||
**Produktstatus unverändert offen:** Das neue Rust-Operationsmodul ist bis zur
|
||
zusammenhängenden BF16-Graphmigration ausdrücklich unter `cfg(test)` eingebunden.
|
||
Es ersetzt noch nicht den alten FP32-Inferenzgraphen. Es ist kein zweiter
|
||
Generator und keine abweichende Headless-Engine. MoE/Gather/Sort, QSA/Attention,
|
||
PLE, komplette GDN-Fallback-/Capture-Pfade sowie Sampling/MTP und der gemeinsame
|
||
Zustands-/Scheduling-Port sind weiterhin umzusetzen. Kein P01–P16 geschlossen,
|
||
keine Geschwindigkeitsmessung, Bundle-Auslieferung oder Paritätsabnahme.
|
||
|
||
Die Fixture-Datei enthält nun insgesamt 571 Fälle mit 797 Ausgabehashes. Die bisherigen
|
||
546 Fälle blieben beim ergänzenden Normmodul-Nachweis unverändert. Zusätzliche
|
||
CPU-Tests prüfen den Shader-Dateihash und die Rust-Dispatch-Grenzen.
|
||
|
||
### Gather-Dispatch: geprüfter Portabschnitt, keine Produktabnahme
|
||
|
||
`qwen_mtplx::gather_bf16` bildet den normalisierten BF16-Gather-Pfad in Rust ab:
|
||
QMV normal/fast, Gather-QMM Steel/NAX sowie sortiertes RHS-QMM mit den originalen
|
||
Bool-Konstanten200/201/202. Es benutzt ausschließlich die unveränderte gepinnte
|
||
Runtime-Metallib. MTPLX sortiert ab64Routen; der Backendwechsel zum sortierten
|
||
RHS-Kernel erfordert separat M=1, mindestens16Routen und Routen/Experten>=4.
|
||
Die NAX-RHS-Tilehöhe wechselt bei Routen/Experten=64 von32 auf64. Diese Bedingungen
|
||
sind keine lokalen Performance-Heuristiken. GPU-Sortierung und Rücksortierung
|
||
sind dadurch ausdrücklich noch nicht implementiert.
|
||
|
||
40 echte `mx.gather_qmm`-Referenzaufrufe prüfen Q4/Q8, Gruppen32/64, allgemeine
|
||
und sortierte Indizes, die Schwellen unmittelbar darunter/darüber, N-Ränder sowie
|
||
512Experten. Alle40Ausgaben sind bitgenau. Der gemeinsame fokussierte Lauf
|
||
führte7Tests aus:7bestanden,0fehlgeschlagen,0ignoriert;149GPU-Fälle/189Hashes.
|
||
|
||
**Referenzfehler im künstlichen K-Randfall:** Bei sortiertem
|
||
X=33,M=1,N=81,K=160,E=8,R=33 liest der gepinnte NAX-RHS-Kernel über logische
|
||
Tensorgrenzen. Bereits MTPLX allein liefert bei unveränderten logischen Eingaben
|
||
andere Ergebnisse, wenn nur nachfolgender Speicher geändert wird. In
|
||
`quantized_nax.h:1659` wird die letzte A-Tilebreite aus BK statt k_remain gebildet;
|
||
Eingangs-Padding allein genügte im gesamten Fixture-Lauf nicht, erst kontrollierte
|
||
physische Grenzen auch für W/Skalen/Biases machten beide Ausführungen identisch.
|
||
Die zwei betroffenen Q4/Q8-Fälle sind deshalb mit explizitem Nullpadding in beiden
|
||
Testläufern enthalten, nicht übersprungen oder toleranzgeweitet. Die übrigen
|
||
38Gather-Ausgabehashes blieben unverändert. Originalkernel und Produktionspuffer
|
||
wurden nicht geändert. Diese synthetische K=160-Form ist keine MoE-Form des
|
||
installierten Modells (K=2560 bzw.640). Beleg und ursprüngliche Hashes stehen in
|
||
`local-eval-results/20260906-mtplx-port/gather-padding-investigation.md`.
|
||
|
||
Der Produktgraph bleibt unverändert offen; diese Checks ersetzen weder die
|
||
MoE-Kette noch die sechs abschließenden Gesamtmessungen.
|
||
|
||
### GPU-Argsort und inverse Reihenfolge
|
||
|
||
Der normalisierte Rust-Argsort für zusammenhängende letzte Achsen verwendet die
|
||
originalen Runtime-Kernel für U32-, BF16- und FP32-Eingaben. Die Referenz führt
|
||
auch `argpartition` als vollständigen Sort aus. Übernommen sind die Auswahl der
|
||
32/64/128/256/512-Thread-Blöcke, Vierer-Tiles, Mehrblock-Sortierung mit Werte- und
|
||
Index-Pingpong, Partition/Merge-Reihenfolge und der abschließende Original-Copy.
|
||
Die Copy-Variante wechselt bei65536Elementen von1 auf2Elemente pro Thread.
|
||
Die Metal-Bindung unterstützt dafür zusätzlich `dispatchThreads`; aufgerundete
|
||
Threadgroups wären bei diesem ungeschützten Copy-Kernel nicht funktionsidentisch.
|
||
Bestehende Matmul-/Gather-Aufrufe verwenden weiter unverändert Threadgroups.
|
||
|
||
123 echte Referenzaufrufe prüfen jeweils `argsort(x)` und `argsort(order)`:
|
||
20Breiten von1 bis65537 bei1/3Zeilen, dazu2048x512; jeweils U32/BF16/FP32.
|
||
Die Daten enthalten gleiche Werte, auch durch BF16-Rundung entstandene Gleichstände.
|
||
Alle246Index-Hashes sind bitgenau. Beide zusammenhängenden Sortierungen samt
|
||
Merge-/Copy-Schritten bleiben in jedem Rust-Test in genau einem Command Buffer;
|
||
kein CPU-Auslesen zwischen den Sortierungen. Der gemeinsame Lauf hat8Tests
|
||
ausgeführt:8bestanden,0fehlgeschlagen,0ignoriert,272Fälle/435Ausgabehashes.
|
||
Rohbeleg: `local-eval-results/20260906-mtplx-port/runtime-sort-combined-check.log`.
|
||
|
||
Damit ist die inverse **Indexreihenfolge** geprüft, nicht schon die vollständige
|
||
`_gather_sort`-/`_scatter_unsort`-Datenbewegung. Deren Division/Gather-Front-Aufrufe,
|
||
die verbundene MoE-Kette und die übrige Produktgraphmigration bleiben offen.
|
||
Keine Gesamtperformance-Abnahme, kein P01–P16 geschlossen.
|
||
|
||
### Verbundene Sort/Gather/Unsort-Datenbewegung
|
||
|
||
Die zuvor offene Datenbewegung ist nun als zusammenhängender Rust-Abschnitt
|
||
implementiert: Experten-Argsort, inverse Reihenfolge, `order // top_k`, Gather
|
||
der BF16-Tokenzeilen und U32-Expertenindizes, anschließend Gather über die inverse
|
||
Reihenfolge für die Rücksortierung. Keine CPU-Auswertung der erzeugten Indizes.
|
||
Die Sortschwelle gehört weiterhin in den noch zu verbindenden MoE-Aufrufer.
|
||
|
||
MTPLXs Runtime erzeugt den Gather-Front-Kernel aus `indexing/indexing.h` und
|
||
`indexing/gather_front.h` zur Laufzeit. Diese Shader-Einheiten werden jetzt mit
|
||
gepinnten Datei- und Einheitshashes unverändert in die vorhandene kanonische
|
||
Quelldatei exportiert; nur Includes werden aufgelöst und Instanziierungen ergänzt.
|
||
Keine C++-Hostimplementierung übernommen. Die bestehende Bindung kann diese
|
||
Shader mit unmittelbaren Größen-/Stride-Parametern aufrufen und behält originale
|
||
`dispatchThreads`-Geometrie und Zwei-Elemente-Grenze bei BF16-Slicegröße>8 bei.
|
||
Die ganzzahlige Division nutzt die unveränderte Runtime-Metallib mit dem
|
||
Referenzwechsel der Arbeit pro Thread bei65536Elementen.
|
||
|
||
Sieben direkte Aufrufe der tatsächlichen MTPLX-Helfer `_gather_sort` und
|
||
`_scatter_unsort` sind mit vier Ausgaben pro Fall geprüft: sortierte Daten,
|
||
Expertenindizes, inverse Reihenfolge und zurücksortierte Daten. Fälle:1/6/7/205/
|
||
2048/6554Tokens bei Top-10, Breiten7/8/9/2560, darunter2048x10x2560 und eine
|
||
65540-Routen-Kette. Alle28Hashes sind bitgenau. Jede gesamte Rust-Kette bleibt in
|
||
einem Command Buffer. Der gemeinsame Lauf führt9Tests aus:9bestanden,0Fehler,
|
||
0ignoriert;279Referenzfälle/463Hashes. Alle bisherigen272Fixture-Zeilen waren
|
||
bei frischer Referenzerzeugung unverändert. Der Quellvergleich prüft außerdem
|
||
die9Custom-Bodies/17Einträge sowie2Runtime-Einheiten/8Gather-Instanziierungen;
|
||
die geketteten Tests betreffen BF16/U32 mit32-Bit-Offsets, nicht alle8Varianten.
|
||
|
||
Beleg: `local-eval-results/20260906-mtplx-port/connected-gather-combined-check.log`.
|
||
**Weiter offen:** verbundene Gate/Up-Aktivierung/Down-MoE-Kette, Router/Shared-
|
||
Expert-Integration, die übrigen Graphabschnitte und die vollständige BF16-
|
||
Produktmigration. Keine Performance-Abnahme oder Änderung der Abschlusskriterien.
|
||
|
||
### Verbundene SwitchGLU-Rechenkette und tatsächlicher SiLU-JIT-Code
|
||
|
||
`qwen_mtplx::switch_glu` bildet jetzt den vollständigen Aufruf von
|
||
`_FusedGateUpSwitchGLU` mit bereits ausgewählten Experten ab: Sortierung ab64Routen,
|
||
gemeinsame Gate/Up-Gather-Projektion, `nn.silu(gate) * up`, Down-Gather-Projektion
|
||
und Rücksortierung. U32-Arange und Broadcast-Strides erhalten die implizite
|
||
Token-/Expertenzuordnung; kein zusätzliches Materialisieren broadcasteter
|
||
Tokenindizes, kein CPU-Auslesen erzeugter Indizes. Aktivierungen bleiben BF16.
|
||
Temporäre Puffer werden bis zum Abschluss des zusammenhängenden GPU-Batches gehalten.
|
||
|
||
Der SiLU-Code wurde nicht anhand seiner Formel neu geschrieben:
|
||
`tools/mtplx-jit-reference.py` beobachtet im isolierten Referenzprozess den
|
||
originalen Objective-C-Metal-Compileraufruf, leitet ihn unverändert weiter und
|
||
setzt den lokalen Beobachtungs-Hook abschließend zurück. Der gespeicherte
|
||
JIT-Receipt `tests/fixtures/mtplx-silu-jit.json` enthält alle19erzeugten Varianten.
|
||
Vollständiger beobachteter Compiler-Quellhash:
|
||
`76cafb45db55a91efba66503dde59b37628ea360f220f35dd860f4ac3c3d0111`.
|
||
Die Rank-2-Erzeugung wurde erneut exakt bestätigt; Rank3/5 der sortierten und
|
||
unsortierten SwitchGLU erzeugen nach Normalisierung der Symbolnamen denselben
|
||
Rechencode. Keine Rechenanweisung wird durch diese Normalisierung geändert.
|
||
|
||
Der bestehende Shader-Exporter übernimmt diese19Varianten sowie ihre originalen
|
||
BF16-Mathematik-, Sigmoid-, Multiply-, Cast- und Stride-Helfer mit gepinnten
|
||
Dateihashes. Nur die Hostnamen erhalten lokale Aliasse. Das ist Shadercode,
|
||
kein übernommener C++-Hostcode. Die Rust-Auswahl erhält Contiguous/Strided-Pfade,
|
||
die65536-Elemente-Grenze und den separaten ursprünglichen Up-Multiply-Dispatch.
|
||
Der Quellcheck umfasst nun9Custom-Bodies/17Einträge sowie8Runtime-Einheiten mit
|
||
27Runtime-Einträgen (8Gather,19SiLU).
|
||
|
||
Nachweise:10Aktivierungsfälle mit zwei Ausgaben, darunter20480x640 und die
|
||
Vektorisierungsgrenzen;21direkte Aufrufe der tatsächlichen MTPLX-SwitchGLU-Klasse
|
||
mit synthetischen Q4-Gewichten, Gruppen32/64/gemischt. Ganze Ketten bei1/6/7/205/
|
||
2048Tokens mit K2560/I640/E16 sowie7/205Tokens mit K128/I64/E512. Alle41neuen
|
||
Ausgabehashes bitgenau; jede Rust-Kette ein Command Buffer. Der gemeinsame Lauf:
|
||
11Tests ausgeführt,11bestanden,0fehlgeschlagen,0ignoriert;310Fälle/504Hashes.
|
||
Beleg: `local-eval-results/20260906-mtplx-port/connected-switch-combined-check.log`.
|
||
Das ist keine Messung des vollständigen512Experten-Modells bei K2560.
|
||
|
||
**P07 bleibt offen:** Router/Softmax/Top-k, Gewichtung, Shared Expert und die
|
||
gesonderten fusionierten Decode-/Verify-Pfade von `SparseMoeBlock` sind nicht
|
||
durch den abgeschlossenen SwitchGLU-Untermodul-Nachweis abgedeckt. Auch die
|
||
übrigen Graphabschnitte, Produktintegration und Gesamtperformance-Abnahme bleiben
|
||
offen. Kein Rollback und keine Auswahl von Teiloptimierungen nach Geschwindigkeit.
|
||
|
||
### Verbundener Router und SparseMoeBlock einschließlich Decode/Verify
|
||
|
||
Der kanonische Rust-Port umfasst jetzt den Standard-MoE-Block mit den
|
||
Sanitize-fusionierten Expert-/Shared-Expert-Packs: Q8-Routerprojektion,
|
||
präzises BF16-Softmax über alle Experten, vollständiges Argpartition/Argsort,
|
||
Top-10-View, GatherAxis und optionale Normalisierung, SwitchGLU, gewichtete
|
||
BF16-Summe, Shared-MLP, Sigmoid-Gate und Addition. Der Top-10-Stride bleibt
|
||
erhalten; erst das originale Flatten vor Sortierung materialisiert ihn.
|
||
Unsortiertes GatherQMM verarbeitet ihn direkt. Keine CPU-Indizes oder
|
||
zusätzlichen Flushes/Wartepunkte innerhalb der verbundenen Kette.
|
||
|
||
Die vier unveränderten Kernelkörper aus `moe_glu_decode.py` sind zusätzlich
|
||
mit16BF16-Spezialisierungen eingebunden: Decode und Verify mit2/3/4Zeilen,
|
||
Gruppen32/64 für Gate-Up und Down unabhängig. Die beiden Referenzflags sind
|
||
standardmäßig aus; ihre aktivierten Zweige einschließlich BF16→FP32-Routengewichten,
|
||
Shared-Expert-Kombination und Rückfall bei mehr als4Zeilen sind im selben
|
||
Rust-Dispatcher portiert. Keine Auswahl anhand eines Teilbenchmarks.
|
||
|
||
- 16 Routerfälle mit 48 Hashes, einschließlich 2048x512 sowie 4096/4097-Softmaxgrenze.
|
||
- 48 vollständige Standard-MoE-Fälle gegen die tatsächliche MTPLX-Klasse.
|
||
- 64 weitere Klassenaufrufe mit beiden Fusionsflags aktiv: Decode/Verify,
|
||
Gruppenkombinationen und5/7-Zeilen-Fallback. Optionale Normalisierung jeweils an/aus.
|
||
- Modellabmessungen K2560/I640/E512 sind im Standardpfad bei 1/7/2048 Zeilen und
|
||
in den fusionierten Pfaden bei1/4Zeilen enthalten; synthetische Gewichte,
|
||
kein vollständiger Modelllauf. Alle Ausgabehashes bitgenau.
|
||
|
||
Gemeinsamer Prüflauf:13Tests ausgeführt,13bestanden,0fehlgeschlagen,0ignoriert;
|
||
438Fälle/664Hashes. Jede verbundene Testkette bleibt in einem Command Buffer.
|
||
Der Quellcheck umfasst13Custom-Bodies/33Einträge und10Runtime-Einheiten mit
|
||
35Einträgen; GatherAxis und dessen Stride-Helfer werden unverändert übernommen.
|
||
Beleg: `local-eval-results/20260906-mtplx-port/connected-moe-combined-check.log`.
|
||
|
||
**Weiter offen:** Diese Operationen bleiben `cfg(test)`. Der alte Produktgraph
|
||
wurde nicht auf diesen Stand umgestellt. P07 umfasst außerdem die nicht
|
||
Sanitize-fusionierten Modulpfade; die übrigen Graphabschnitte, State/Cache,
|
||
Submission und die zusammenhängende BF16-Produktmigration bleiben offen.
|
||
Exakte Blockausgaben beweisen weder Scheduling-Parität des vollständigen
|
||
Modells noch UI-Responsiveness oder Gesamtperformance. P01–P16 nicht geschlossen.
|
||
|
||
### Getrennte MoE-Projektionen und verbundene Normmodule
|
||
|
||
Der kanonische MoE-Dispatcher bildet nun auch `SwitchGLU` und `Qwen3NextMLP`
|
||
ohne Sanitize-Fusion ab. Expert- und Shared-MLP können unabhängig zusammengepackt
|
||
oder getrennt vorliegen; getrennte Gate-/Up-Projektionen behalten ihre eigenen
|
||
Quantisierungsgruppen und ihre ursprüngliche Aufrufreihenfolge. Die fusionierten
|
||
Decode-/Verify-Kernel werden bei separaten Experten trotz aktivierter Flags wie
|
||
in MTPLX nicht gewählt. Keine Änderung an der Standard-Flagbelegung.
|
||
|
||
Der ursprüngliche `swiglu`-Compileraufruf wurde mit dem bestehenden lokalen
|
||
Beobachter erfasst. Receipt `tests/fixtures/mtplx-swiglu-jit.json`, voller
|
||
beobachteter Quellhash:
|
||
`bf78eee5cf96ea7c112c4e61546c12bcacf57fe512e0572182604cb94137510b`.
|
||
Alle 19 erzeugten Varianten sind unverändert mit lokalen Host-Aliassen exportiert.
|
||
Rank-3 und Rank-5 liefern nach reiner Symbolnormalisierung denselben Rechencode.
|
||
Anders als beim fusionierten Pack ist SwiGLU hier ein gemeinsamer kompilierter
|
||
Aktivierungs-/Multiply-Aufruf mit zwei separaten Projektionseingaben.
|
||
|
||
108 zusätzliche Aufrufe der tatsächlichen MTPLX-MoE-Klasse prüfen getrennte und
|
||
gemischte Modulbelegungen, Gruppen 32/64, Normalisierung an/aus, Sort-/Matmul-
|
||
Grenzen und aktivierte Fusionsflags. Darunter E512/K2560/I640 mit 1/7/2048 Zeilen.
|
||
Alle 108 Ausgabehashes sind exakt; die bisherigen 438 Fixtures blieben unverändert.
|
||
|
||
Außerdem sind `GroupedRMSNorm` (HC/PLE) und `SigmoidRMSNormGated` (GDN) als
|
||
verbundene Rust-Operationen mit den unveränderten Runtime-Shadern portiert.
|
||
Erhalten bleiben ungewichtete Gruppen-RMS vor separater Vollbreitengewichtung,
|
||
BF16-Rundung vor dem FP32-Sigmoid-/Multiply-Epilog, fehlendes Gate sowie das
|
||
strided Z-View aus der fusionierten GDN-Eingangsprojektion. 25 direkte Aufrufe
|
||
der tatsächlichen Normklassen sind exakt, einschließlich 2K Zeilen, Loop-/
|
||
Vektorisierungsgrenzen und GDN-Zeilenstride 16480. Das ist noch nicht der komplette
|
||
gestufte GDN-Forward einschließlich Conv, compute_g, Rekurrenz und Capture-State.
|
||
|
||
Gemeinsamer Lauf: 14 Tests bestanden, 0 fehlgeschlagen, 0 ignoriert;
|
||
571 Fälle / 797 exakte Hashes. Jede verbundene Kette bleibt in einem Command Buffer.
|
||
Quellcheck: 13 Custom-Körper / 33 Einträge, 11 Runtime-Einheiten / 54 Einträge.
|
||
Beleg: `local-eval-results/20260906-mtplx-port/separate-moe-norm-combined-check.log`.
|
||
P07 bleibt wegen der Produktintegration offen. P06/P08/P09/P10 sowie die übrigen
|
||
Host-/State-/Scheduling-Aufgaben bleiben offen; keine Gesamtperformance-Abnahme.
|
||
|
||
### Verbundener gestufter GDN-Forward und compute_g
|
||
|
||
`gated_delta_update` ist einschließlich des tatsächlichen kompilierten
|
||
`compute_g`, BF16-Sigmoid, initialem FP32-Nullzustand, Maske und ursprünglicher
|
||
Rekurrenz verbunden. Das JIT-Receipt bewahrt alle 19 erzeugten Varianten;
|
||
BF16-Add/LogAddExp vor den FP32-Exponentialoperationen bleibt unverändert.
|
||
80 direkte Referenzaufrufe mit zwei aufeinanderfolgenden Updates prüfen
|
||
kalte/vorhandene Zustände, Masken und A/B-Zeilenstride 48/16480 bis 2K Zeilen.
|
||
Alle 320 Hashes sind exakt.
|
||
|
||
Der gestufte `GatedDeltaNet`-Forward mit fusionierter Eingangsprojektion ist
|
||
jetzt bis zur Ausgangsprojektion verbunden: QKV-Maske, Conv-Zustandskonkatenation,
|
||
Tail beziehungsweise geklippte Cache-Längen mit originalem INT32-GatherAxis,
|
||
ursprüngliche Depthwise-Conv1D, SiLU, FP32-L2-Normalisierung mit BF16-Grenze vor
|
||
Q-Skalierung, Rekurrenz, Sigmoid-RMS und Ausgangsprojektion. Die Conv-Norm-
|
||
Fusionen für S1/S2–6 und die Output-Fusion behalten ihre Flag-/Form-/Masken-/
|
||
Längenbedingungen. Kalte Broadcast-Zustände werden am tatsächlichen
|
||
General-Copy-Punkt materialisiert; zusammenhängende Ein-Zeilen-Views werden
|
||
nicht zusätzlich kopiert. Bestehende Bindungen und unveränderte Shader werden
|
||
wiederverwendet; kein mathematisch ähnlicher Ersatzkernel.
|
||
|
||
130 Aufrufe der tatsächlichen MTPLX-Klasse prüfen Zeilen 1/2/4/6/7/32/2048,
|
||
kalte/vorhandene Zustände, Masken, Fusionsflags und Längen unterhalb/in/oberhalb
|
||
des gültigen Bereichs. Jeder Fall führt einen zweiten Forward auf beiden
|
||
zurückgegebenen Zuständen aus. Verglichen werden finaler Hidden-Output,
|
||
Conv-Zustand, FP32-Delta-Zustand sowie die erfassten Q/K/V-Zeilen. Alle 780
|
||
Hashes sind bitgenau; beim Export blieben die vorherigen 651 Receipts unverändert.
|
||
|
||
Gemeinsamer Abschlusslauf: **16 Tests bestanden, 0 fehlgeschlagen, 0 ignoriert;
|
||
781 Fälle / 1.897 exakte Ausgabehashes**. Verbundene Ketten bleiben in einem
|
||
Command Buffer. Quellcheck: 13 Custom-Körper / 33 Einträge, 17 Runtime-Einheiten /
|
||
81 Einträge. Beleg:
|
||
`local-eval-results/20260906-mtplx-port/staged-gdn-combined-check.log`.
|
||
|
||
**P06 bleibt offen.** Diese Operationen sind weiterhin `cfg(test)` und ersetzen
|
||
noch nicht den produktiven FP32-Qwen-Graph. Separate GDN-Eingangsprojektionen,
|
||
vollständige Advance-/Capture-Commit-Zustandsführung, No-Cache-/Batch-Hostpfade
|
||
und gemeinsame Submission-/Concurrency-Semantik sind noch nicht vollständig
|
||
angebunden. QSA/HC/PLE, Sampling/MTP und die zusammenhängende BF16-Produktmigration
|
||
bleiben ebenfalls offen. Ausgabeidentität dieser Module ist weder eine
|
||
Scheduling- noch eine UI-/Harness- oder Gesamtperformance-Abnahme. Kein
|
||
Performance-Auswahlversuch, keine Rücknahme und kein Abschluss von P01–P16.
|
||
|
||
### Gemeinsame GDN-Projektion und tatsächliche Forward-Auswahl
|
||
|
||
Die bisher doppelte Eingangsprojektion in gestuftem und fusioniertem Forward
|
||
ist durch `gdn_project` ersetzt. `GdnInputWeights` bildet sowohl den fusionierten
|
||
Pack als auch die vier separaten QKV-/Z-/B-/A-Module ab. Getrennte Module behalten
|
||
ihre eigene Quantisierung und Aufrufreihenfolge; ihr zusammenhängendes Layout
|
||
wird nicht wie ein fusioniertes View mit Zeilenstride 16480 behandelt. Die
|
||
bestehenden Affine-/GPU-Bindungen werden wiederverwendet, keine Shaderänderung.
|
||
|
||
`gdn_forward` übernimmt die Branch-Priorität für die installierte B=1-Geometrie:
|
||
fusionierter Schritt nur bei entsprechendem Flag, lebendem FP32-Delta, einer
|
||
unmaskierten Zeile, vorhandenem Cache, fehlenden Längen und inaktivem
|
||
Verify-Capture. Ein fehlender Conv-Zustand bei vorhandenem Delta wird wie in
|
||
der Referenz materialisiert. Ein vollständig kalter Aufruf startet gestuft;
|
||
der Folgeschritt kann mit dem zurückgegebenen Delta in den fusionierten Pfad
|
||
wechseln. Die Flags sind keine neu eingeführten Produktdefaults.
|
||
|
||
264 zusätzliche Aufrufe der tatsächlichen MTPLX-Klasse decken fusionierte,
|
||
getrennte und gemischt Q4/Q8-quantisierte Eingänge mit Gruppen 32/64 ab; Zeilen
|
||
1/2/6/7/33/2048, kalte/vollständige/Conv-only/Delta-only-Zustände, Flags aus/an/
|
||
Step-only, Masken, Cache-Längen und Verify-Capture. Zwei aufeinanderfolgende
|
||
Forwards behalten jeweils beide Zustände. Alle 792 Ausgabehashes und die
|
||
tatsächlichen Step-/Conv-Branchentscheidungen sind exakt. Der Export prüfte
|
||
außerdem alle bisherigen 781 Receipts unverändert.
|
||
|
||
Gemeinsamer Prüflauf: **17 Tests bestanden, 0 fehlgeschlagen, 0 ignoriert;
|
||
1.045 Referenzfälle / 2.689 exakte Ausgabehashes**. Belege:
|
||
`local-eval-results/20260906-mtplx-port/gdn-forward-check.log` und
|
||
`gdn-forward-combined-check.log` (kompakter Sammelbeleg; dessen erste Tool-Ausgabe
|
||
war gekürzt, der finale Teststatus ist vollständig). Quell-/Format-/Whitespace-
|
||
Prüfungen bestanden. Keine Performanceauswahl oder Rücknahme.
|
||
|
||
Die zuvor offene separate GDN-Eingangsprojektion ist damit auf Modulebene
|
||
angebunden, **nicht im Produktgraph**. P06 bleibt für vollständige Advance-/
|
||
Capture-Commit-Zustandsführung, No-Cache-/Batch-Hostpfade und gemeinsame
|
||
Submission-/Concurrency-Semantik offen. Das gesamte Modell bleibt auf dem alten
|
||
Produktpfad; sämtliche übrigen Portierungs- und Gesamtperformancepflichten
|
||
bleiben unverändert. Der bestehende Capture-Commit muss mit QSA-/PLE-Snapshots
|
||
und gemeinsamer Validierung vor jeder Cache-Mutation portiert werden, nicht als
|
||
isolierter GDN-Replay-Ersatz für den vollständigen Commit.
|
||
|
||
### QSA-Indexer-Vorbereitung und verbindliche restliche Pfadabdeckung
|
||
|
||
Die tatsächliche QSA-Aufrufkette wurde in `qwen4_exp.py` von `QSACache` über
|
||
`QSAIndexer` bis `Attention` verfolgt. Die folgenden Teile gehören gemeinsam zu
|
||
P08; sie sind keine wahlweisen Performance-Optimierungen:
|
||
|
||
| Abschnitt | Referenzverhalten / verbleibende Verpflichtung |
|
||
| --- | --- |
|
||
| Raw-/Pool-/KV-Zustand | Geometrisches Wachstum, reservierte Kapazitäten, logische Frontier, Trim/Restore; FP32-transponierter Pool-Mirror einschließlich Neuaufbau/Invalidierung |
|
||
| Query-/Key-Vorbereitung | Quantisierte Projektion oder vorhandene QK-Zeilen, RMS/partielles RoPE, vollständige Key-Blöcke; fusionierte und Eager-Fallbackpfade |
|
||
| Auswahl | Cache-Updates vor Dense==Sparse-Rückgabe; ursprünglicher Eager-Score/Top-k, Legacy-Fusion für Decode/kleine Verify-Fenster, gekachelter Prefill-Selektor und expliziter Compiled-State-Pfad |
|
||
| Ergebnisformen | `blocks`, `prefill_blocks`, `row_tokens`, `dense_mask`, `update_only`; logische Grenzen und Scratch-/Kapazitätsbedingungen, kein stiller Retry nach Dispatchfehlern |
|
||
| Attention-Verbraucher | Decode-Flash-Skip, Prefill-Flash, gekacheltes Prefill-Gather, Rows-Gather, Decode-Gather und Dense-SDPA; Masken/kausaler Tail/KV-Stride und Output-Gate erhalten |
|
||
| Vision | M-RoPE und Dense-Causal-Verbrauch bei unverändert weiter gepflegtem QSA-Indexer-/Cache-Zustand |
|
||
|
||
Umgesetzt ist jetzt die fusionierte **Indexer-Vorbereitung** mit den beiden
|
||
unveränderten Körpern aus `qsa_indexer_prepare.py`: Query-RMSNorm/partielles RoPE
|
||
und FP32-Blockmittelwert/BF16-Rundung/RMSNorm/RoPE für Keys. Der Exporter liest
|
||
die Funktionsliterale als AST, schützt den Quelldateihash und löst nur Includes,
|
||
Headerparameter und Einstiegspunkt-ABI auf. Stride-Metadaten behalten den
|
||
ursprünglichen `constant int64_t`-Adressraum. Die Spezialisierung entspricht dem
|
||
vorhandenen Modell: H4/D128/Rotary64/Ratio4/Epsilon1e-6/Attention-Scale1.
|
||
Andere geometrische Konfigurationen sind dadurch nicht als portiert behauptet.
|
||
|
||
`qsa_project_prepare` verbindet die bestehende quantisierte Affine-Operation
|
||
mit dem ursprünglichen Query-Kernel; Raw-Key-Views behalten Zeilenstride 640.
|
||
105 zusätzliche Referenzfälle prüfen Query-Vorbereitung, Key-Pooling und die
|
||
verbundene Projektion/Vorbereitung/Pooling-Kette: bis 2K Zeilen, 512 Key-Blöcke,
|
||
strided und Stride-2-Views, große absolute Positionen, Q4g64/Q8g64/Q8g32. Die
|
||
Frequenzen stammen unverändert vom tatsächlichen MTPLX-Modell. Alle 129 Hashes
|
||
sind exakt; sämtliche vorherigen 1.045 Receipts blieben beim Export unverändert.
|
||
|
||
Gemeinsamer Prüflauf: **18 Tests bestanden, 0 fehlgeschlagen, 0 ignoriert;
|
||
1.150 Referenzfälle / 2.818 exakte Ausgabehashes**. Vollständiger Beleg:
|
||
`local-eval-results/20260906-mtplx-port/qsa-prepare-combined-check.log`.
|
||
Quellcheck: 15 Custom-Körper / 35 Einträge plus 17 Runtime-Einheiten / 81 Einträge.
|
||
Format- und Whitespace-Prüfungen bestanden.
|
||
|
||
**P08 bleibt offen:** Der verbundene Vorbereitungstest ist nicht der vollständige
|
||
Indexer mit Cache/Selektion und nicht der Attention-Forward. Die übrigen
|
||
Tabellenabschnitte, Eager-Fallback und Produktintegration sind noch ausstehend.
|
||
Der kanonische Rust-Pfad bleibt `cfg(test)`; weder UI-/Harness-Verhalten noch
|
||
Gesamtlaufzeit oder das all-model ±2%-Ziel wurden hiermit abgenommen.
|
||
|
||
### QSA-Cache-Lebenszyklus einschließlich Session-State-Aliasing
|
||
|
||
`QsaCache` verbindet Raw-Key-Schreibzugriffe, ursprüngliches Key-Pooling,
|
||
geometrisches Indexer-Wachstum, KVCache-Schrittwachstum, Reservierung, Trim,
|
||
State-Restore und den abgeleiteten FP32-Mirror. Strided KV-Slices werden am
|
||
ursprünglichen Copy-Punkt materialisiert. Nur vorhandene Original-Copy-/Cast-
|
||
und Pooling-Kernel werden verwendet. Die Speicherzählung entspricht
|
||
`QSACache.nbytes`, einschließlich Backing-Kapazitäten und ohne FP32-Mirror.
|
||
|
||
Der Referenztest hat eine falsche Annahme korrigiert: State-Leaves sind **nicht
|
||
generell immutable**. Der Setter übernimmt die Python-Array-Objekte; `__setitem__`
|
||
ersetzt deren Descriptor und ist über dieselben Objekt-Aliase sichtbar. Separate
|
||
Slices teilen dagegen nur Storage. Rust bildet beide Ebenen getrennt mit lokalen
|
||
`Rc` und `RefCell` ab; beim Wachstum wird wie in MTPLX ein neues Objekt gebunden.
|
||
Dieser Unterschied wird durch erhaltene Snapshots nach Restore/Trim/Write geprüft,
|
||
nicht durch angepasste Sollwerte verdeckt.
|
||
|
||
44 zusätzliche Zustandsübergänge mit 536 Ausgabehashes stimmen bitgenau überein:
|
||
kalter und vorreservierter Cache, mehrere Kapazitätsgrenzen, drei gleichzeitig
|
||
gehaltene Snapshots, Fortsetzung nach Restore, vollständiger Trim und erneuter
|
||
Aufbau. Verglichen werden auch ungenutzte Buffer-Bereiche und der Mirror.
|
||
Alle 1.194 Referenzfälle wurden erneut ausgeführt; vorherige Hashes unverändert.
|
||
Gemeinsamer Prüflauf: **19 bestanden, 0 fehlgeschlagen, 0 ignoriert;
|
||
1.194 Fälle / 3.354 exakte Hashes**. Beleg:
|
||
`local-eval-results/20260906-mtplx-port/qsa-cache-combined-check.log`.
|
||
|
||
**P08 und Produktintegration bleiben offen.** Der Cache-Port bleibt zusammen mit
|
||
den bisherigen kanonischen Operationen `cfg(test)`. Vollständige QSA-Selektion,
|
||
Attention und Compiled-Indexer-State-Commit sind noch anzubinden. Dies schließt
|
||
weder den Audit noch UI-/Harness- oder Gesamtperformance-Parität ab.
|
||
|
||
### Ursprüngliche QSA-Selektion und verbundene Cache-Ausführung
|
||
|
||
`qsa_indexer_select.py` ist mit unverändertem gemeinsamen Header, Selektorkörper
|
||
und allen drei Epilogen (`blocks`, `dense_mask`, `row_tokens`) übernommen.
|
||
`metal/mtplx-qsa-select.json` enthält die AST-extrahierten Originalteile samt
|
||
Quelldatei-/Teilhashes. Rust setzt die ursprünglichen Header-Literale für die
|
||
jeweilige Backing-Kapazität ein; weder Laufzeitparameter statt Compile-Konstanten
|
||
noch feste Testkapazitäten ersetzen die Referenzspezialisierung. Die bestehende
|
||
native Pipeline-Bindung kompiliert diese Formen mit MTPLXs Safe-Math- und
|
||
Metal-Sprachversionsauswahl und verwendet ihren vorhandenen Cache weiter.
|
||
|
||
Die verbundene Host-Kette umfasst Raw-Key-Schreiben, ursprüngliches Pooling,
|
||
Query-Vorbereitung, Selektion und KV-Fortschreibung. `_select_fused` begrenzt
|
||
wie die Referenz den Score-Scratch pro Dispatch auf 32 MiB durch Query-Chunking,
|
||
nicht History-Kürzung. Chunk-Ausgaben werden mit den ursprünglichen typisierten
|
||
GeneralGeneral-Copies zusammengefügt; die dichte Maske bleibt ein logischer
|
||
Slice der kapazitätsbreiten Ausgabe. Die allgemeine Metal-Bindung verwirft keine
|
||
Byte-Offsets pauschal wegen einer nur für breitere Typen passenden Vierergrenze.
|
||
|
||
84 neue Referenzfälle / 168 Hashes sind exakt: BF16/FP32 und gemischte Operanden,
|
||
TF32 an/aus, Strides, leere logische Historie, kausale Grenzen, Padding und
|
||
All-zero-Ties; außerdem tatsächliches Host-Chunking bei 65.536 reservierten
|
||
Blöcken sowie drei aufeinanderfolgende Cache-Forwards. Header und vollständiger
|
||
Selektorkörper stimmen zusätzlich mit den tatsächlich erzeugten MTPLX-Quellen
|
||
überein. Alle vorherigen 1.266 Receipts blieben beim erneuten Export unverändert.
|
||
|
||
Gemeinsamer Prüflauf: **21 bestanden, 0 fehlgeschlagen, 0 ignoriert;
|
||
1.278 Fälle / 3.522 exakte Hashes**. Beleg:
|
||
`local-eval-results/20260906-mtplx-port/qsa-select-combined-check.log`.
|
||
|
||
**Offen bleiben** der große vektorisierte Prefill-Selektor, Eager- und Compiled-
|
||
Indexerzweige, Attention-Verbraucher und die zusammenhängende Produktintegration.
|
||
Der kanonische Pfad ist weiter `cfg(test)`. Insbesondere nutzt das ursprüngliche
|
||
`concatenate_gpu` einen Concurrent-Bereich; Ressourcenabhängigkeiten, diese
|
||
Concurrency und automatische Commit-Grenzen sind gemeinsam in P05 zu portieren.
|
||
Die exakten Ergebnisse hier sind kein Scheduling- oder Gesamtperformance-Beleg;
|
||
kein P01–P16 geschlossen und keine Optimierung per Mikrobenchmark verworfen.
|
||
|
||
### Ursprünglicher QSA-Prefill: beide Score-Produzenten, Top-k und Cache-Fortsetzung
|
||
|
||
Die beiden Prefill-Stufen aus `qsa_indexer_prefill.py` sind verbunden portiert:
|
||
der ursprüngliche H4/D128-TensorOps-Score-Kernel (16 Query-Zeilen × 32 Keys pro
|
||
Threadgroup) und der separate adaptive Insertion-/Radix-Top-k-Körper. Header,
|
||
Körper und Epiloge bleiben unverändert; `mtplx-qsa-select.json` enthält zusätzlich
|
||
die gepinnten Prefill-Quellen. Die vorhandene Pipeline-Kompilierung und typisierte
|
||
Ausgabe-Verkettung werden gemeinsam mit dem Legacy-Selektor benutzt.
|
||
|
||
MPP lädt über die ursprünglichen Strides ohne versteckte Contiguous-Copy.
|
||
Der Top-k-Wrapper materialisiert dagegen nichtkontiguierliche FP32-Score-Views
|
||
am ursprünglichen General-Copy-Punkt. Beide Fälle sind gegen echte Referenzaufrufe
|
||
geprüft. Die producerabhängige 128-MiB-Planung samt Alignment-Abrundung ist
|
||
übernommen: eine Score-Ebene für MPP, H4+1 für den allgemeinen
|
||
FP32-Produzenten. Eine irreduzible Zeile darf wie in MTPLX das Budget überschreiten.
|
||
Ein ausgewählter MPP-Kernel fällt bei Fehlern nicht auf einen anderen Pfad zurück.
|
||
|
||
Die gemeinsame Rust-Funktion `qsa_prefill` enthält jetzt auch MTPLXs allgemeinen
|
||
FP32-Score-Zweig: Cast, Matmul, ReLU pro Kopf, Kopf-Summe und Skalierung. Die
|
||
Rust-Dispatch-Auswahl übernimmt `matmul.cpp` der gepinnten Runtime für H4/D128
|
||
auf M5 Max einschließlich GEMV, regulärem Steel/NAX und beiden Split-K-Varianten.
|
||
Alle Shader stammen unverändert aus der gepinnten metallib. Vector-Casts erhalten
|
||
transponierte/gebroadcastete Speicherlayouts; General-Casts materialisieren Views.
|
||
Matmul prüft Transposition und bereits gebroadcastete Operanden vor der
|
||
Batch-Zusammenfassung. Der Pool-Cast wird einmal über alle Chunks gehalten;
|
||
Top-k und typisierte Verkettung sind für beide Produzenten gemeinsam.
|
||
|
||
384 neue Score-Fälle decken BF16/FP32-Queries, acht Layoutkombinationen, bis 2K
|
||
Query-Zeilen und den echten `MLX_ENABLE_TF32=0/1`-Runtime-Schalter in separaten
|
||
Prozessen ab. 160 der 192 Form-/Typ-Paare haben tatsächlich unterschiedliche
|
||
TF32-an/aus-Referenzergebnisse; beide Varianten sind jeweils bitgenau. Dazu kommen
|
||
96 verbundene Prefill-Fälle mit allen vier BF16/FP32-Operandenpaaren, allen drei
|
||
Ausgabeformen und erzwungenem Chunking einschließlich Alignment-Abrundung.
|
||
|
||
`qsa_prefill_cached` verarbeitet den gültigen Pool-Ausschnitt wie der große
|
||
MTPLX-Prefill-Zweig, nicht die reservierte Kapazität des Legacy-Selektors. Der
|
||
fortlaufende Cache-Test hängt nach 1/4/7 Zeilen einen vollständigen 2K-Prefill an;
|
||
Query-Vorbereitung, Raw-Writes, Pooling, Selektion und KV-Fortschreibung bleiben
|
||
verbunden. Alle drei Selektions-Ausgabeformen sind geprüft.
|
||
|
||
159 neue Fälle / 284 Hashes: Kachelränder, bis 2K Query-Zeilen, bis 65.536
|
||
Key-Blöcke, Stride-2-/gepaddingte Score-Views auch mit nichtkonstanten Werten,
|
||
kausale Grenzen, Null-/Einser-Ties, kurze/lange Radix-Kandidatenlisten, erzwungene
|
||
Chunk-/Concat-Grenzen und reale Cache-Fortsetzung. Die vorherigen Receipts
|
||
blieben bei den erneuten Referenzexporten unverändert. Gemeinsamer Prüflauf
|
||
einschließlich der 480 zusätzlichen FP32-/Producer-Fälle:
|
||
**25 bestanden, 0 fehlgeschlagen, 0 ignoriert; 1.917 Fälle / 4.382 exakte Hashes**.
|
||
Beleg: `local-eval-results/20260906-mtplx-port/qsa-f32-prefill-combined-check.log`.
|
||
|
||
**Nicht abgeschlossen:** vollständiger Eager-Indexer,
|
||
Compiled-State/Graph-Bank, Attention-Verbraucher, vollständige Branch-Auswahl,
|
||
Scheduling und Produktintegration. Die unterstützte M5-Prefill-Kette wird nicht
|
||
als Ersatz für diese Zweige ausgegeben. Der kanonische Port bleibt `cfg(test)`;
|
||
keine Änderung der UI-Performance behauptet, kein P01–P16 geschlossen und kein
|
||
Gesamtbenchmark oder Rücknahmeentscheid vor der vollständigen Integration.
|
||
|
||
### Eager-Indexer: Selektion, Kachel-Eval und sämtliche Ausgabeformen
|
||
|
||
Der kanonische Rust-Port enthält jetzt auch die untiled `_select_eager`-Kette:
|
||
kausale Blockgültigkeit, FP32-Matmul/ReLU/Kopf-Summe/Skalierung, `where`,
|
||
`block_id * 1e-12`-Tie-Break und die originale Runtime-`ArgPartition`-Ausführung
|
||
(vollständiger Argsort). Die letzte K-Spalten-View behält den ursprünglichen
|
||
Zeilenstride. Für `flash_prefill` folgen originale Int32-Sortierung,
|
||
Int64-Indexkonvertierung, Bool-GatherAxis und Nullsetzen ungültiger Slots.
|
||
Dense-Maske, Rows-Gather sowie beide Decode-Ausgaben (Flash-Blöcke und
|
||
Gather-Tokenliste) sind ebenfalls verbunden. Dense verwendet den originalen
|
||
Bool-ScatterAxis, Gültigkeit, Repeat/Concat und die Tail-/Kausalmaske. Rows-Gather
|
||
behält die Argsort-Reihenfolge, liefert K*4+4 gepaddingte Tokens mit Gültigkeit
|
||
und setzt ungültige IDs auf null. Decode sortiert chronologisch und hält die
|
||
Tail-Grenze auf dem Host; Flash hat wie in MTPLX Vorrang vor Gather. Die für diese
|
||
beiden lazy Ausgaben tote Dense-Maskenexpression wird nicht ausgeführt.
|
||
GatherAxis/ScatterAxis verwenden unveränderte Originalkörper mit den benötigten
|
||
Templatespezialisierungen; kein Ersatzkernel. Cast, Sort und Vektor-Dispatch
|
||
werden zwischen den Epilogen geteilt.
|
||
|
||
Die Referenzreceipts stammen aus tatsächlichen `QSAIndexer._select_eager`-
|
||
Aufrufen. Beobachter reichen `where`/`argpartition` unverändert weiter und lesen
|
||
die realen Zwischenwerte; die Blockausgabe wird über den echten Prefill-Phasen-
|
||
und Konfigurationspfad ausgewählt. 60 Zwischenwert- und 24 verbundene Blockfälle
|
||
prüfen BF16/FP32, Null-Ties, kausale Grenzen, bis 2K Queries und bis 65.536 Blöcke,
|
||
jeweils mit dem echten TF32-Runtime-Schalter an/aus. Hinzu kommen 144 Dense-,
|
||
108 Rows-Gather- und 72 Decode-Fälle, einschließlich Tail-Längen 0/1/3 und
|
||
gleichzeitig gesetzten Flash-/Decode-Gather-Schaltern. Insgesamt prüfen 408
|
||
Eager-Fälle die echten MTPLX-Ausgaben bzw. Zwischenwerte.
|
||
|
||
`_tiled_topk` ist an dieselbe Score-/Ranking-Kette angeschlossen. Block-/Tie-
|
||
Vektoren und der FP32-Pool werden geteilt. Jede Kachel wartet synchron auf das
|
||
Top-k-Ergebnis, bevor die nächste entsteht; kein Ersatz durch asynchrones Flush.
|
||
Score-Scratch wird nach der Kachel freigegeben, die ausgewerteten ArgPartition-
|
||
Views bleiben bis zum originalen GeneralGeneral-Concat erhalten. Der Indexstride
|
||
wechselt dabei von N auf K; Gültigkeit behält ihren N-Stride. Alle Epiloge beachten
|
||
beide Strides. Der ganze Blockgültigkeitsausdruck folgt erst nach den Kachel-Evals.
|
||
|
||
`qsa_eager_output` entscheidet die Rückgabe nun gemeinsam in Referenzreihenfolge:
|
||
Prefill-Blöcke, Decode-Flash, Decode-Gather, ungekächeltes Rows-Gather, Dense.
|
||
Die gemeinsame Large-Prefill-Berechtigung ist weiterhin ein Eingabeparameter;
|
||
ihre vollständige Verknüpfung mit Indexer/Compiled-Core gehört zur offenen
|
||
Indexer-Integration. Die neuen Tests wählen nicht selbst den erwarteten Epilog,
|
||
sondern übergeben dieselben Schalter wie der MTPLX-Aufruf. Insbesondere bleibt
|
||
Gather eingeschaltet, wenn der gekachelte Zweig trotzdem Dense zurückgeben muss.
|
||
|
||
132 zusätzliche Fälle / 198 Hashes prüfen echte Kachel-Eval-Aufrufe, 2K Queries,
|
||
65.536 Blöcke, Stride-2-FP32-Queries, Tail 0/1, Kachelreste und die Abschaltung
|
||
der Kachelung bei Kachelgröße >= Query-Zeilen. 108 Fälle sind tatsächlich
|
||
gekachelt; 24 prüfen diese Abschaltgrenze. Die Referenzreceipts erfassen die
|
||
unverändert weitergereichten `mx.eval`-Aufrufe. Das beweist nicht die allgemeine
|
||
Graph-Tape-/Allocator-/Concurrency-Parität innerhalb einer Eval-Grenze.
|
||
|
||
Gemeinsamer Korrektheitslauf: **26 bestanden, 0 fehlgeschlagen, 0 ignoriert;
|
||
2.457 Fälle / 5.240 Hashes**, davon 540 Eager-Fälle. Quellenexport, Formatierung
|
||
und Diff-Whitespace-Prüfung bestanden. Erneute Originalexporte bestätigen alle
|
||
1.947 Default-/TF32-an- und 510 TF32-aus-Receipts unverändert. Beleg:
|
||
`local-eval-results/20260906-mtplx-port/qsa-eager-tiled-combined-check.log`.
|
||
|
||
### Eager-Vorbereitung im Projektions- und Cache-Pfad
|
||
|
||
Die Eager-Query-/Pool-Vorbereitung ist für die installierte BF16-Geometrie
|
||
(Q H4/D128, Pool H1/D128, Rotary64, Ratio4, Epsilon1e-6, Skalierung1) verbunden.
|
||
Nichtkontiguierliche Projektionsslices werden vor RMSNorm mit der originalen
|
||
General-Copy materialisiert. Pooling bleibt FP32-Summe mal 0,25 mit anschließendem
|
||
BF16-Cast vor RMSNorm. RoPE verwendet die ursprünglichen Arange-/Cast-/Concat-,
|
||
Cos/Sin-, BF16-Negative- und FP32-Multiply/Add-Schritte samt abschließendem
|
||
BF16-Cast und unverändertem Pass-through-Anteil. Kein Ersatz durch den fusionierten
|
||
Kernel; keine neuen Shaderkörper. General-Copy und die vorhandenen Norm-/Cast-/
|
||
Concat-Dispatcher werden gemeinsam genutzt.
|
||
|
||
`qsa_project_prepare` und `QsaCache::extend_pooled` besitzen jetzt beide
|
||
Vorbereitungszweige. Ihre Zwischenpuffer werden durch die verbundenen Operationen
|
||
bis zur Auswertung gehalten. 105 neue Originalfälle prüfen Query-, Pool- und
|
||
quantisierte Projektionsketten, einschließlich Padding/Stride2, hoher Positionen
|
||
und 2K-Zeilen. 44 zusätzliche echte QSACache-/KVCache-Übergänge prüfen Eager-
|
||
Pooling bei Wachstum, Reservierung, Trim, Snapshots/Restore und Spiegel-Neuaufbau.
|
||
Die bisherigen 2.052 Default-/TF32-an-Fälle blieben beim letzten vollständigen
|
||
Originalexport unverändert; hinzu kamen die 44 Eager-Cache-Fälle.
|
||
|
||
Der Eager-Selektions-Test prüft nun auch die tatsächliche Anzahl abgeschlossener
|
||
Command Buffer über die vorhandenen `GpuBusyStats`: genau ein Abschluss je
|
||
beobachtetem MTPLX-Kachel-Eval plus ein finaler Ausgabe-Batch. Dies ersetzt nicht
|
||
den weiterhin offenen Nachweis der allgemeinen Graph-/Scheduling-Parität.
|
||
|
||
Gemeinsamer Korrektheitslauf: **26 bestanden, 0 fehlgeschlagen, 0 ignoriert;
|
||
2.606 Fälle / 5.905 Hashes**, davon 210 Vorbereitungsfälle und 88 Cache-Übergänge.
|
||
Quellenexport, Formatierung und Diff-Whitespace-Prüfung bestanden. Beleg:
|
||
`local-eval-results/20260906-mtplx-port/qsa-eager-preparation-combined-check.log`.
|
||
|
||
### Verbundener nicht-kompilierter Indexer-Aufruf
|
||
|
||
`qsa_indexer_rows_uncompiled` bildet den Abschnitt von `_call_rows` nach der
|
||
Compiled-Entscheidung zusammenhängend ab: eigene quantisierte Projektion oder
|
||
mitgelieferte Q/K-Zeilen, Query-Vorbereitung, Raw-Write, Pool-Fortschreibung und
|
||
Selektion. Die bestehenden Ketten werden wiederverwendet. Im Dense==Sparse-
|
||
Bereich bleibt die ungenutzte Query-Vorbereitung wie in MTPLXs Lazy-Ausführung
|
||
unausgewertet. Der KV-Offset wird erst vom nachfolgenden Attention-Schritt erhöht,
|
||
nicht vor der Indexer-Selektion.
|
||
|
||
Die Zweigauswahl berücksichtigt Phase, früheste Query-Position, Prefill-Mindest-
|
||
breite, Gather-Schwellen und Decode-Gather-Ausschluss des Legacy-Fused-Zweigs.
|
||
Large-Prefill verwendet die logische Pool-Sicht, Legacy-Fused die reservierte
|
||
Backing-Kapazität; Eager verwendet den gespeicherten FP32-Spiegel. Die Rückgabe
|
||
beschränkt sich auf die vom Modell konsumierten Ausgaben und hält die übrigen
|
||
Kernel-Ausgabepuffer bis zur Auswertung. Der gemeinsame Rückgabetyp heißt deshalb
|
||
jetzt `QsaIndexerSelection`, nicht mehr `QsaEagerSelection`.
|
||
|
||
92 Originalaufrufe in 24 fortlaufenden Sequenzen prüfen kalten Start, den
|
||
Budgetübergang, projizierte und mitgelieferte Q/K-Zeilen (704er Zeilenstride),
|
||
2K-Zeilen, 32K-Historie, Flash/Gather-Vorrang, aktivierte Kachelung und die
|
||
Prefill-Schwelle auf beiden Seiten. Die Fixtures rufen den echten MTPLX-Indexer
|
||
auf; Beobachter reichen seine Selektionsmethoden unverändert weiter. Rust prüft
|
||
den tatsächlich gewählten Pfad, 82 Selektionshashes, 268 zusätzliche Raw-/Pool-/
|
||
Spiegelhashes, Kapazitäten/Offset und abgeschlossene Command Buffer. Die numerische
|
||
Prüfung wertet Cache-Zustände explizit aus; sie ist kein Beleg für den vollständigen
|
||
Lazy-Graph-Lebenszyklus einer Modellgenerierung.
|
||
|
||
Gemeinsamer Korrektheitslauf: **27 bestanden, 0 fehlgeschlagen, 0 ignoriert;
|
||
2.698 Fälle / 5.987 Ausgabehashes plus 268 Zustands-Hashes**. Quellenexport,
|
||
Formatierung und Diff-Whitespace-Prüfung bestanden. Der erneute Originalexport
|
||
bestätigt alle 2.188 Default-/TF32-an-Fälle unverändert, einschließlich der
|
||
Indexer-Sequenzen und Zustands-Hashes. Beleg:
|
||
`local-eval-results/20260906-mtplx-port/qsa-indexer-routes-combined-check.log`.
|
||
|
||
**Weiter offen:** Compiled-Eignungsentscheidung und Compiled-State/Graph-Bank,
|
||
Attention, Scheduling und
|
||
Produktintegration. Insbesondere ist die breiteabhängige BFS-Tape-Planung aus
|
||
Runtime `transforms.cpp` nicht durch serielles Rust-Encoding nachgewiesen.
|
||
Der explizit nicht-kompilierte Einstieg ersetzt keinen geeigneten Compiled-Pfad.
|
||
P05 und P08 bleiben offen; keine Gesamtmodell-/Performance-Parität behauptet.
|
||
|
||
Compiled-Cache-Voraussetzungen sind anschließend gegen die Referenz geprüft:
|
||
`qsa_replay_capacity` übernimmt die Power-of-two-Buckets einschließlich des
|
||
festen `ceil(S/4)`-Stagingfensters; `ensure_compiled_backings` berücksichtigt
|
||
ausstehende Reservierungen und materialisiert unberührte Backings. 108 reine
|
||
Kapazitätsfälle und vier echte `_ensure_compiled_backings`-Übergänge prüfen
|
||
unter anderem S=1025 und die Übernahme vorhandener Daten, ohne KV-Offset oder
|
||
logische Pool-Länge vorzeitig zu verändern. Acht weitere Fälle prüfen die
|
||
originalen dynamischen BF16-Kopien mit int32-GPU-Startwerten, 128/704-Stride
|
||
und bis zu 2048 Zeilen. Keine Host-Auslese der Startwerte. Die gemeinsame
|
||
Kopierfunktion nutzt dieselben bisherigen Kernel/Geometrien für statische
|
||
Aufrufe; nur dynamische Aufrufe binden die originalen int64-Offset-Leaves.
|
||
|
||
`tools/mtplx-jit-reference.py --operation qsa-update --check` führt den echten
|
||
Compiled-Indexer aus und prüft drei unveränderte erfasste Shader: Fused Clamp,
|
||
Multiply und Dynamic Offset. Alle drei sind jetzt im verbundenen
|
||
`qsa_compiled_cache_window` verwendet: Raw-Update, dynamische Clamp-Grenze,
|
||
festes Raw-Fenster, originales Pooling und Pool-Update. Der unveränderte
|
||
Runtime-Header ist ebenfalls übernommen. Die drei originalen Constant-CSE-
|
||
Layouts (obere Grenze null / gleich max_new / verschiedene Konstanten) sind
|
||
separat erfasst; Rust spezialisiert nur Formkonstanten und exportierte Symbole.
|
||
Eine zusätzliche Originalvariante mit 257/255 prüft diese Spezialisierung.
|
||
|
||
26 echte `QSACompiledIndexerCore.select_qk_rows`-Aufrufe prüfen die komplette
|
||
Cache-Ausgabe und unveränderte Eingangs-Backings: 104 zusätzliche Hashes,
|
||
640/704-Zeilenstride, unvollständige Blöcke, rückwärts verschobenes Poolfenster,
|
||
Kapazitätsgrenzen und S=2048. Startwerte bleiben GPU-Leaves; kein Zwischen-Eval
|
||
oder Frontier-Readback. Die Referenz hält Eingangs-Leaves während der Auswertung
|
||
fest. Damit ist ausdrücklich der **nicht-donierende Kopierzweig** geprüft,
|
||
nicht der Allokator oder das vollständige Graph-Replay. Eignungsentscheidung,
|
||
Graph-Bank, Donation, BFS-Tape, Modell-Aufrufintegration und
|
||
Produktionsintegration bleiben offen. Keine Modell-/Performance-Parität.
|
||
Neue Referenzfälle: `tests/fixtures/mtplx-qsa-compiled-state.jsonl`;
|
||
gemeinsamer Lauf: `local-eval-results/20260906-mtplx-port/qsa-compiled-state-check.log`.
|
||
Dieser frühere Voraussetzungslauf besteht mit **29 Tests, 0 fehlgeschlagen, 0 ignoriert** und deckt
|
||
insgesamt **2.818 Fälle / 6.019 Ausgabehashes plus 268 Zustands-Hashes** ab.
|
||
Quellenexport, frische JIT-Referenzprüfung, Formatierung und Diff-Prüfung bestehen.
|
||
Der anschließende verbundene Cache-Fenster-Lauf besteht mit **31 Tests,
|
||
0 fehlgeschlagen, 0 ignoriert**: **2.844 Fälle / 6.123 Ausgabehashes plus
|
||
268 Zustands-Hashes**. Alle vier Compiled-Quellenproben einschließlich des
|
||
unveränderten Runtime-Headers sind frisch reproduziert. Neue Fälle:
|
||
`tests/fixtures/mtplx-qsa-compiled-window.jsonl`; vollständiger Beleg:
|
||
`local-eval-results/20260906-mtplx-port/qsa-compiled-window-check.log`.
|
||
|
||
Der verbundene BF16-Q/K-Einstieg umfasst jetzt alle fünf festen Ausgabemodi
|
||
(`update_only`, `blocks`, `row_tokens`, `dense_mask`, `prefill_blocks`). Die
|
||
Query-Vorbereitung sowie Legacy-/Prefill-Top-k binden echte int32-GPU-Leaves;
|
||
bestehende Host-Aufrufe verwenden dieselben Dispatch-Funktionen. Die originale
|
||
kompilierte Positionsaddition wird auch für `+0` ausgeführt. Vier unverändert
|
||
erfasste Add-Kernel prüfen die reine Formkonstanten-Spezialisierung. Die
|
||
Selektionskachelung verwendet die gesamte Pool-Kapazität, das jeweilige
|
||
Scratch-/Workspace-Budget und die originale Prefill-Abrundung auf 32 Zeilen.
|
||
|
||
66 echte `QSACompiledIndexerCore.select_qk_rows`-Aufrufe vergleichen sämtliche
|
||
Selektionsausgänge und unveränderte/aktualisierte Cache-Backings: 144 zusätzliche
|
||
Ausgabehashes und 264 Zustands-Hashes. Darunter sind gekachelte Legacy-Ausgaben,
|
||
Prefill mit 2048 Zeilen, 640/704-Stride und die reine Update-Route. Rust bestätigt
|
||
jeweils einen abgeschlossenen Command Buffer ohne Zwischen-Eval. Das beweist
|
||
die verbundene Q/K-Arithmetik im Retained-Input-Zweig, **nicht** das noch offene
|
||
Graph-Replay oder identische BFS-Reihenfolge. Neue Fälle:
|
||
`tests/fixtures/mtplx-qsa-compiled-indexer.jsonl`; Beleg:
|
||
`local-eval-results/20260906-mtplx-port/qsa-compiled-indexer-check.log`.
|
||
Gemeinsamer Lauf: **32 Tests bestanden, 0 fehlgeschlagen, 0 ignoriert**;
|
||
**2.910 Fälle / 6.267 Ausgabehashes plus 532 Zustands-Hashes**. Originalquellen,
|
||
frische Compiled-Add-/Update-Proben, Formatierung und Diff-Prüfung bestanden.
|
||
|
||
Der Hidden-Einstieg ist anschließend an denselben Q/K-Pfad angeschlossen:
|
||
`qsa_compiled_indexer_hidden_retained` führt die originale affine Quantisierung
|
||
vor Cache-Aktualisierung und Selektion im selben asynchronen Aufruf aus. Es
|
||
gibt keinen Zwischen-Eval oder abweichenden Selektionspfad. 132 echte
|
||
`QSACompiledIndexerCore.select_hidden`-Aufrufe prüfen 4-/8-Bit-Projektionen mit
|
||
Gruppengröße 32/64, alle fünf Modi und dieselben Kachel-/2K-Prefill-Grenzen:
|
||
288 weitere Ausgabehashes und 528 Zustands-Hashes. Die ursprünglichen 66
|
||
Q/K-Referenzfälle sind frisch unverändert reproduziert. Zusammen prüft der
|
||
verbundene Test 198 Aufrufe. Dies schließt die arithmetische Projektion ein,
|
||
nicht die offene Eignungsentscheidung, Graph-Bank, Donation/BFS oder den
|
||
produktiven Modell-Aufruf. Neue Fälle:
|
||
`tests/fixtures/mtplx-qsa-compiled-hidden.jsonl`; Beleg:
|
||
`local-eval-results/20260906-mtplx-port/qsa-compiled-hidden-check.log`.
|
||
Gemeinsamer Lauf: **32 Tests bestanden, 0 fehlgeschlagen, 0 ignoriert**;
|
||
**3.042 Fälle / 6.555 Ausgabehashes plus 1.060 Zustands-Hashes**. Formatierung,
|
||
Originalquellenexport und Diff-Prüfung bestanden. Keine neuen Metal-Kernel,
|
||
Modelldownloads oder Produktions-/Performance-Abnahme in diesem Schritt.
|
||
|
||
Die Host-Routenauswahl ist jetzt für den installierten B1/BF16/Ratio4-Vertrag
|
||
mit Cache-Commit und Ausgabeadapter verbunden (heute `qsa_indexer_rows`).
|
||
`QsaIndexerOptions` übernimmt Compiled-Schalter und kanonische Compile-Breite;
|
||
Prefill-Eignung verwendet den frühesten Query und den echten Phasenwert.
|
||
Die Eignungsprüfung läuft vor Kapazitäts-Bucketing, berücksichtigt fehlende
|
||
Backings, Cache-Lücken und Flash-Vorrang gegenüber Decode-Gather. 720 Aufrufe
|
||
der unveränderten MTPLX-Hostmethoden (12 Optionssätze × 30 Cache-Zustände ×
|
||
Hidden/QK) stimmen überein, einschließlich nicht-potenzförmiger Kapazitäten.
|
||
Das ist die Cache-/Phasenentscheidung für feste Modelldatentypen, kein Nachweis
|
||
beliebiger Source-/Norm-/Projektions-Datentyp- und Shape-Eignung.
|
||
|
||
108 zusätzliche vollständige Original-Indexer-Aufrufe in 28 fortgesetzten
|
||
Sequenzen prüfen die Verbindung von Eignung, Backing-Reservierung, GPU-Frontiers,
|
||
Rechenpfad und Host-Commit: 38 Compiled-Aufrufe sowie tatsächliche Eager-,
|
||
Prefill- und Update-only-Alternativen. Cache-Raw/Pool und logischer Frontier
|
||
werden ohne Readback ersetzt; ein früherer FP32-Mirror wird invalidiert;
|
||
KV.offset bleibt bis zur anschließenden Attention-KV-Aktualisierung unverändert.
|
||
Flash-/Prefill-/Gather-Ausgaben und der logische Ausschnitt der kapazitätsbreiten
|
||
Dense-Maske stimmen mit dem Original überein. Dispatched Fehler werden nicht
|
||
durch einen Eager-Fallback verborgen. Die 92 bisherigen Aufrufe verwenden
|
||
jetzt denselben verbundenen Rust-Einstieg mit abgeschaltetem Compiled-Schalter;
|
||
der gemeinsame Test prüft 200 Aufrufe einschließlich echter Command-Buffer-Zahl.
|
||
Neue Referenzen: `tests/fixtures/mtplx-qsa-compiled-routes.json` und
|
||
`tests/fixtures/mtplx-qsa-indexer-connected.jsonl` (98 Ausgabe-/282 Zustands-Hashes).
|
||
Gemeinsamer Lauf: **33 Tests bestanden, 0 fehlgeschlagen, 0 ignoriert**;
|
||
**3.150 Rechenfälle / 6.653 Ausgabehashes plus 1.342 Zustands-Hashes**, zusätzlich
|
||
720 Host-Routingentscheidungen. Beleg:
|
||
`local-eval-results/20260906-mtplx-port/qsa-connected-routing-check.log`.
|
||
Originalkernel unverändert. Weiterhin ausdrücklich offen: Graph-Bank und
|
||
Parameteridentität, Donation/BFS/Allocator, vollständige Modell-/Produktintegration
|
||
und danach die Gesamt-Performanceabnahme. Der verbundene Testpfad verwendet
|
||
noch die ausdrücklich benannte Retained-Input-Ausführung; er ist kein Ersatz
|
||
für die fehlende Runtime-Parität und bleibt außerhalb des Produktpfads.
|
||
|
||
Die direkte Compiled-Rechenkette ist danach durch eine echte QSA-Graph-Bank
|
||
ersetzt worden (`src/engine/metal/qwen_mtplx/qsa_graph.rs`). Ein struktureller
|
||
Schlüssel erzeugt einmal die Primitiv-Knoten und ihren Ausführungsplan;
|
||
Wiederaufrufe binden die zehn aktuellen Array-Eingaben. Frontier-Werte und
|
||
Q/K-Strides sind keine Trace-Schlüssel. Query-/Key-Views, dynamische Updates,
|
||
ursprüngliche skalare Compiled-Operationen, Pool-/Query-Vorbereitung, MPP-/Topk-
|
||
oder Legacy-Selektion und jede einzelne Concatenate-Ausgabe bilden explizite
|
||
Abhängigkeiten. Die bisherigen direkten Compiled-Hidden-/QK-/Selektionsketten
|
||
sind entfernt, nicht als zweite Ausführung daneben behalten.
|
||
|
||
99 vor dem Eval exportierte optimierte MTPLX-Graphen prüfen Primitiv-Abhängigkeiten
|
||
und Mehrfach-Ausgaben für alle Modi, Kachelgrenzen und beide Einstiege. Evaluierte
|
||
Konstanten werden im Struktur-Fingerprint ausgespart; Originalshader und
|
||
numerische Ergebnisse bleiben separate Prüfungen. Die 2K-Constant-CSE-Variante
|
||
ist enthalten. Der Plan verwendet den Degree-/BFS-Algorithmus des gepinnten
|
||
`mlx/transforms.cpp:180` mit Breitenlimit 20, spezialisiert auf einen Stream und
|
||
bereits evaluierte Eingaben. Dies ist noch **kein** globaler Modellgraph oder
|
||
Nachweis der tatsächlich überlappenden Metal-Encoder-Zeitlinie.
|
||
|
||
Alle 198 bisherigen Compiled-Rechenfälle laufen jetzt durch diese Graph-Bank;
|
||
ein Q/K-Layoutwechsel 640→704 muss denselben Graphen wiederverwenden. Die
|
||
108 fortgesetzten Original-Indexer-Aufrufe wurden frisch um echte
|
||
`compiled_calls`-/`traces`-/Entry-Zähler ergänzt; sämtliche bisherigen Inhalte
|
||
und Hashes blieben unverändert. Rust stimmt auch mit diesen Zählern überein,
|
||
einschließlich vier Wiederaufrufen ohne neue Trace. Parameterersetzung verwirft
|
||
die Bank; ein zusätzlicher Austausch-/Rücktausch-Test prüft Invalidierung und
|
||
erneuten Layout-Replay. Die noch testgebundene Buffer-Identität verhindert dabei
|
||
Verwechslungen durch wiederverwendete native Adressen, ohne den gegenwärtigen
|
||
Produkt-Buffer um Laufzeitaufwand zu erweitern.
|
||
|
||
Gemeinsamer Lauf **33/33 bestanden**, danach der ergänzte Identitäts-Test
|
||
bestanden. Die bestehende Rechenfall-/Hash-Zahl bleibt unverändert; neu sind
|
||
99 Graphstruktur-Referenzen in `tests/fixtures/mtplx-qsa-compiled-graphs.jsonl`
|
||
und die Engagement-Zähler im verbundenen Fixture. Originalquellenexport,
|
||
Formatierung, Diff-Prüfung und `cargo check --release --bin ds4-server` für
|
||
die Nicht-Test-Konfiguration bestanden. Beleg:
|
||
`local-eval-results/20260906-mtplx-port/qsa-graph-replay-check.log`.
|
||
Weiter offen sind insbesondere Donation, frühzeitige Freigabe/Allocator,
|
||
modellweiter lazy Graph mit passender Root-/Stream-/Encoder-Ausführung,
|
||
generische Tensor-Eignung und die Produktintegration. Intermediates bleiben
|
||
in dieser Retained-Lane noch bis zum Aufrufende gehalten. P05/P16 und das
|
||
vollständige 2%-Ziel bleiben offen; keine Performance-Abnahme aus diesen Tests.
|
||
|
||
Die Lebensdauer der Graph-Zwischenwerte folgt nun dem letzten Verbraucher:
|
||
Der gecachte Plan enthält die Freigabestellen, einschließlich aller Geschwister
|
||
einer Mehrfach-Ausgabe. Nach einem Primitiv werden nicht mehr benötigte
|
||
Graph-Referenzen gelöst; nur die echten Ergebnisblätter bleiben im Resultat.
|
||
Block-/Raw-Start-Scratch gehört nicht mehr zum Graph-Ergebnis. Die GPU-seitige
|
||
Freigabe ist davon getrennt: Rust überträgt besessene Puffer an einen
|
||
Completion-Handler des bereits offenen Command Buffers. Es wird weder ein
|
||
zusätzlicher Command Buffer angelegt noch ein Flush oder Wait ausgelöst.
|
||
Leere Batches nehmen keinen Besitz an; ohne offene/ausstehende Arbeit erfolgt
|
||
die Freigabe unmittelbar. Ein eigener Test prüft diese Besitzübergabe vor und
|
||
nach einem asynchronen Flush. Die 198 Rechenfälle prüfen zusätzlich, dass am
|
||
Aufrufende nur Ergebnisblätter übrig sind und keine ausgemusterten Graph-Blätter
|
||
als versteckte Temporaries zurückgegeben werden. Die gezählten Graph-Blätter
|
||
sind ausdrücklich **keine** Messung physisch bereits freigegebenen GPU-Speichers.
|
||
|
||
Der verschärfte Lauf mit `DS4_METAL_UNRETAINED_COMMAND_BUFFERS=1` deckte vier
|
||
`Invalid Resource`-Fehler auf (Cache-Lifecycle, Compiled-Indexer, verbundene
|
||
Cache-Selektion und Indexer-Routing). Ursache: Die gemeinsame kanonische
|
||
Metal-Dispatch-Grenze hielt gebundenen Speicher nicht selbst bis zum GPU-Ende;
|
||
ein kurzlebiges Argument konnte vor Batch-Commit verschwinden. Das war durch
|
||
Metals Standard-Retention verdeckt. Korrigiert ist die gemeinsame Dispatch-
|
||
Grenze, nicht jeder betroffene Aufrufer: gebundene Metal-Ressourcen werden
|
||
dedupliziert bis zum Completion-Callback gehalten und dort explizit freigegeben.
|
||
Das entspricht dem Lifetime-Vertrag des gepinnten GPU-Evaluators; die native
|
||
Bridge hält nur Plattform-Ressourcen, Modell-/Graph-Orchestrierung bleibt Rust.
|
||
Compile und Dispatch haben zudem eigene Autorelease-Pools wie das Original
|
||
`gpu::eval`, damit Foundation-Temporaries nicht am Lebensende des Worker-Threads
|
||
hängen. Keine Kernelquelle, Dispatch-Geometrie oder Host-/GPU-Synchronisation
|
||
wurde dadurch geändert.
|
||
|
||
Der normale vollständige Lauf besteht mit **34/34 Tests**; der verschärfte Lauf
|
||
nach der gemeinsamen Ressourcen-Korrektur ebenfalls. Rechen-/Graph-Fixtures
|
||
bleiben unverändert. Rohfehler und erfolgreiche Verifikation werden in
|
||
`local-eval-results/20260906-mtplx-port/qsa-lifetime-check.log` getrennt bewahrt.
|
||
Aktuelle vollständige Sammlung ist nun `cargo test --release qwen_mtplx --
|
||
--include-ignored --test-threads=1`, damit der neue Lifetime-Test im Graph-Modul
|
||
nicht durch den alten engeren Filter ausgelassen wird.
|
||
|
||
Donation verlangt nach MTPLX exklusiven Array-Descriptor **und**
|
||
exklusiven Data-Besitz, passende Elementgröße und höchstens 16 KiB Überhang.
|
||
Dabei zählen auch die noch ausstehenden GPU-Evaluator-Referenzen. Weder der
|
||
letzte Graph-Verbraucher noch ein einzelner `Rc::strong_count` beweist diese
|
||
Bedingungen. Ebenso offen: vollständiger Allocator, modellweiter lazy Graph,
|
||
Root-/Stream-/Encoder-Parität und Produktintegration. Keine UI-Stall-Behebung
|
||
oder Performance-Parität wird aus diesem noch testgebundenen Port abgeleitet.
|
||
|
||
### Getrennter Array-/Data-Besitz im kanonischen Port
|
||
|
||
Die gemeinsame testgebundene `Buffer`-Schicht unterscheidet jetzt eine eindeutige
|
||
Array-/View-Identität vom gemeinsam referenzierten Data-Besitz. Auch verschachtelte
|
||
native Views teilen denselben Rust-Data-Besitz; der native Root wird erst mit dem
|
||
letzten Data-Besitzer freigegeben. Der GPU-Completion-Transfer hält Data, nicht
|
||
mehr ausgemusterte Graph-/View-Descriptoren. Die Data-Referenz bleibt dadurch nach
|
||
Graph-Detach sichtbar. `Buffer` selbst bleibt nicht `Send`/`Sync`; nur der private,
|
||
nicht zugängliche Allocation-Besitz darf abschließend vom Completion-Thread über
|
||
die bereits mutex-geschützte native Freigabe zerstört werden.
|
||
|
||
Damit ist eine konkrete COW-Lücke an der gemeinsamen `QsaArray.shared_storage`-
|
||
Grenze geschlossen: bisher wurden nur mehrere `Rc<Buffer>` erkannt, nicht zwei
|
||
verschiedene Buffer-Views derselben Allocation. Der direkte gepinnte MTPLX-Test
|
||
(`QSACache.write_raw`, Runtime 0.32.2, modellfrei) bestätigt für ein Update 1→2:
|
||
Ein Alias desselben Array-Objekts sieht 2, eine vorher ausgewertete View bleibt 1.
|
||
Der entsprechende Rust-Test wurde negativ geprüft: Nur die alte Besitzprüfung
|
||
wiederhergestellt ergibt einen Fehlschlag (View fälschlich 2); die Korrektur
|
||
erhält 1. Die bestehende Sammlung und ihre numerischen Fixtures bleiben erhalten.
|
||
Der Completion-Test prüft zusätzlich verschachtelte Views, Root-Lebensdauer und
|
||
sichtbaren GPU-Data-Besitz vor/nach Abschluss. Belege:
|
||
`local-eval-results/20260906-mtplx-port/qsa-data-ownership-check.log`.
|
||
Normaler und verschärfter Lauf bestehen mit jeweils 34/34 Tests; Kernelquellen-
|
||
Prüfung, produktiver Release-Buildcheck, Formatierung und Release-Test-Clippy
|
||
bestehen ebenfalls. Die Abhängigkeit `block 0.1.6` meldet weiterhin nur ihren
|
||
bekannten Future-Incompatibility-Hinweis.
|
||
|
||
Die QSA-Graphauswertung registriert inzwischen nach jedem Primitiv dessen
|
||
Eingaben (einschließlich gebundener Projektionsparameter) und Geschwisterausgaben
|
||
als deduplizierte Data-Menge, abzüglich der tatsächlich ausgewerteten Hauptausgabe,
|
||
wie im gepinnten `backend/metal/eval.cpp`. Die Halterung beginnt vor dem nächsten
|
||
Primitiv, nicht erst beim letzten Graph-Verbraucher. Graph-Detach löst nun nur
|
||
die Descriptoren; ein zweites Halten dieser Blätter würde die Hauptausnahme
|
||
wieder aufheben. Backend-Scratch und Fehlerpfad behalten ihre eigene Halterung.
|
||
Der Scheduler führt dafür neben dem Produzenten diejenige Geschwisterausgabe mit,
|
||
deren geteilte Abhängigkeitszahl null wurde; sie ist nicht immer Ausgabe null.
|
||
Ein CPU-Test deckt unterschiedliche Root-Reihenfolgen und doppelte Kanten ab.
|
||
Ein Metal-Test prüft leere Batch-Fallbacks, deduplizierte Views, Hauptausgabe eins,
|
||
die Ausnahme bei geteiltem Eingabe-/Ausgabespeicher und Referenzzahlen vor/nach
|
||
GPU-Abschluss. Es gibt keinen neuen Flush, Wait, Kernel oder GPU-Readback.
|
||
Belege: `local-eval-results/20260906-mtplx-port/qsa-evaluator-holds-check.log`.
|
||
Die erweiterte Sammlung besteht normal und mit unretained Command Buffers jeweils
|
||
mit **36/36 Tests**. Kernelquellen-Prüfung, Release-Test-Clippy, produktiver
|
||
Release-Buildcheck und Formatprüfung bestehen ebenfalls.
|
||
|
||
### Tatsächliche Donation bei QSA-Cache-Updates
|
||
|
||
Die beiden BF16-`DynamicSliceUpdate`-Knoten verwenden jetzt wie das gepinnte
|
||
`backend/gpu/primitives.cpp` → `backend/common/copy.h` vorhandenen Speicher,
|
||
wenn der Vector-Copy-Donation-Vertrag erfüllt ist. Die neue Ausgabe erhält eine
|
||
eigene View-/Array-Identität auf demselben Data; der Vector-Copy-Dispatch entfällt,
|
||
die originale dynamische Zeilenkopie bleibt. Prüfkriterien am Ausführungszeitpunkt:
|
||
exklusiver Array-Descriptor, exklusives `Rc<Buffer>`/Data einschließlich GPU-Holds,
|
||
identischer Eingabedescriptor, ausreichender View-Bereich und höchstens 16 KiB
|
||
Überhang der **Root-Allocation**, nicht nur der kleineren View. Beide Elementtypen
|
||
sind in diesem installierten Cachepfad BF16; dies ist keine generische Dtype-Regel.
|
||
|
||
Der unveränderte Graph nimmt entweder festgehaltene Buffer-Eingaben oder exklusiv
|
||
veränderlichen `QsaCacheInput::State` entgegen. Die verbundene Hostmethode heißt
|
||
nun `qsa_indexer_rows` und gibt den echten Cache über die State-Variante hinein.
|
||
Snapshots/Views bleiben durch die gemeinsame Besitzprüfung geschützt. Es gibt
|
||
keinen zweiten Algorithmus und keine Donation-Einstellung für Anwender.
|
||
|
||
Alle 198 bestehenden Q/K-/Hidden-Referenzfälle laufen zusätzlich durch die
|
||
State-Variante mit lebenden Snapshots und anschließend exklusivem Besitz. Gleiche
|
||
Ausgabe-/Zustandshashes, unveränderte Snapshot-Hashes und tatsächliche unterschiedliche
|
||
bzw. identische Data-Adressen prüfen Kopieren und Donation getrennt. Die zwei
|
||
zusätzlichen Durchläufe sind keine neuen unabhängigen Referenz-Fixtures. Ein
|
||
zusätzlicher Test prüft Descriptor-Aliase, geteilte Storage-Snapshots, native Views,
|
||
GPU-Data-Holds sowie Überhänge 0/16384/16386 Byte. Reproduktionsbelege:
|
||
`local-eval-results/20260906-mtplx-port/qsa-cache-donation-check.log`.
|
||
Normaler und verschärfter Lauf bestehen mit **37/37 Tests**. Kernelprüfung,
|
||
Release-Test-Clippy, produktiver Release-Buildcheck und Formatprüfung bestehen.
|
||
|
||
### Allocator: Referenzfolge, Cache-Auswahl und Größenrundung
|
||
|
||
`tools/mtplx-allocator-reference.py` zeichnet 101 echte modellfreie Allokations-,
|
||
Freigabe-, Limit- und Clear-Ereignisse der installierten MTPLX-Runtime 0.32.2 auf.
|
||
`tests/fixtures/mtplx-allocator.jsonl` hält aktive/gecachete Bytes, tatsächliche
|
||
Buffergrößen und lauflokal anonymisierte physische Buffer-Identitäten fest.
|
||
Es ist kein nachgebauter Python-Allocator und kein Performance-Benchmark.
|
||
|
||
Die Rust-Implementierung von `backend/common/buffer_cache.h` verwendet zwei
|
||
geordnete Standard-Maps anstelle der C++-Multimap plus intrusiver Zeigerliste.
|
||
Sie erhält Best-Fit, älteste Einfügung bei gleicher Größe, die strikte Grenze
|
||
`min(2*Anforderung, Anforderung+2*Seitengröße)`, altersbasierte Teilfreigabe und
|
||
vollständiges Leeren ab 90% angeforderter Freigabe. Bei vollständigem Leeren
|
||
bleibt die größenbasierte Reihenfolge erhalten. Der Replay-Test prüft alle
|
||
101 Zustandsübergänge und wiederverwendeten Buffer-Identitäten; außerdem die
|
||
Grenzen beim Ändern des Cache-Limits und dessen erlaubtes kurzfristiges
|
||
Überschreiten bei Freigabe. Der Cache ist noch nicht an native Ressourcen gebunden.
|
||
|
||
Die Größenrundung aus `MetalAllocator::malloc` ist bereits an `Buffer::bytes`
|
||
und `Buffer::untracked` der testgebundenen Schicht angeschlossen: Anforderung
|
||
zuerst gegen das wirkliche Metal-`maxBufferLength` prüfen, nur oberhalb einer
|
||
VM-Seite aufrunden. Auf diesem M5 Max beträgt die Seite 16384 Byte. Eine logische
|
||
View erhält die angeforderte Tensorgröße; Data besitzt weiterhin die vollständige
|
||
Allocation. Dadurch sehen Donation und Speicherzählung die tatsächliche Größe,
|
||
während Read-/Write-Grenzen unverändert bleiben. Die native Ergänzung liest nur
|
||
die Metal-Gerätegrenze; Auswahl-/Rundungslogik bleibt Rust.
|
||
Der Metal-Test prüft beide vorhandenen Resource-Optionen und 1/255/256 Byte sowie
|
||
die Seitengrenzen. Die Donation-Grenztests verwenden jetzt die real gerundeten
|
||
Root-Größen. Kernel und Synchronisationsgrenzen bleiben unverändert.
|
||
Belege: `local-eval-results/20260906-mtplx-port/allocator-policy-check.log`.
|
||
Normaler und unretained Metal-Lauf bestehen mit jeweils **39/39 Tests**;
|
||
Kernelprüfung, Release-Test-Clippy, produktiver Release-Buildcheck und
|
||
Formatprüfung bestehen ebenfalls.
|
||
|
||
Noch offen für den vollständigen Allocator: Bindung des Pools an die echte
|
||
Data-Freigabe, 1-MiB-Heap für Anforderungen unter 256 Byte, Residency/Wired-Limit,
|
||
Ressourcen-/GC-/Speicherlimits und deren Zähler sowie die leere Array-/Null-Buffer-
|
||
Repräsentation. Die vorhandenen Resource-/Hazard-Optionen wurden nicht pauschal
|
||
umgestellt; dazu gehört die noch fehlende vollständige Encoder-Abhängigkeitslogik.
|
||
|
||
Dies ist noch **keine vollständige Donation-/Evaluator-Parität**: Außerhalb des
|
||
QSA-Graphen fehlt die modellweite Integration dieser Regeln; ebenso andere
|
||
Primitive und generische Typ-/Layoutzweige. Vollständiger Modellgraph und produktive Integration bleiben
|
||
offen. Der produktive FP32-Pfad erhält durch diese testgebundene Besitzschicht
|
||
keine neue Referenzzählung; keine Durchsatz- oder UI-Parität wird behauptet.
|
||
|
||
### Allocator: GPU-Ressourcenbesitz unabhängig von Data-Donation
|
||
|
||
Die gemeinsame kanonische Dispatch-Schicht hält jetzt Rust-Allocation-Besitz
|
||
bis zum Abschluss des zugehörigen Metal-Command-Buffers. `BufferData` besitzt
|
||
eine gemeinsame Root-Allocation; GPU-Bindings halten diese Allocation, nicht
|
||
Data. Damit bleibt die vorhandene referenzkonforme Donation-Prüfung unabhängig
|
||
von der physischen GPU-Ressourcenhaltung. Nur der letzte Allocation-Besitzer
|
||
gibt den nativen Root frei. Diese Trennung ist für die noch ausstehende Pool-
|
||
Anbindung erforderlich: Ein bloßer nativer `MTLBuffer`-Retain verhindert zwar
|
||
Deallokation, aber nicht die verfrühte Wiederverwendung durch einen Rust-Pool.
|
||
|
||
Rust dedupliziert Root-Allocations pro Dispatch. Die bestehende native
|
||
Completion-Registrierung übernimmt den Rust-Besitz atomar und setzt den
|
||
Übergabezeiger auf null; bei früher Validierungs-/Pipeline-/Encoder-Ablehnung
|
||
behält und bereinigt Rust ihn. Der Callback ersetzt in diesem Pfad das native
|
||
Resource-Set, ohne zusätzliche Callbacks, Flushes, Commits oder Wartepausen.
|
||
Der rohe ABI-Pfad ohne Rust-Owner behält seine bisherige native Haltung.
|
||
Die typisierten Bindings binden zudem die Lebensdauer von Tensor-Views und
|
||
Scalar-Zeigern an ihre Rust-Referenzen bis zur Übergabe.
|
||
|
||
Ein modellfreier Metal-Test prüft Deskriptor-/Data-Detach bei noch uncommitteter
|
||
GPU-Arbeit, Allocation-Lebensdauer, unveränderte Data-Donation, Deduplikation
|
||
bei In-place-Bindings, Freigabe nach Completion, synchrone Einzel-Dispatches
|
||
sowie zurückbehaltenen Besitz bei Validierungsfehlern. Beide vollständigen
|
||
kanonischen Sammlungen bestehen mit **40/40 Tests**, normal und mit
|
||
`DS4_METAL_UNRETAINED_COMMAND_BUFFERS=1`; alle bisherigen Referenzhashes bleiben
|
||
gleich. Beleg: `local-eval-results/20260906-mtplx-port/allocation-lifetime-check.log`.
|
||
Kernelprüfung, Release-Test-Clippy und produktiver Release-Buildcheck bestehen.
|
||
|
||
Zu dieser Zwischenstufe war der Pool noch nicht aktiviert. Der folgende
|
||
Abschnitt dokumentiert die anschließende native Anbindung; modellweiter
|
||
Evaluator und produktive Integration bleiben offen.
|
||
|
||
### Allocator: Nativer Pool, Heap und Limits
|
||
|
||
`Allocator` bindet die bestehende Cache-Politik jetzt an echte native Roots und
|
||
deren finale Allocation-Freigabe an. Das gilt einschließlich der GPU-Besitzer
|
||
des gemeinsamen Dispatch-Pfads: Solange ein Command Buffer noch auf Speicher
|
||
zugreift, bleibt dieser aktiv und kann nicht als Cache-Treffer vergeben werden.
|
||
Die Besitzerstruktur enthält keinen Zyklus: Der Cache besitzt native Roots,
|
||
nicht die Allocation-Deskriptoren, die ihrerseits den Allocator halten.
|
||
|
||
Die Rust-Seite übernimmt die vollständige bisher portierte malloc/free-Policy:
|
||
Cache-Suche vor GC, ursprüngliche Best-Fit-Grenzen, aktive/gecachete/Peak-Bytes,
|
||
Ressourcenzähler, Cache-Limitwechsel ohne sofortiges Leeren, Trimmen erst nach
|
||
Allokation, Memory-Limit/GC-Schwelle und Ressourcenlimit. Auch die unsigned
|
||
Subtraktion bei ausschließlich ressourcenbedingtem Druck bleibt erhalten.
|
||
Ein Memory-Limit ist hier wie in der Referenz keine harte Ablehnung einer
|
||
größeren Allokation. Anfangswerte stammen aus den tatsächlichen Metal-/sysctl-
|
||
Werten und den Referenzformeln; Resource-Limit-Fallback ist 499000.
|
||
|
||
Die native Ergänzung stellt nur Metal-Plattformoperationen bereit: einen
|
||
1-MiB-Heap, Buffer daraus oder als Fallback direkt vom Gerät sowie Freigaben.
|
||
Rust wählt den Heap ausschließlich für Anforderungen unter 256 Byte.
|
||
Die Ressourcenoptionen sind `Shared | HazardTrackingUntracked`. Die Paravirtual-
|
||
Ausnahme bleibt erhalten. Null/0 Byte liefert `None`, keine künstliche
|
||
Ein-Byte-Allokation; vorhandene Array-APIs müssen diese Darstellung noch
|
||
modellweit übernehmen. Logische Views bewahren die ursprünglichen Tensorgrenzen
|
||
auch bei gerundeten oder größeren wiederverwendeten Roots.
|
||
|
||
Der native Replay-Test führt alle **101 Referenzereignisse** mit echten
|
||
Allokationen aus und prüft nach jedem Schritt aktive/gecachete/Peak-Bytes,
|
||
Ressourcenzahl und logische/physische Größen. Cache-Treffer müssen tatsächlich
|
||
dieselben Speicheradressen zurückgeben; neue Geräteallokationen dürfen andere
|
||
Adressen als beim Referenzprozess haben. Ein weiterer Test prüft 1/255/256/257-
|
||
Byte-Heap-Routing, Erschöpfung der 1-MiB-Heap-Slots mit Geräte-Fallback,
|
||
Memory-/Ressourcen-GC, unveränderte Zähler bei Ressourcenablehnung und echte
|
||
Cache-Wiederverwendung erst nach GPU-Completion.
|
||
|
||
Beide kanonischen Sammlungen bestehen mit **42/42 Tests**, normal und unretained.
|
||
Beleg: `local-eval-results/20260906-mtplx-port/native-allocator-check.log`.
|
||
Clippy für Release-Tests, produktiver Release-Buildcheck, Original-Kernel- und
|
||
Formatprüfung bestehen. Es wurden keine Modellgewichte geladen.
|
||
|
||
**Verbleibende Integration:** Residency/Wired-Limit, externe/wrapped Buffer,
|
||
prozessweiter Allocator-Lebenszyklus, Routing aller kanonischen Allokationen
|
||
und vollständige Encoder-Abhängigkeiten. Der Allocator wird bislang explizit
|
||
von den modellfreien Tests verwendet, nicht vom vollständigen Modellpfad.
|
||
Die vorhandenen Helfer werden nicht vor der Abhängigkeits-Portierung pauschal
|
||
auf untracked Ressourcen umgestellt. Vollständiger Modellgraph, UI/Harness-
|
||
Produktionspfad und ±2%-Performance-Abnahme bleiben weiterhin unerledigt.
|
||
|
||
### Allocator: Residency und Wired-Limits
|
||
|
||
`qwen_mtplx/residency.rs` portiert die Regeln aus dem gepinnten
|
||
`backend/metal/resident.cpp`: Metal-3/macOS-15-Freigabe, initiales Set mit
|
||
stehender Residency-Anforderung, 5%-Standardcap mit 64-MiB-Untergrenze,
|
||
Single-Set-Modus, First-Fit, Wiederverwendung leerer Sets für übergroße
|
||
Allokationen und Emptiest-Fallback bei 32 Sets oder späterem Treiberfehler.
|
||
Die ursprünglichen Umgebungsvariablen und deren einmalige `atoi`-Auswertung
|
||
bleiben erhalten. Rust führt Budgets, Sets und gespeicherte Allokationsgrößen;
|
||
die native Bridge enthält nur die Metal-Operationen.
|
||
|
||
Der Allocator registriert den Heap einmal und jeden Nicht-Heap-Root bei
|
||
Neuanlage. Cache-Einträge bleiben registriert/verdrahtet; tatsächliche Freigabe
|
||
entfernt sie vor dem nativen Release. Wired-Limitwechsel registrieren passende
|
||
bereits vorhandene Allokationen bzw. entfernen sie unter das neue Budget.
|
||
Pro berührtem Set erfolgt ein Commit. Weder Freigabe noch erneutes Setzen
|
||
desselben Limits befördert wartende Allokationen automatisch. Eine atomare
|
||
Set-Zahl erlaubt den schnellen Queue-Attach-No-op; neue Sets werden im Test
|
||
unmittelbar vor dem GPU-Commit angefügt, nicht bereits beim Allokieren.
|
||
|
||
Ein nativer Test überträgt die zehn Lifecycle-Szenarien aus der ursprünglichen
|
||
`tests/residency_tests.cpp` und prüft zusätzlich Cache-Verbleib, Limit-Ablehnung
|
||
und tatsächliche Metal-`allocationCount`-/`containsAllocation`-Ergebnisse.
|
||
Maximal rund 129 MiB werden dabei gleichzeitig verdrahtet. Die Tests prüfen
|
||
Budgets, Set-Auswahlregeln und native Mitgliedschaft; gleiche Adress-/Hash-
|
||
Bucket-Reihenfolgen zwischen zwei Prozessen werden damit nicht behauptet.
|
||
Der Resize-Durchlauf verwendet wie die Referenz eine ungeordnete Map.
|
||
|
||
Beide kanonischen Sammlungen bestehen mit **43/43 Tests**, normal und unretained;
|
||
Release-Test-Clippy, produktiver Release-Buildcheck, Original-Kernel- und
|
||
Formatprüfung bestehen. Beleg:
|
||
`local-eval-results/20260906-mtplx-port/residency-check.log`.
|
||
|
||
**Weiter offen:** automatische Anbindung an sämtliche tatsächlichen Encoder-
|
||
Commit-Pfade, externe/wrapped Buffer, prozessweiter Besitzer, vollständiges
|
||
Routing der Modellallokationen und Encoder-Abhängigkeiten. Der explizite
|
||
Allocator ist weiterhin testgebunden; es gibt keinen neuen Gesamtmodell-
|
||
Benchmark und weiterhin keinen Nachweis der verlangten ±2%-Parität.
|
||
|
||
### Submission: Residency an tatsächlichen Commit-Grenzen
|
||
|
||
`qwen_mtplx/submission.rs` hält Queue, Allocator und den bereits angefügten
|
||
Set-Index über mehrere Command-Batches hinweg. Ein Scope registriert einen
|
||
threadlokalen, synchronen Rust-Callback vor dem tatsächlichen nativen Commit.
|
||
Beim Erstellen werden vorhandene Sets angefügt; vor jedem späteren Commit
|
||
werden nur neu entstandene Sets ergänzt. Nested Scopes können den Besitzer
|
||
nicht überschreiben. Finish/Drop lassen den Besitzer bis nach dem Drain leben
|
||
und entfernen dann den Callback; danach erbt der Legacy-Pfad keinen Hook.
|
||
|
||
Alle zwölf bisherigen direkten Command-Buffer-Commit-Stellen der Bridge
|
||
laufen jetzt durch einen gemeinsamen Einstieg, einschließlich Flush,
|
||
Readback, Cleanup und GLM-Streaming-Split. Der Hook ist nur im kanonischen
|
||
Scope aktiv und auf dessen Encoding-Thread sowie die Haupt-Queue begrenzt;
|
||
andere Queues bleiben ausgenommen. Metal-Residency-Set-Commits bleiben eigene
|
||
Operationen. Es entstehen keine zusätzlichen Command Buffers, Flushes oder
|
||
Wartepausen. Ein Quelltest schützt gegen erneute direkte Commit-Umgehungen.
|
||
|
||
Der native Test prüft nachträglich erzeugte Sets, Flush, Eval, Finish, Drop,
|
||
native interne Batch-Beendigung mit anschließendem synchronen Einzel-Dispatch
|
||
und das Entfernen des Hooks. Die kanonische Sammlung besteht normal und
|
||
unretained mit **45/45 Tests**. Release-Test-Clippy, produktiver Release-
|
||
Buildcheck, Original-Kernel- und Formatprüfung bestehen ebenfalls. Beleg:
|
||
`local-eval-results/20260906-mtplx-port/submission-check.log`.
|
||
|
||
Dies schließt den bisher manuellen Residency-Attach für diesen testgebundenen
|
||
Scope, **nicht** den gesamten MTPLX-Encoder. Weiter offen sind die genaue
|
||
Input-/Output-Klassifikation aller Bindings, Barrier-Epochen, ConcurrentContext,
|
||
Encoder-Fences/Completion-Bereinigung, Ops-/Byte-Commit-Schwellen und vollständige
|
||
Modell-/Produktintegration. Der produktive Qwen-Graph nutzt den Scope noch nicht;
|
||
Gesamtmodell-Performance und ±2%-Abnahme bleiben unbewiesen.
|
||
|
||
### Encoder: abhängige Ausführung, Fences und Shared Events
|
||
|
||
`qwen_mtplx/encoder.rs` portiert die zusammengehörige Steuerung aus MTPLXs
|
||
gepinntem Runtime-`backend/metal/device.cpp`, einschließlich `event.cpp` und
|
||
der verbrauchenden Fehlersemantik aus `error.h`. Rust besitzt eine eigene Queue
|
||
und unretained Command Buffers. Jeder Compute-Encoder ist Concurrent; Rust
|
||
entscheidet anhand tatsächlicher Metal-Buffer-Identitäten über Read/Write-
|
||
Barrieren, aktuelle Barrier-Epochen, deferred ConcurrentContext-Ausgänge und
|
||
deduplizierte Fence-Waits zwischen Encodern. Completion entfernt einen Producer
|
||
nur, wenn dessen Fence noch aktuell ist. Temporäre Ressourcen werden aus den
|
||
encoderübergreifenden Mengen entfernt und bis Completion gehalten.
|
||
|
||
Shared-Event-Wait und -Signal beenden den aktuellen Encoder. Completion führt
|
||
zuerst den Benutzer-Callback aus, übernimmt den ersten gültigen fremden
|
||
Wait-Event-Fehler und danach gegebenenfalls einen GPU-Fehler. Signal-Events
|
||
teilen den konsumierbaren Fehlerzustand des Encoders; bei GPU-Fehlern werden
|
||
sie zusätzlich auf der CPU signalisiert, damit wartende Queues nicht hängen.
|
||
Synchronize wirft/entnimmt den Fehler; der Destruktor wartet, ohne ihn zu
|
||
entnehmen. Fence-, Event- und Buffer-Holds bleiben bis Completion gültig.
|
||
|
||
Die ursprünglichen Commit-Schwellen und ihre einmaligen Umgebungsvariablen
|
||
werden übernommen. **Korrektur der bisherigen Byte-Bezeichnung:** Der gepinnte
|
||
Code addiert `array.data_size()` ohne Multiplikation mit `item_size`. Laut
|
||
`array.h` sind das Elemente, keine Bytes. Auf Max/Ultra gilt daher strikt
|
||
`ops > 50 || (data_size >> 20) > 50`. Ein Buffer zählt beim ersten Input-Eintrag
|
||
je Encoder; die Summen werden erst beim Command-Commit zurückgesetzt. Raw-
|
||
Buffer-Bindings zählen als encoderübergreifende Ein- und Ausgänge, ändern aber
|
||
weder die Barrier-Epochen noch den Größenzähler. Es gibt keine zusätzlichen
|
||
automatischen Sleeps oder pro-Layer-Waits.
|
||
|
||
Die native Bridge benutzt denselben validierenden Pipeline-/Binding-/Dispatch-
|
||
Code für den bisherigen und den explizit übergebenen Encoder. Sie entscheidet
|
||
nicht über Abhängigkeiten, Batching oder Fehlerweitergabe. Der neue Rust-
|
||
Encoder lehnt Tensor-Bindings ohne explizite Input/Output/Raw-Rolle ab, statt
|
||
aus Buffergrößen oder Kernel-Namen Zugriffsrollen zu erraten.
|
||
|
||
Drei neue Checks prüfen Barrier-/Commit-Epochen, disjunkte Concurrent-Outputs,
|
||
abhängige untracked Kopien über mehrere Encoder und asynchrone Command Buffers,
|
||
Fence-Deduplizierung/Completion-Rennen, temporäre Buffer, beide Dispatch-
|
||
Geometrien sowie reale Shared-Event-Transfers zwischen zwei Queues. Fehler-
|
||
Completion wird gezielt mit einem synthetischen GPU-Status geprüft, ohne einen
|
||
GPU-Hänger auszulösen. Die gesamte Sammlung besteht normal mit **48/48** und
|
||
unretained mit **48/48 Tests**; Clippy, produktiver Release-Buildcheck und
|
||
Original-Kernel-Abgleich bestehen. Beleg:
|
||
`local-eval-results/20260906-mtplx-port/encoder-check.log`.
|
||
|
||
**Nicht abgeschlossen:** Dieser Encoder ist weiterhin testgebunden. Vollständige
|
||
Zugriffsrollen und exakte Array-`data_size`-Metadaten aller Operator-Bindings,
|
||
Routing der Allokationen, Stream-/Scheduler-/Graph-Integration einschließlich
|
||
aller Eval- und Completion-Grenzen sowie der komplette Modellpfad fehlen noch.
|
||
Die große bestehende Kernelsammlung läuft weiterhin über den bisherigen
|
||
Dispatch-Pfad; nur die neuen Encoder-Tests benutzen die eigene Queue. Der alte
|
||
Submission-Scope ist damit noch keine Produktintegration. P05 und der gesamte
|
||
Paritätsaudit bleiben offen; keine neue UI-/Gesamtmodell- oder ±2%-Abnahme.
|
||
|
||
### Operator-Routing: Normen und zusammenhängende MoE-Kette
|
||
|
||
Ein threadgebundener `Scope` verbindet die vorhandenen Operatorfunktionen jetzt
|
||
mit dem eigenen Concurrent-Encoder und demselben gepoolten, untracked Allocator.
|
||
Er fügt keine Dispatch-/Eval-Grenzen ein. Nested Scopes werden abgelehnt; nach
|
||
dem Scope erbt der bisherige Pfad weder Encoder noch Allocator. Der Besitzer
|
||
bleibt über mehrere Operationsketten hinweg bestehen und wartet beim Abbau.
|
||
Die Dispatch-Implementierung und die vorhandenen Fixture-Auswertungen werden
|
||
wiederverwendet, nicht als zweiter Operatorpfad nachgebaut.
|
||
|
||
Explizite Ein-/Ausgangsrollen und Elementspannen sind für die gesamte
|
||
Norm-/MoE-Kette übernommen: Softmax/Top-10-Router, Argsort mit Multi-Block-Merge,
|
||
Gather/Unsort, Gate/Up und SwiGLU, Grouped-/Gated-RMS, BF16/FP32-Casts,
|
||
Affine-QMV/QMM einschließlich Split-K, Gather-QMM einschließlich sortiertem
|
||
RHS und Broadcast-Indizes, Stock-/Fused-MoE sowie Shared Expert und Gate.
|
||
Geslicte Inputs zählen wie `backend/common/slicing.cpp` ihre adressierte
|
||
Elementspanne, nicht die volle Allokation oder nur die Zahl logischer Werte.
|
||
Broadcast-Indizes behalten ihre tatsächliche Speicherspanne.
|
||
|
||
Zwei bisherige `setBytes`-Ersatzbindungen sind durch die ursprünglichen skalaren
|
||
Array-Inputs ersetzt: das Einheitsgewicht für ungewichtete RMSNorm und der
|
||
Divisor in GatherSort. Sortier- und Split-K-/Reduktions-Scratch werden an den
|
||
ursprünglichen Stellen als Backend-Temporaries registriert. Ihre Lebensdauer
|
||
und ihr Ausschluss aus den encoderübergreifenden Ressourcenmengen laufen damit
|
||
über den portierten Encoder, nicht nur über zurückgegebene Rust-Bufferlisten.
|
||
Original-Kernel, Rundungsfolgen und Geometrien bleiben unverändert.
|
||
|
||
Neun vorhandene Fixture-Gruppen werden ohne Abschwächung ihrer Ausgabehash-
|
||
Prüfungen jeweils im bisherigen und im neuen Encoder ausgeführt:
|
||
78 Affine, 40 Gather-QMM, 123 Argsort, 7 GatherSort, 16 Router, 10 Gate/Up,
|
||
25 Normen, 21 SwitchGLU und 220 MoE — insgesamt **540 Referenzfälle in beiden
|
||
Encodern**. Das sind zusätzliche Ausführungen vorhandener Fälle, keine neuen
|
||
unabhängigen Referenz-Fixtures. Die Tests unterscheiden native Legacy-Busy-
|
||
Zähler ausdrücklich vom Commit-Zähler der eigenen Queue. Der neue Scope-Test
|
||
prüft zudem tatsächliche Pool-Allokation, Cache-Rückgabe, den Gate/Up-
|
||
Speicherspannenzähler und genau eine erforderliche Barrier ohne Zwischencommit.
|
||
|
||
Die gesamte kanonische Sammlung besteht mit **49/49 Tests** sowohl normal als
|
||
auch mit unretained Legacy-Command-Buffers. Release-Test-Clippy, produktiver
|
||
Release-Buildcheck, Format-/Diff-Prüfung und Original-Kernel-Abgleich bestehen.
|
||
Beleg: `local-eval-results/20260906-mtplx-port/operator-encoder-check.log`.
|
||
|
||
**Weiter offen:** GDN-/QSA-Operator-Routing, allgemeine Array-Metadaten/Donation,
|
||
vollständige Stream-/Evaluator-/Graph-Anbindung und deren tatsächliche Eval-,
|
||
Commit- und Completion-Grenzen sowie der produktive Gesamtmodellpfad. Ein
|
||
manuell abgegrenzter Operator-Testbatch beweist nicht die Scheduling-Parität
|
||
eines gesamten MTPLX-Chats. Der eigene Encoder ist noch nicht mit der normalen
|
||
UI-/Harness-Instrumentation verbunden. Die ±2%-Abnahme bleibt ausstehend.
|
||
|
||
### Operator-Routing: zusammenhängende GDN-Kette
|
||
|
||
GDN verwendet nun ebenfalls den gemeinsamen Dispatch mit expliziten Input-/
|
||
Output-Rollen und Array-Elementspannen: Conv/Mask/Cache, Q/K-L2-Norm, compute_g,
|
||
Sigmoid, rekurrentes Delta-Update, Fused-Step und Fused-Output. Der bisherige
|
||
direkte native Fused-Step-Aufruf entfällt. Projektionen und Gated-Norm verwenden
|
||
die bereits angebundenen Operatoren; Original-Kernel und Geometrien bleiben
|
||
unverändert. Binäre skalare Operanden und das CustomKernel-T-Argument sind echte
|
||
skalare Array-Inputs, keine `setBytes`-Ersatzbindungen.
|
||
|
||
`backend/metal/slicing.cpp::concatenate_gpu` bestimmt den Conv-Fenster-Aufbau:
|
||
disjunkte Output-Slices mit ihrer jeweiligen `data_size`, eine Concurrent-Region
|
||
für beide Kopien und anschließender Dependency-Join. Ein RAII-Guard stellt den
|
||
Join auch bei vorzeitigem Fehler sicher. CustomKernel-Eingangskopien werden in
|
||
Input-Reihenfolge nach der Output-Allokation ausgeführt und nach dem Dispatch
|
||
als Backend-Temporaries registriert. Die fehlende Conv-State-Kopie im Fused-Step
|
||
liegt jetzt hinter der Eingangsprojektion statt davor.
|
||
|
||
Die vier bestehenden Gruppen mit 80 Delta-Update-, 2 laufenden Fused-Step-,
|
||
130 Staged- und 264 Forward-Fällen laufen jetzt jeweils in beiden Encodern.
|
||
Zusammen mit Norm/MoE sind das **1.016 vorhandene Referenzfälle in beiden
|
||
Encodern**, ohne neue oder abgeschwächte Referenz-Hashes. Die Forward-Fälle
|
||
prüfen auch fortgesetzte Zustände, Nullzustände, Masken, gültige Längen,
|
||
Projektionslayouts und die gewählten Fusionszweige.
|
||
|
||
Die gesamte Sammlung besteht normal mit **49/49 Tests (35,79 s)** und mit
|
||
unretained Command Buffers mit **49/49 Tests (35,28 s)**. Release-Test-Clippy,
|
||
produktiver Release-Buildcheck, Format-/Diff-Prüfung und Original-Kernel-Abgleich
|
||
bestehen. Beleg: `local-eval-results/20260906-mtplx-port/gdn-encoder-check.log`.
|
||
|
||
**Weiter offen:** QSA-Operator-Routing, allgemeine Array-/Donation-Verträge,
|
||
der vollständige Evaluator mit tatsächlichen Eval-/Commit-/Completion-Grenzen,
|
||
Stream-Anbindung, UI-/Harness-Instrumentation und produktiver Gesamtmodellpfad.
|
||
Diese GDN-Integration ist noch kein vollständiger Modellgraph und keine
|
||
Performance-Paritätsabnahme. P05 und der Gesamtauftrag bleiben offen.
|
||
|
||
### QSA-Cache-Kopien und kompilierte Cache-Fenster am Encoder
|
||
|
||
Die gemeinsamen QSA-Kopierfunktionen tragen jetzt explizite Array-Metadaten:
|
||
statische Source-Slices zählen ihre adressierte Elementspanne; Slice-Updates
|
||
binden das vollständige Zielarray, Concatenate dagegen die logische Größe
|
||
seines Output-Slices. Dynamische Kopien erhalten beide vollständigen Array-
|
||
`data_size`-Werte vom Aufrufer, unabhängig von der kopierten Zeilenzahl. Der
|
||
Encoder-Test prüft genau diese Unterscheidung sowie die Ablehnung zu kleiner
|
||
Metadaten. Konstanten, die im Original Arrays sind, bleiben skalare Arrays;
|
||
die dynamischen Offset-Arrays sind Inputs und Backend-Temporaries.
|
||
|
||
Zero-Fill, COW-/General-Kopien, die kompilierten Frontier-Operationen und die
|
||
fused Query-/Pool-Vorbereitung benutzen explizite Ein-/Ausgangsrollen.
|
||
Die KV-Vergrößerung verwendet für ihre disjunkten Concatenate-Kopien den
|
||
originalen Concurrent-Kontext. Kernelquellen und Dispatch-Geometrien wurden
|
||
nicht verändert. Die vorhandenen 12 Backing-/Dynamic-Copy- und 26 Cache-Window-
|
||
Fälle laufen mit identischen Hash-Prüfungen in beiden Encodern; insgesamt sind
|
||
damit **1.054 bestehende Referenzfälle in beiden Encoder-Pfaden** abgedeckt.
|
||
|
||
Gesamtsammlung: **49/49 normal (35,53 s)** und **49/49 unretained (35,11 s)**.
|
||
Release-Test-Clippy, produktiver Release-Buildcheck, Format-/Diff-Prüfung und
|
||
Original-Kernel-Abgleich bestehen. Beleg:
|
||
`local-eval-results/20260906-mtplx-port/qsa-copy-encoder-check.log`.
|
||
|
||
**Weiter offen:** Das ist noch nicht die komplette QSA-Kette. Insbesondere
|
||
eager RoPE/Pooling, Score-Produzenten und Selektoren, sämtliche verbleibenden
|
||
Concurrent-/Eval-Grenzen und der vollständige Graph-/Produktionspfad müssen
|
||
weiter angebunden werden. Die neuen Cache-Fälle ersetzen weder die vollständige
|
||
Modellprüfung noch die geforderte Performance-Abnahme.
|
||
|
||
### QSA-Vorbereitung, Cache-Fortsetzung und fused Selektor am Encoder
|
||
|
||
Die eager Query-/Pool-Vorbereitung verwendet jetzt ebenfalls explizite
|
||
Ein-/Ausgangsrollen und die adressierten Elementspannen. Alle drei RoPE-
|
||
Concatenates haben die ursprünglichen Concurrent-Regionen samt anschließenden
|
||
Dependency-Joins. Positions-, Amplituden- und Mittelwertskalierung verwenden
|
||
skalare Array-Operanden; die BF16-/FP32-Grenzen bleiben unverändert. Die
|
||
vorhandenen Norm-, Cast- und General-Copy-Operatoren werden weiterverwendet.
|
||
|
||
Der fused Selektor und seine Chunk-Zusammenführung sind ebenfalls angebunden.
|
||
Die drei Frontier-Arrays werden wie im Original separat angelegt statt als
|
||
drei Views derselben Allokation. Seine private Score-Ausgabe bleibt ein
|
||
CustomKernel-Output, keine als Backend-Temporary deklarierte Arbeitskopie.
|
||
Numerische Kernelquellen und Dispatch-Geometrien sind unverändert.
|
||
|
||
Die vorhandenen 210 Vorbereitungs-/Projektions-, 88 laufenden Cache- und 75
|
||
Selektor-/Chunk-Fälle werden nun in beiden Encodern geprüft, einschließlich
|
||
Trim/Reserve/Restore und Descriptor-/Data-Alias-Verhalten. Insgesamt laufen
|
||
damit **1.427 bestehende Referenzfälle in beiden Encoder-Pfaden**. Die Cache-
|
||
Tests enthalten auch reine Metadatenoperationen; ihre manuellen Testgrenzen
|
||
sind ausdrücklich keine Behauptung identischer Modell-Eval-Grenzen.
|
||
|
||
Gesamtsammlung: **49/49 normal (36,34 s)** und **49/49 unretained (36,33 s)**.
|
||
Release-Test-Clippy, produktiver Release-Buildcheck, Format-/Diff-Prüfung und
|
||
Original-Kernel-Abgleich bestehen. Beleg:
|
||
`local-eval-results/20260906-mtplx-port/qsa-prepare-encoder-check.log`.
|
||
|
||
**Weiter offen:** getrennte Score-Produzenten, eager Selektions-/Ausgabepfade,
|
||
komplette Graph-/Stream-/Evaluator- und Produktionsanbindung samt Instrumentation.
|
||
Die bisherige minimale Platzhalter-Allokation für leere Selektor-Arrays ist
|
||
unverändert; ein allgemeiner Null-Storage-Array-Vertrag fehlt weiterhin.
|
||
Keine dieser Operator-Prüfungen ist eine vollständige Modell- oder Performance-
|
||
Abnahme. Der gesamte Paritätsauftrag bleibt offen.
|
||
|
||
### QSA-Score-Produzenten und verbundener Prefill am Encoder
|
||
|
||
Beide Score-Produzenten, Prefill-Top-k und die bestehende Chunk-Verkettung laufen
|
||
jetzt über den unabhängigen Encoder. Der FP32-Pfad bindet GEMV, Steel/NAX,
|
||
Split-K samt Akkumulation, Maximum und Reduktion mit expliziten Array-Rollen
|
||
und Elementspannen. Maximum/Divide verwenden echte skalare Arrays. Matmul
|
||
allokiert seinen Output vor den Transpose-Kopien; diese Kopien und Split-K-
|
||
Scratch werden nach ihren Konsumenten als Backend-Temporaries registriert.
|
||
AsType- und Score-Zwischenergebnisse bleiben normale Graph-Arrays.
|
||
|
||
Der MPP-Pfad behält seine stridefähigen Eingaben ohne zusätzliche Kopien.
|
||
Prefill-Top-k allokiert alle Outputs vor der erforderlichen General-Copy,
|
||
registriert diese Arbeitskopie nach dem Dispatch und verwendet drei separate
|
||
Frontier-Arrays. Kernelquellen, Spezialisierungen und Dispatch-Geometrien bleiben
|
||
unverändert. Vorhandene Operatoren und Referenzfälle werden wiederverwendet.
|
||
|
||
Die 384 FP32-Score-, 146 MPP/Top-k/Prefill- und 96 gemischten Producer-Fälle
|
||
bestehen nun in beiden Encodern mit unveränderten Originalhashes. Insgesamt:
|
||
**2.053 bestehende Referenzfälle in beiden Encoder-Pfaden**. Die bestehenden
|
||
manuellen Testgrenzen ergeben jeweils genau ein Submission; sie behaupten
|
||
ausdrücklich keine identischen vollständigen Modell-Eval-Grenzen.
|
||
|
||
Gesamtsammlung: **49/49 normal (36,76 s)** und **49/49 unretained (37,19 s)**.
|
||
Release-Test-Clippy, produktiver Release-Buildcheck, Format-/Diff-Prüfung und
|
||
Original-Kernel-Abgleich bestehen. Beleg:
|
||
`local-eval-results/20260906-mtplx-port/qsa-score-encoder-check.log`.
|
||
|
||
**Weiter offen:** eager Selektions-/Ausgabepfade, vollständiger Graph, Streams,
|
||
Evaluator, allgemeiner Null-Storage-Vertrag und Produktionsanbindung samt
|
||
Instrumentation. Die produktive Qwen-Ausführung ist nicht umgeschaltet.
|
||
Diese Operator-Prüfungen ersetzen weder Modell- noch Performance-Abnahme;
|
||
der vollständige Paritätsauftrag bleibt offen.
|
||
|
||
### Eager QSA und verbundener Indexer am Encoder
|
||
|
||
Maskierung, Ranking und sämtliche eager Ausgabevarianten verwenden nun
|
||
explizite Array-Rollen/-Spannen und skalare Array-Operanden. Die negative
|
||
Unendlichkeit wird zwischen Kacheln geteilt. Jedes ursprüngliche `mx.eval(top_t)`
|
||
wartet auf der tatsächlich aktiven Queue; der unabhängige Pfad eröffnet dafür
|
||
keinen Legacy-Command-Buffer. Tiled-Index-, Decode-Tail-, Rows-Gather- und Dense-
|
||
Concatenates besitzen ihre ursprünglichen Concurrent-Regionen samt Join.
|
||
|
||
Zwei frühere Verkürzungen sind entfernt: Dense-Padding wird vor Concatenate
|
||
materialisiert, und Rows-Gather erzeugt seine beiden separaten Arange-Ausdrücke.
|
||
Vorhandene Originaloperatoren werden wiederverwendet, keine Kernelkörper oder
|
||
Spezialisierungen verändert. Der feste Indexer-Graph hält Input-/Sibling-Data
|
||
nun über Completion-Callbacks der aktiven Queue; primäre beziehungsweise
|
||
gespendete Output-Data bleiben ausgeschlossen. Graph-Concatenates sind ebenfalls
|
||
angebunden, und kompilierte Frontiers sind vier separate int32-Arrays.
|
||
|
||
Die bestehenden **540 eager Fälle und 200 laufenden Indexer-Aufrufe** laufen
|
||
jetzt in beiden Encodern, einschließlich kompilierter Varianten, Cache-
|
||
Fortsetzungen, Selektions-/State-Hashes, Graph-Engagement und expliziter Tile-
|
||
Eval-Anzahlen. Insgesamt **2.793 bestehende Dual-Encoder-Referenzfälle**.
|
||
Der vorhandene Data-Ownership-Test prüft zusätzlich beide Queues, Donation-
|
||
Ausschluss und das Ausbleiben einer Submission beim bloßen Registrieren von Holds.
|
||
|
||
Gesamtsammlung: **49/49 normal (40,19 s)** und **49/49 unretained (40,20 s)**.
|
||
Release-Test-Clippy, produktiver Release-Buildcheck, Original-Kernel-Abgleich,
|
||
Format-/Diff-Prüfung bestehen. Beide Referenz-Checkouts sind sauber und auf den
|
||
festgehaltenen Commits. Beleg:
|
||
`local-eval-results/20260906-mtplx-port/qsa-eager-encoder-check.log`.
|
||
|
||
**Weiter offen:** vollständiger Modellgraph und allgemeiner Stream-/Evaluator-
|
||
Scheduler, insbesondere die automatische Commit-Entscheidung nach Original-
|
||
Primitiven; allgemeiner Null-Storage-Vertrag und Produktionsanbindung samt
|
||
Instrumentation. Die manuellen Fixture-Grenzen ersetzen diese nicht. Der
|
||
produktive Qwen-Pfad ist weiterhin nicht umgeschaltet, und die vollständige
|
||
Modell-/Performance-Abnahme aller drei Modelle bleibt offen.
|
||
|
||
### Primitive-Commits und Scheduler am festen Indexer-Tape (2026-09-07)
|
||
|
||
Der Rust-Scheduler übernimmt die FIFO-Worker je CPU-Stream, früheste Fehler,
|
||
nicht konsumierende Event-Fehlerweitergabe, Synchronisation und abarbeitendes
|
||
Shutdown aus der von MTPLX verwendeten Runtime 0.32.2. Verwendet werden stdlib
|
||
und die vorhandene Shared-Event-Bridge, keine weitere Abhängigkeit. GPU-Encoding
|
||
bleibt auf dem aufrufenden Thread wie in der Referenz.
|
||
|
||
Der feste Indexer-Tape prüft die originale Commit-Bedingung jetzt nach dem
|
||
vollständigen Primitiv, nicht pro Kernel. Input-/Sibling-Data und Backend-Holds
|
||
sind davor an den betreffenden Command Buffer gebunden. Automatische Commits
|
||
zählen laufende Aufgaben, deren Completion beziehungsweise fehlgeschlagene
|
||
Übergabe den Zähler wieder ausgleicht. Die originale Druckbedingung
|
||
`tasks > 10 || (active_memory > memory_limit && tasks > 0)` finalisiert den
|
||
hier einzigen offenen GPU-Stream und wartet auf Fortschritt; keine neuen Sleeps.
|
||
|
||
Dabei fiel eine veraltete Testannahme auf: Der verbundene Indexer erwartete
|
||
pauschal die manuellen Tile-/Final-Submissions. Zwei volle Prefill-Fälle
|
||
(`compiled_s12_qk0_step0` und `compiled_s12_qk1_step0`) benötigen zusätzlich je
|
||
einen automatischen Commit: nach 17 Dispatches mit 57.469.227 beziehungsweise
|
||
55.246.572 gezählten Elementen gilt `(data_size >> 20) > 50`. Diese beiden
|
||
Fall-Erwartungen werden unabhängig vom Zähler der expliziten Synchronisationen
|
||
geprüft; alle übrigen verbundenen Fälle erwarten null automatische Commits.
|
||
Die alte Prüfung wurde nicht durch eine pauschale größere Toleranz ersetzt.
|
||
Output-, Cache- und Graph-Hashes bleiben unverändert.
|
||
|
||
**Prüfung:** vier zusätzliche Scheduler-/Primitive-Tests; Gesamtsammlung
|
||
**53/53 normal (42,53 s)** und **53/53 unretained (41,97 s)**. Release-Test-Clippy,
|
||
produktiver Release-Buildcheck, Format-/Diff-Prüfung und Original-Kernel-Abgleich
|
||
bestehen. Beide Referenz-Checkouts sauber auf den festgehaltenen Commits.
|
||
Beleg: `local-eval-results/20260907-mtplx-port/scheduler-check.log`.
|
||
|
||
**Weiter offen:** allgemeine Device-/TLS-Stream-Verwaltung, vollständiger
|
||
Evaluator mit streamübergreifendem Tape, CPU-Primitive-Encoding, vollständiger
|
||
Qwen-Modellgraph, allgemeiner Null-Storage-Vertrag und Produktionsanbindung samt
|
||
Instrumentation. Die CPU-Worker sind bisher modellfrei geprüft, nicht im
|
||
Produktionsmodell angebunden. Der kanonische Port bleibt `cfg(test)`;
|
||
Produkt-Qwen, UI/Harness-Verhalten und Gesamt-Performance sind nicht abgenommen.
|
||
Der vollständige Auftrag und die anschließende Drei-Modell-Matrix bleiben offen.
|
||
|
||
### CPU-Dispatch und gemeinsame Primitive-Ownership (2026-09-07)
|
||
|
||
Der CPU-CommandEncoder-Teil aus `backend/cpu/encoder.h` ist im bestehenden
|
||
Rust-Scheduler ergänzt: jeder zehnte Dispatch zählt eine laufende Aufgabe;
|
||
eine separate nachfolgende FIFO-Aufgabe meldet den Abschluss auch bei einem
|
||
Fehler im eigentlichen Dispatch. Ein abgewiesenes Enqueue lässt keinen neuen
|
||
Task-Zähler zurück. Die Cleanup-Aufgabe aus `backend/cpu/eval.cpp` zählt dabei
|
||
ebenfalls als Dispatch und hält Input-/Sibling-Data sowie Backend-Temporaries
|
||
bis hinter die zuvor eingereichte Arbeit.
|
||
|
||
CPU- und GPU-Evaluator verwenden dafür jetzt dieselbe Data-Auswahlfunktion:
|
||
Deduplication nach Data-Identität, primärer Output einschließlich gespendeter
|
||
Input-Data ausgeschlossen. CPU-Temporaries behalten ihre vollständigen nativen
|
||
Deskriptoren; der private Send-Wrapper erlaubt ausschließlich deren Freigabe
|
||
auf dem Worker, keinen Buffer-Zugriff. `Buffer` selbst bleibt nicht Send/Sync.
|
||
Es gibt keine neue Abhängigkeit, keinen Metal-Kernel- oder Produktionswechsel.
|
||
|
||
Gezielte Prüfungen: **5/5 Scheduler-Tests**, GPU-Evaluator-Ownership **1/1**,
|
||
verbundener Indexer mit allen 200 Fällen in beiden Encodern **1/1 normal**
|
||
(2,54 s) und **1/1 unretained** (2,50 s), jeweils unveränderte Ausgabe-/State-
|
||
Hashes. Release-Test-Clippy, Produkt-Buildcheck, Originalquellen-Abgleich und
|
||
Format-/Diff-Prüfung bestehen. Die vollständige 53er-Sammlung des vorherigen
|
||
Schrittes wurde hierfür nicht als neue Gesamtabnahme ausgegeben.
|
||
Beleg: `local-eval-results/20260907-mtplx-port/cpu-scheduler-check.log`.
|
||
|
||
**Weiter offen:** Device-/TLS-Stream-Registry und allgemeiner Evaluator samt
|
||
Modellgraph; CPU-Dispatch-/Hold-Regeln sind vorhanden, CPU-Modelloperationen
|
||
und deren Routing aber noch nicht verbunden. Produktionsanbindung und gesamte
|
||
Modell-/Performance-Abnahme bleiben unverändert offen. Der Stream-Abgleich
|
||
ist keine Behauptung, dass bereits eine vollständige Registry implementiert sei.
|
||
|
||
### CPU-/GPU-Stream-Verwaltung und Indexer-Anbindung (2026-09-07)
|
||
|
||
Ein Runtime-eigener Stream-Besitzer verbindet jetzt die vorhandenen CPU- und
|
||
GPU-Encoder für den installierten Ein-CPU-/Ein-Metal-Backend-Vertrag. Die Regeln
|
||
aus `stream.h/cpp` sind abgebildet: getrennte Defaults pro Thread/Device,
|
||
threadlokale Stream-Templates mit verzögerter Auflösung, normale threadgebundene
|
||
Streams und sequentiell threadübergreifend verwendbare globale Streams.
|
||
CPU-IDs bleiben wegen des gemeinsamen Schedulers über Context-Wechsel eindeutig.
|
||
|
||
Die Registry hält ihren Lock weder beim Encoding noch bei Dispatch oder Wait.
|
||
Ein ausgewählter GPU-Encoder benutzt weiterhin den vorhandenen Rc/RefCell-/TLS-
|
||
Operatorpfad und denselben Allocator; pro Stream-Auswahl wird kein neuer Encoder
|
||
oder neuer GPU-Queue-Besitzer erzeugt. Für die sichere Rückgabe aus einer Auswahl
|
||
werden genau ein starker und null schwache Rc-Besitzer verlangt. Gleichzeitige
|
||
mutable Nutzung wird abgewiesen, Fehler und Unwinding geben den Encoder zurück.
|
||
Ein TLS-Cleanup gibt lokale Encoder auch beim Thread-Ende ohne explizites Clear
|
||
frei. Explizites Clear erhält wie die Referenz die dann gegebenenfalls veralteten
|
||
Default-/Template-Handles und Stream-Metadaten; globale GPU-Encoder werden dabei
|
||
nur vom Scheduler-Main-Thread entfernt, globale CPU-Encoder nicht.
|
||
|
||
Wait/Signal, Finalize und Synchronize verwenden die existierenden CPU-FIFOs und
|
||
Metal-Events. Die streamübergreifende Lastbegrenzung finalisiert alle offenen
|
||
GPU-Streams in der ursprünglichen Device-/Index-Reihenfolge, bevor sie auf
|
||
Fortschritt wartet. Der gezielte Test verbindet zwei GPU-Queues per Event und
|
||
hält elf gezählte CPU-Aufgaben dahinter zurück. Erst das Einreichen beider
|
||
GPU-Queues löst die Kette. Eine fünfsekündige Sicherung würde einen kaputten
|
||
Finalize-All-Pfad fehlschlagen lassen statt den Test endlos hängen zu lassen.
|
||
|
||
Die vorhandene laufende **200-Fall-Indexer-Folge** nutzt nun im unabhängigen
|
||
Pfad einen registrierten Default-GPU-Stream statt eines alleinstehenden Scope;
|
||
Legacy-Gegenpfad und sämtliche Ausgabe-/State-/Commit-Erwartungen bleiben erhalten.
|
||
Zwei neue Stream-Tests prüfen außerdem Defaults, Thread-Zuordnung, Template-
|
||
Auflösung, Cleanup, Fehler-Rückgabe, Thread-Wechsel und echte Kernel-Kopien.
|
||
|
||
**Prüfung:** vollständige modellfreie Sammlung **57/57 normal (41,39 s)** und
|
||
**57/57 unretained (41,56 s)**. Release-Test-Clippy, Produkt-Buildcheck,
|
||
Format-/Diff-Prüfung und Original-Kernel-Abgleich bestehen; beide Referenzen
|
||
sauber auf den festgehaltenen Commits. Beleg:
|
||
`local-eval-results/20260907-mtplx-port/stream-check.log`.
|
||
|
||
**Weiter offen:** vollständiger allgemeiner Array-/Evaluator-Graph mit
|
||
streamübergreifenden Abhängigkeiten, CPU-Modelloperationen, Compile-Cache-Clear-
|
||
Anbindung, Null-Storage-Vertrag und kompletter Modell-/Produktionspfad samt
|
||
Instrumentation. Die Registry ist bisher im kanonischen Test-Port angebunden,
|
||
nicht in der UI-Inferenz. Dieser Schritt belegt weder den kalten UI-Ping noch
|
||
Modell-/Performance-Parität; die anschließende Drei-Modell-Matrix bleibt offen.
|
||
|
||
### Evaluator-Events und beide Inter-Stream-Fence-Pfade (2026-09-07)
|
||
|
||
Der Port enthält jetzt die Event-/Fence-Verträge aus `event.h`,
|
||
`backend/metal/event.cpp` und `backend/metal/fence.cpp`. Graph-Event-Kopien teilen
|
||
native Event-/Fehlerzustände, behalten aber ihren eigenen Wert-Snapshot und
|
||
Ursprungsstream. Host-Waits prüfen den gemeinsamen Fehler vor und nach dem Wait.
|
||
Diese Events sind von den internen MTLFences des Command Encoders getrennt.
|
||
|
||
Inter-Stream-Fences unterstützen beide Referenzzweige. Standardmäßig bleibt
|
||
SharedEvent-Synchronisation aktiv. Der optionale Fast-Pfad verlangt unverändert
|
||
`MLX_METAL_FAST_SYNCH` und Metal3/macOS15-Unterstützung. Er verwendet die bereits
|
||
in der gepinnten Metallib vorhandenen Originalfunktionen `input_coherent`,
|
||
`fence_update` und `fence_wait`, keine nachgebauten Kernel. GPU-Waits registrieren
|
||
die konsumierten Arrays als Outputs; GPU-Updates erhalten die ursprüngliche
|
||
Cross-Device-Coherence-Stufe und explizite Barrier. CPU-Operationen verwenden
|
||
den separaten atomaren Timestamp mit SeqCst-Zugriffen, ohne neue Sleeps/Yields.
|
||
Fence-Kopien teilen den Update-Zähler, während eingereihte Operationen ihren
|
||
jeweiligen Zählerwert erfassen. CPU-Aufgaben und Command-Completion-Holds halten
|
||
den privaten Timestamp-Speicher bis zum tatsächlichen Abschluss.
|
||
|
||
Die Metal-Bridge akzeptiert nun wie die Referenz leere Dispatch-Grids. Ein
|
||
gezielter Test prüft den leeren Coherence-Dispatch sowie eine BF16-Spanne, die
|
||
auf zwei uint32-Wörter aufgerundet wird. Das prüft einen realen Speicher mit
|
||
`data_size=0`, nicht den weiterhin offenen allgemeinen Null-Storage-Vertrag.
|
||
Die betroffene Rust-FFI wird derzeit ausschließlich vom `cfg(test)`-Port benutzt.
|
||
|
||
Drei neue Prüfungen decken Event-Snapshots/Fehler, kleine leere/teilwortige
|
||
Coherence-Grids und eine **CPU → GPU → GPU → CPU**-Kette in beiden Fence-Modi
|
||
mit exakten Daten und Freigabe nach Completion ab. Eine ausschließlich im Test
|
||
vorhandene fünfsekündige Sicherung löst Wartebedingungen bei einem Fehler auf;
|
||
sie griff nicht ein. Neue modellfreie Gesamtsammlung:
|
||
**60/60 normal (41,38 s)** und **60/60 unretained (41,47 s)**. Release-Test-Clippy,
|
||
Produkt-Buildcheck, Format-/Diff-Prüfung, Originalquellen- und Metallib-Hash-
|
||
Prüfung bestehen. Beide Referenzen sind sauber auf den gepinnten Commits.
|
||
Beleg: `local-eval-results/20260907-mtplx-port/graph-sync-check.log`.
|
||
|
||
**Weiter offen:** vollständiger Array-/Evaluator-Graph, der diese Abhängigkeiten
|
||
aus den Modelloperationen erzeugt; CPU-Modelloperationen, Compile-Cache-Clear,
|
||
Null-Storage und vollständige Qwen-Produktionsanbindung samt Instrumentation.
|
||
Der Fast-Modus wird nicht als Optimierung eingeschaltet. UI-Verhalten und
|
||
Gesamt-Performance wurden nicht neu gemessen; die vollständige Drei-Modell-
|
||
Abnahme bleibt offen.
|
||
|
||
### Gemeinsame Graph-Planung und Stream-Abhängigkeiten (2026-09-07)
|
||
|
||
`qwen_mtplx/eval.rs` übernimmt die Traversierung aus dem gepinnten
|
||
`transforms.cpp::eval_impl`: Auswahl des Synchronizer-Streams, DFS-Gradzählung
|
||
für alle Geschwister-Ausgaben, BFS mit Breitenlimit und DFS-Fortsetzung sowie
|
||
umgekehrte Ausführungsreihenfolge. Tape-Einträge identifizieren die tatsächlich
|
||
gewählte Ausgabe, nicht bloß deren Producer; diese Wahl ist für Data-Holds und
|
||
Donation relevant. `MLX_BFS_MAX_WIDTH` wird wie in `utils.h` einmalig mit
|
||
`get_var`/`atoi`-Semantik gelesen (Default 20), nicht mehr lokal fest verdrahtet.
|
||
|
||
Die Traversierung berücksichtigt Unscheduled/Evaluated/Available und das vom
|
||
Aufrufer gelieferte effektive Tracer-Flag. Bereits ausgewertete, nicht mehr
|
||
getracete Primitive werden einschließlich ihrer Geschwister abgelöst. Async-
|
||
Tracer und fehlende Primitive behalten die Referenzfehler. Stream-Abhängigkeiten
|
||
werden pro Ausgabe ermittelt; der Cross-Device-Bedarf wird über alle Konsumenten
|
||
vereinigt. Das ist noch keine allgemeine Array-Speicher- oder Transform-Runtime.
|
||
|
||
Der bisherige separate QSA-Scheduler ist entfernt. Der bestehende kompilierte
|
||
Indexer erzeugt sein wiederverwendetes Tape jetzt über diesen gemeinsamen
|
||
Planer. Sein einzelner logischer Stream wird beim Replay weiterhin auf dem
|
||
Encoder des Aufrufers ausgeführt; die Planung erzeugt keine zusätzliche Queue.
|
||
Alle bestehenden Ergebnis-, State-, Lifetime- und Commit-Prüfungen bleiben
|
||
unverändert. Keine Metal-Kernel, Flush- oder Prefill-Sonderregeln geändert.
|
||
|
||
Drei neue modellfreie Strukturprüfungen decken Breiten-/Sibling-Reihenfolge,
|
||
Stream-/Device-Abhängigkeiten sowie Status-/Detach-/Tracer-Fehler ab. Ihre
|
||
Erwartungen wurden aus der gepinnten Traversierung abgeleitet, nicht als neue
|
||
Live-Runtime-Trace ausgegeben. Gesamtsammlung **63/63 normal (40,70 s)** und
|
||
**63/63 unretained (40,90 s)**; Release-Test-Clippy, Produkt-Buildcheck,
|
||
Format-/Diff-Prüfung und Originalquellen-/Metallib-Hash-Prüfung bestanden.
|
||
Beide Referenz-Checkouts sind unverändert auf den festgehaltenen Commits.
|
||
Beleg: `local-eval-results/20260907-mtplx-port/graph-tape-check.log`.
|
||
|
||
**Weiter offen:** allgemeine Array-Daten-/Primitive-Ausführung mit dem gesamten
|
||
Eval-Epilog und Fehler-Cleanup, Verknüpfung der hier ermittelten Abhängigkeiten
|
||
mit Graph-Events/Fences, CPU-Modelloperationen, Compile-Cache-Clear, Null-Storage
|
||
und vollständiger Qwen-Produktionspfad samt Instrumentation. Der kanonische Port
|
||
bleibt `cfg(test)`; der UI-Modellpfad ist damit nicht umgestellt. Keine neuen
|
||
Modell-/Performance-Läufe, kein Paritäts-Pass und keine Rücknahme eines
|
||
Referenzbestandteils. Die vollständige Drei-Modell-Abnahme bleibt offen.
|
||
|
||
### Gemeinsamer Eval-/Async-Eval-Ablauf mit Abschluss und Fehler-Cleanup (2026-09-07)
|
||
|
||
Der gemeinsame Planer ist jetzt mit dem Ausführungs-Kontrollfluss aus
|
||
`transforms.cpp::eval_impl`, `eval` und `async_eval` verbunden. Der Evaluator
|
||
verwendet die vorhandene Stream-Registry, CPU-FIFOs, Encoder, Graph-Events und
|
||
beide Graph-Fence-Backends. GPU-Primitive laufen auf dem aufrufenden Thread im
|
||
Scope ihres Streams, nicht in einem neu eingeführten Worker-Pool.
|
||
|
||
Innerhalb einer Auswertung werden die geplanten Stream-Abhängigkeiten per Fence
|
||
abgewickelt; zwischen Async-Auswertungen über das gespeicherte Event. Bereits
|
||
signalisierten Events wird beim Ablösen noch ihr Fehler entnommen. Ein
|
||
fehlgeschlagenes Ablösen lässt Event und Status bestehen. Status, primäre Ausgabe
|
||
und Geschwister werden in Referenzreihenfolge aktualisiert. Der Abschluss
|
||
signalisiert die Eval-Events und finalisiert alle offenen GPU-Streams; der
|
||
synchrone Aufruf wartet auf den Synchronizer, der asynchrone nicht. Leere oder
|
||
bereits geplante Async-Ausgaben erzeugen keine neue Auswertung/Submission.
|
||
|
||
Bei einem Primitivfehler werden die beteiligten Events signalisiert und alle
|
||
betroffenen Streams synchronisiert. Cleanup-Fehler ersetzen nicht die Ursache.
|
||
Dasselbe Cleanup läuft beim Rust-Unwinding; danach wird der ursprüngliche Panic
|
||
weitergereicht. Der lokale Synchronizer wird in allen Rückgabewegen entfernt.
|
||
Frühere erfolgreiche Knoten bleiben ausgewertet, so dass ein Retry nur die
|
||
fehlgeschlagenen Knoten erneut ausführt. Gemeinsame Data-Hold-Helfer werden für
|
||
den bestehenden QSA-Pfad und den neuen Kontrollfluss wiederverwendet; CPU-Cleanup
|
||
behält seine Zehner-Taskzählung. Der Synchronizer benötigt keinen Datenpuffer.
|
||
|
||
Drei neue modellfreie Prüfungen verbinden echte kleine CPU-/GPU-Operationen:
|
||
CPU → GPU mit Geschwister-Ausgaben → zweite GPU-Queue → CPU; eine absichtlich
|
||
noch laufende Async-Ausgabe als Eingabe der nächsten Auswertung; Fehler und
|
||
Panic mit vollständigem Drain/Retry; Tracer-Donation-Schutz und behaltene
|
||
Topologie. Die zehnsekündige Deadlock-Sicherung gilt ausschließlich für diese
|
||
winzigen Unit-Tests und beendet bei einem Hänger deren Prozess; sie griff nicht
|
||
ein und ersetzt nicht den Startup-/Progress-Watchdog der Modell-Harness.
|
||
Zusätzlich prüft der bestehende Event-Test einen Fehler trotz signalisiertem Event.
|
||
|
||
Gezielte neue Tests: **3/3 SharedEvent (0,14 s)** und separat
|
||
**3/3 Fast-Fence (0,12 s)**. Gesamtsammlung **66/66 normal (41,35 s)** und
|
||
**66/66 unretained (41,58 s)**. Release-Test-Clippy, Produkt-Buildcheck,
|
||
Format-/Diff-Prüfung und Originalquellen-/Metallib-Hash-Prüfung bestanden.
|
||
Keine Shader-/Bridge-Änderung; beide Referenzen sauber auf ihren Pins.
|
||
Beleg: `local-eval-results/20260907-mtplx-port/eval-execution-check.log`.
|
||
|
||
**Abgrenzung:** Das ist der gemeinsame Ausführungs-Kontrollfluss, noch nicht der
|
||
vollständige Array-/Modellport. Primitive werden als konkrete Rust-Operationen
|
||
eingespeist; materialisierte Buffer mit Elementzahl/Elementgröße bleiben beim
|
||
Aufrufer. Allgemeine Descriptor-/Graph-Ownership, Shapes/Strides, Freigabe bei
|
||
letzter Graph-Referenz und Null-Storage müssen noch mit diesem Ablauf verbunden
|
||
werden. Der derzeitige Tracer-Schutz hält Input-Data vorübergehend und verhindert
|
||
Donation; die vollständige Descriptor-Referenzsemantik ist damit nicht belegt.
|
||
CPU-Modelloperationen, Compile-Cache-Clear und vollständiger Qwen-Produktionspfad
|
||
samt Instrumentation bleiben offen. QSA nutzt weiter seinen kompilierten
|
||
Replay innerhalb des Caller-Batches, nicht einen zusätzlichen Eval-Abschluss
|
||
pro Indexer-Aufruf. Der gesamte kanonische Port bleibt `cfg(test)`.
|
||
Keine UI-/Modell-/Performance-Abnahme und keine Schließung des Drei-Modell-Ziels.
|
||
|
||
### Leere materialisierte Daten und Null-Bindings (2026-09-07)
|
||
|
||
Der kanonische Buffer-Pfad kann nun leere Data-Objekte ohne Metal-Allokation
|
||
darstellen. `MetalAllocator::malloc(0)` der gepinnten Runtime liefert null;
|
||
`array::set_data` erzeugt trotzdem eine eigene Data-Identität. Entsprechend
|
||
erzeugt `Buffer::bytes(0)` im Test-Port einen leeren nativen Descriptor mit
|
||
`buffer=nil`, nicht einen Dummy-Puffer. Allokator-, Cache-, Peak- und Ressourcen-
|
||
Zähler bleiben unverändert. `Allocator::allocate(0)` liefert weiterhin `None`.
|
||
|
||
Der vorhandene Descriptor-/Data-/Allocation-Lebenszyklus wird wiederverwendet:
|
||
unabhängige leere Buffer haben verschiedene Data-Identitäten, Views teilen Data
|
||
und bekommen ihre eigene Descriptor-ID. Die native View-/Free-Verwaltung bleibt
|
||
zuständig; es gibt keine zweite Speicherverwaltung. Leere Reads/Writes sind
|
||
gültig, nichtleere oder außerhalb liegende Zugriffe bleiben Fehler. Eine leere
|
||
View kann außerdem einen vorhandenen nichtleeren Speicher behalten und am Ende
|
||
dieser Allokation liegen; sie wird nicht stillschweigend durch Null-Data ersetzt.
|
||
|
||
Die kanonische Metal-Bindung akzeptiert jetzt die von `device.cpp` verwendeten
|
||
Null-Bindings und leere Views. Null-Ressourcen bleiben wie in der Referenz Teil
|
||
der RAW-/WAR-Abhängigkeitsmengen; ihr `data_size` ist null. Die Objective-C-
|
||
Fallback-Hold-Menge übernimmt nur tatsächliche Metal-Buffer, da `NSSet` kein nil
|
||
aufnehmen darf. `tensor_contents` gibt für Null-Storage direkt null zurück,
|
||
ohne Pointer-Arithmetik darauf auszuführen. Die unveränderten Originalkernel
|
||
`input_coherent`, `fence_update` und `fence_wait` laufen in den entsprechenden
|
||
leeren Grids/Fence-Pfaden; kein Ersatzkernel und kein zusätzlicher Flush.
|
||
|
||
Zwei neue Prüfungen decken Identitäten, Freigabe, Grenzen, unveränderte
|
||
Allokatorzähler, Null-Abhängigkeiten, leere Tail-Views sowie beide nativen
|
||
Ownership-Pfade ab. Bestehende Fence-/Evaluator-Prüfungen enthalten nun echten
|
||
Null-Storage, einschließlich GPU → CPU. Gezielte Prüfungen je **1/1 (0,06 s)**;
|
||
erweiterter Fast-Fence-Evaluator **3/3 (0,11 s)**. Gesamtsammlung
|
||
**68/68 normal (41,23 s)** und **68/68 unretained (41,44 s)**. Release-Test-Clippy,
|
||
Produkt-Buildcheck, Format-/Diff-Prüfung und Originalquellen-/Metallib-Hash-
|
||
Prüfung bestanden; Referenz-Checkouts unverändert auf den Pins.
|
||
Beleg: `local-eval-results/20260907-mtplx-port/empty-storage-check.log`.
|
||
|
||
**Abgrenzung:** Damit ist der leere Buffer-/Binding-Vertrag verbunden, nicht
|
||
automatisch jeder Zero-Shape-Zweig sämtlicher Array-Operationen. Allgemeine
|
||
Array-Descriptor-/Graph-Ownership, Shapes/Strides, Freigabe bei letzter
|
||
Graph-Referenz, CPU-Modelloperationen und der vollständige Modell-/Produktions-
|
||
pfad bleiben offen. Die neue Buffer-Erzeugung ist an den kanonischen `cfg(test)`-
|
||
Pfad gebunden; die produktive Inferenz ist noch nicht umgestellt. Keine neuen
|
||
Modelldownloads oder Modell-/Performance-Läufe; das Drei-Modell-/2%-Ziel bleibt offen.
|
||
|
||
### Gemeinsame Array-Ownership im Lazy-Evaluator (2026-09-07)
|
||
|
||
Die externe `Vec<Option<Value>>` des allgemeinen Evaluators ist entfernt.
|
||
`eval`/`async_eval` arbeiten jetzt unmittelbar auf geteilten Array-Deskriptoren;
|
||
Primitive materialisieren ihre vorhandenen Ausgabedeskriptoren. Status, Events,
|
||
Eingaben, Geschwister, Ausgabeposition und Data gehören diesem Owner. Der
|
||
kompilierte QSA-Planner bleibt derselbe; seine vorhandenen materialisierten
|
||
Cache-Arrays verwenden ebenfalls den gemeinsamen Storage-/Descriptor-Owner.
|
||
|
||
Die Ownership-Regeln stammen aus `array.cpp`/`array.h` der gepinnten Runtime:
|
||
Descriptor-Kopien teilen Identität, separate Data-Views nicht; Donation verlangt
|
||
exklusive Descriptor- und Data-Ownership. Geschwister halten sich gegenseitig
|
||
und ihre jeweiligen Eingaben. Beim letzten äußeren Verweis werden die Zyklen
|
||
aufgelöst und lange Eingabeketten iterativ freigegeben. `detach` entfernt bei
|
||
allen Geschwistern Primitive, Eingaben, Geschwister und Ausgabeposition, ohne
|
||
Status oder Events zu löschen. Data-/Allocation-/GPU-Completion-Holds bleiben
|
||
in der bestehenden Speicher-/Encoder-Verwaltung; keine zweite Allokatorlogik.
|
||
|
||
Für die Planung entsteht nur ein schwacher Topologie-Index, keine zusätzliche
|
||
starke Referenz auf jedes Zwischenergebnis. Der Ausführungstape hält die von
|
||
MTPLX ausgewählten Ausgaben; nach Detach und letztem Verbraucher verschwinden
|
||
die Eingabedeskriptoren. Planungs-Detach wirkt unmittelbar, auch vor einem
|
||
späteren Planungsfehler. Bei Ausführungsfehlern bleibt der Rest-Tape bis nach
|
||
dem Event-/Stream-Cleanup erhalten. Tracer halten während des Primitivaufrufs
|
||
jetzt zusätzliche **Descriptor-Verweise**, nicht ersatzweise zusätzliche Data.
|
||
|
||
Zwei neue reine Ownership-Tests prüfen die letzte äußere Geschwisterreferenz,
|
||
30.000 Knoten mit behaltenem Zwischenknoten, 10.000 doppelte Geschwisterstufen
|
||
und vollständigen Detach. Die bestehenden drei verbundenen Evaluatorprüfungen
|
||
sind auf Array-Ownership umgestellt; eine vierte prüft Donation ohne künstliche
|
||
Arena-Referenzen, Freigabe nach letztem Verbraucher und unabhängig behaltene
|
||
Geschwister-Ausgaben. Der QSA-Donation-Test prüft zusätzlich einen direkten
|
||
Descriptor-Alias. Ergebnis-, Cache-, Lifetime- und Commit-Assertions des
|
||
vorhandenen Kernel-/Indexer-Bestands bleiben erhalten.
|
||
|
||
Prüfstand: **71/71 normal (42,16 s)** und **71/71 unretained (42,15 s)**;
|
||
abschließender Fast-Fence-Evaluator **4/4 (0,14 s)**. Release-Test-Clippy,
|
||
Produkt-Buildcheck, Format-/Diff-Prüfung und Originalquellen-/Metallib-Hash-Prüfung
|
||
bestanden. Beide Referenz-Checkouts sauber auf ihren Pins; keine Shader- oder
|
||
native Bridge-Änderung in diesem Schritt. Diese Zeiten sind Testlaufzeiten,
|
||
keine Modell-Performance. Beleg:
|
||
`local-eval-results/20260907-mtplx-port/array-ownership-eval-check.log`.
|
||
|
||
**Abgrenzung:** Das verbindet die Descriptor-/Graph-Lebensdauer mit dem
|
||
Ausführungskontrollfluss, schließt aber nicht den gesamten Array-/Modellport.
|
||
Allgemeine Shapes/Strides/Dtypes/Flags, konkrete Modellprimitive und ihre
|
||
vollständige Verbindung, CPU-Modelloperationen, Compile-Cache-Clear sowie die
|
||
Produktionsanbindung samt Instrumentation bleiben offen. Elementzahl und
|
||
Elementgröße werden ausdrücklich mit Materialisierungen übergeben; das ist
|
||
noch kein allgemeiner Shape-Inferenzpfad. Der kanonische Port bleibt `cfg(test)`.
|
||
Keine neuen Modellgewichte, keine Gesamtmodell-Messung, keine Paritätsabnahme.
|
||
|
||
### Typisierte Array-Geometrie vor der Auswertung (2026-09-07)
|
||
|
||
Der allgemeine Evaluator übernimmt keine freie Kombination von `data_size`
|
||
und `itemsize` mehr. Der bisherige `Value`-Transporttyp ist entfernt; Shapes
|
||
und echte Dtypes stehen bereits am unscheduled Ausgabedeskriptor. Primitive
|
||
materialisieren dessen Daten über `set_data`. Die gemeinsame Array-Geometrie
|
||
enthält Shape, kanonische Strides, Elementzahl, Dtype, Data-Elementzahl und
|
||
Contiguity-Flags. BF16 und FP16 bleiben verschiedene Typen trotz gleicher
|
||
Bytebreite; alle 14 Dtype-Werte der gepinnten Runtime sind abgebildet.
|
||
|
||
Die Regeln folgen `ArrayDesc::init`, `array::set_data`, `array::make_arrays`
|
||
und `dtype.h`: skalare Shapes haben ein Element, Shapes mit Null-Dimensionen
|
||
null; kanonische Strides werden von hinten aufgebaut. Negative Achsen werden
|
||
relativ zum Rank ausgewertet. Vor Materialisierung sind die drei Flags true;
|
||
danach wird Column-Contiguity aus der Form bestimmt. Ein neuer Primitivoutput
|
||
übernimmt nicht versehentlich die materialisierten Flags seines Inputs.
|
||
GPU-Primitive weisen Float64 an Eingaben oder Ausgaben zurück; die reine
|
||
CPU-Deskriptorkonstruktion erlaubt es. Leere Ausgabelisten erzeugen keine
|
||
Deskriptoren und führen diese GPU-Prüfung entsprechend nicht aus.
|
||
|
||
Materialisierungen mit zu kleinem Buffer sind Fehler und lassen vorhandene
|
||
Daten/Geometrie unverändert; Größenberechnungen sind geprüft. Die bestehende
|
||
Data-/Descriptor-/Completion-Verwaltung bleibt unverändert. QSA-Backing-Arrays
|
||
sind als BF16 typisiert; ihre vorhandene logische Cache-Geometrie und Head-
|
||
Strides bleiben beim Cache. Das ist noch keine Umstellung jedes Cache-Views
|
||
auf allgemeine Array-Shape-/Offset-Operationen. Im Evaluator leiten sich die
|
||
Fence-Elementzahl und Bytebreite jetzt aus dem typisierten Descriptor ab.
|
||
|
||
Eine neue reine Geometrieprüfung deckt die 14 Dtypes mit skalaren, leeren,
|
||
einheitsdimensionalen und mehrdimensionalen Formen sowie Grenzen/Flags ab.
|
||
Eine neue modellfreie Metal-Prüfung deckt echte Materialisierung, Fehler ohne
|
||
Datenverlust, Aliase und leeren Speicher ab. Der bestehende Evaluator- und
|
||
QSA-Testbestand ist auf den typisierten Vertrag umgestellt; keine bisherigen
|
||
Ergebnis-/Lebensdauer-/Commit-Prüfungen entfernt.
|
||
|
||
Prüfstand: **73/73 normal (42,01 s)** und **73/73 unretained (41,66 s)**;
|
||
Fast-Fence-Evaluator **4/4 (0,14 s)**. Gezielte Array-Prüfungen einschließlich
|
||
kleiner Metal-Allokationen **4/4 (0,07 s)**. Release-Test-Clippy, Produkt-Buildcheck,
|
||
Format-/Diff- und Originalquellen-/Metallib-Prüfung bestanden. Referenzen sauber
|
||
auf den bisherigen Pins; keine Shader-/Bridge-Änderung. Beleg:
|
||
`local-eval-results/20260907-mtplx-port/typed-array-geometry-check.log`.
|
||
|
||
**Abgrenzung:** Allgemeine strided Views mit Byte-Offsets, negative Strides,
|
||
Broadcast/Transpose/Reshape-Operationen, Dtype-Promotion/Conversions und alle
|
||
Modellprimitive sind damit nicht als vollständig portiert abgenommen. Auch
|
||
CPU-Modelloperationen, Compile-Cache-Clear, vollständiger Qwen-Modell-/Produktions-
|
||
pfad und Instrumentation bleiben offen. Der Port ist weiterhin `cfg(test)`;
|
||
keine Modell- oder 2%-Performance-Abnahme und keine neuen Modellgewichte.
|
||
|
||
### Geteilte Views und Byte-Offsets bis zur Metal-Bindung (2026-09-07)
|
||
|
||
Array-Deskriptoren tragen jetzt ihren eigenen Byte-Offset über demselben
|
||
geteilten Backing. `set_strided_data` übernimmt Strides/Flags/Data-Größe und
|
||
einen Byte-Offset; `copy_shared_buffer` addiert wie `array.cpp` einen Offset in
|
||
**Elementen des Ziel-Dtypes** zum vorhandenen Offset. Beide verwenden die
|
||
bestehenden Descriptor-/Data-/Allocation-Owner, keine zusätzlichen GPU-Views
|
||
oder Allokationen. Ungültige Spannen/Offsets werden vor einer Mutation abgewiesen.
|
||
`set_data` setzt den Offset zurück, behält aber wie die Referenz die Strides.
|
||
|
||
Die gemeinsamen materialisierten Backend-Operationen Slice, Broadcast und
|
||
Transpose sind aus `backend/common/slicing.cpp`, `broadcasting.cpp` und
|
||
`common.cpp::Transpose::eval` angeschlossen. Sie erhalten bereits inferierte
|
||
Ausgabe-Shapes und normalisierte Achsen/Indizes. Negative Strides und Broadcast-
|
||
Strides von null bleiben erhalten; Flags/Data-Größe werden nach den jeweiligen
|
||
Referenzregeln berechnet. Leeres Slice/Broadcast erzeugt leere eigene Data statt
|
||
das Eingabebacking zu halten. Generelles Reshape und Dtype-View/Conversion sind
|
||
noch nicht durch diese drei Backend-Operationen abgedeckt.
|
||
|
||
Der kanonische Metal-Binding-Vertrag hat nun einen zusätzlichen Byte-Offset.
|
||
Rust reicht ihn an `setBuffer` weiter; die native Brücke prüft Basisgrenzen und
|
||
Additionsüberlauf vor der Submission. Inline-Bytes haben weiterhin Offset null.
|
||
Die Ressourcenabhängigkeiten bleiben pro Backing, nicht pro View. Auch der
|
||
Fast-Fence-Coherence-Aufruf des allgemeinen Evaluators bindet den Array-Offset;
|
||
bestehende Buffer-Aufrufer verwenden unverändert Offset null. Kein zusätzlicher
|
||
Flush, Wait, Puffer oder veränderter Originalkernel.
|
||
|
||
Die neue überwachte Prüfung verbindet Reverse-Slice → Transpose → Slice →
|
||
Broadcast → Original-Metal-Copy im gemeinsamen Evaluator. Das Ergebnis ist
|
||
bytegenau geprüft; bis zur tatsächlichen Copy bleiben Allokatorzähler unverändert.
|
||
Zusätzlich: positive Offset-View über GPU → CPU, leere/ungültige Views, Freigabe
|
||
der ursprünglichen Graphreferenz. Bestehende Array-Tests prüfen explizite
|
||
negative Strides, Ziel-Dtype-Offseteinheiten, Selbst-Sharing, Fehler ohne Mutation
|
||
und Offset-Reset. Native Grenztests prüfen, dass ein ungültiger Binding-Offset
|
||
den Ressourcen-Owner nicht übernimmt. Der vorhandene kleine Test-Watchdog ist
|
||
wiederverwendet, keine neue Modell-Gesamtlaufzeitgrenze.
|
||
|
||
Prüfstand: **74/74 normal (41,18 s)** und **74/74 unretained (41,35 s)**.
|
||
Die neue View-Kette besteht separat normal **1/1 (0,08 s)** und mit Fast-Fences
|
||
**1/1 (0,06 s)**; der bestehende Fast-Fence-Evaluator **4/4 (0,15 s)**.
|
||
Release-Test-Clippy, Produkt-Buildcheck, Format-/Diff-Prüfung und Originalquellen-
|
||
/Metallib-Hash-Prüfung bestanden; Referenz-Checkouts sauber auf den Pins. Beleg:
|
||
`local-eval-results/20260907-mtplx-port/array-views-offsets-check.log`.
|
||
|
||
**Abgrenzung:** Das ist eine verbundene Backend-/Ownership-/Binding-Erweiterung,
|
||
keine vollständige Array-Ops-API oder Qwen-Modellintegration. Allgemeines Reshape,
|
||
Dtype-View/Promotion/Conversions, weitere Modellprimitive, vollständige logische
|
||
QSA-Graphanbindung, CPU-Modelloperationen, Compile-Cache-Clear und produktive
|
||
Instrumentation bleiben offen. Der kanonische Port bleibt `cfg(test)`; keine
|
||
Gesamtmodell-/UI-/2%-Performance-Abnahme und keine neuen Modellgewichte.
|
||
|
||
### Reshape: gemeinsames Backing oder Original-General-Copy (2026-09-07)
|
||
|
||
`views::reshape` übernimmt `common.cpp::prepare_reshape` und
|
||
`metal/copy.cpp::reshape_gpu`: gleiche Elementzahl/Dtype, Single-Array-Collapse
|
||
mit INT32_MAX-Grenze, passende geteilte Strides einschließlich negativer und
|
||
Broadcast-Strides; unveränderte Data-Größe/Offsets und referenzgleiche Flags.
|
||
Leere und row-contiguous Inputs teilen das Backing ohne GPU-Allokation.
|
||
Der Copy-Fall kollabiert dagegen Input- und kanonische Output-Strides gemeinsam
|
||
in der **Input-Shape**, allokiert die Ausgabe und dispatcht die unveränderten
|
||
General-Copy-Kernel aus der übernommenen Metallib. Rust selektiert Rang,
|
||
Large-Index-Namen und Work-per-thread wie die Referenz; Inline-Slices werden
|
||
über den vorhandenen Binding-Helfer mit ihrer tatsächlichen Byte-Länge gebunden.
|
||
Kein zusätzlicher Flush oder Wait, keine neue Ownership-Schicht.
|
||
|
||
Der überwachte Test verbindet Transpose → Reshape im gemeinsamen Evaluator:
|
||
13 GPU-Dtypes × vier Shape-Fälle, mit positivem Backing-Offset, Singleton-Achsen,
|
||
g2/g3/gn2-Kopien und unabhängig indizierter bytegenauer Ausgabeprüfung.
|
||
Zusätzlich: Reverse-Strides beim geteilten Reshape, skalare und nichtuniforme
|
||
Broadcasts (Share versus Copy), leere Arrays und Größenfehler ohne Mutation.
|
||
Das sind kleine modellfreie Funktionstests; Large-Index-Kopien oberhalb
|
||
INT32_MAX werden hier nicht mit großen Allokationen ausgeführt.
|
||
|
||
Prüfstand: **75/75 normal (41,85 s)**, **75/75 unretained (41,63 s)**;
|
||
View-/Reshape-Ketten mit Fast-Fences **2/2 (0,09 s)**. Release-Test-Clippy,
|
||
Produkt-Buildcheck, Format-/Diff-Prüfung und Quellen-/Metallib-Hash-Prüfung
|
||
bestanden; beide Referenz-Checkouts sauber auf den Pins. Befehle/Ergebnisse:
|
||
`local-eval-results/20260907-mtplx-port/reshape-check.log`.
|
||
|
||
Der kanonische Port bleibt `cfg(test)`. Dtype-View/Promotion/Conversions,
|
||
weitere Modellprimitive, vollständige logische QSA-Graphanbindung, CPU-
|
||
Modelloperationen, Compile-Cache-Clear, produktive Instrumentation und der
|
||
vollständige Qwen-Modellpfad sind weiterhin offen. Der Reshape-Backend-Port
|
||
ist ausdrücklich keine Produktions-, UI- oder Gesamtmodell-Performance-Abnahme.
|
||
|
||
### AsType und Dtype-View am gemeinsamen Copy-/Evaluator-Pfad (2026-09-07)
|
||
|
||
Die tatsächlich verwendeten Qwen-Referenzaufrufe wechseln u.a. Router-Indizes,
|
||
QSA-Pooled-Scores und RoPE-Zwischenwerte (`models/qwen4_exp.py`: 345, 803–804,
|
||
1633–1658, 1945, 1965–1968). Der kanonische Rust-Backend-Port bildet jetzt
|
||
`gpu/primitives.cpp::AsType::eval_gpu` und `View::eval_gpu` ab, ohne dafür
|
||
Konvertierungsshader neu zu schreiben.
|
||
|
||
AsType selektiert Vector anhand des **contiguous**-Flags (nicht nur row-
|
||
contiguous), erhält dabei Strides/Flags/physische Data-Größe und übernimmt
|
||
donierbare gleich breite Speicher innerhalb der referenzierten 16-KiB-Grenze.
|
||
Bei gleichem Dtype entfällt dann der Dispatch; bei verschiedenem Dtype werden
|
||
Werte tatsächlich in place konvertiert. Andere Layouts gehen durch General
|
||
Copy. Vector-Work-per-thread richtet sich nach Zieldtype und 65536-Schwelle;
|
||
Large-Index-Namen und 2D-Grid-Faktorisierung folgen der gepinnten Referenz.
|
||
|
||
Dtype-View prüft skalare/letzte-Achsen-Bytegrößen. Gleiche Breite, geeignete
|
||
kleinere Breite oder row-contiguous Input teilen das Backing mit angepassten
|
||
Strides/Data-Größen. Andernfalls kopiert der originale General-Kernel zunächst
|
||
in einen dichten temporären Input-Dtype-Puffer, den die Ausgabe anschließend
|
||
teilt. Der General-Copy-Pfad wird auch von Reshape wiederverwendet. Seine
|
||
1024-Thread-Bedingung wird jetzt am tatsächlichen Pipeline-State geprüft;
|
||
Vector nutzt dessen Maximum. Die native Lookup-Routine ist aus dem vorhandenen
|
||
Dispatch extrahiert und zwischen Abfrage/Encoding geteilt. Kein zusätzlicher
|
||
GPU-Command, Flush, Wait oder geänderter Metal-Kernel.
|
||
|
||
Neue überwachte Evaluator-Prüfung: alle 169 GPU-Dtype-Konvertierungspaare mit
|
||
unabhängig kodierten 0/1-Werten; Vector-Schwellen 65535/65536/65537, Donation
|
||
mit/ohne Konvertierung, negative Strides, spaltenkontiguierliche und Broadcast-
|
||
Backings, Dtype-View-Sharing und -Copy, skalare/ungültige/leere Ausgaben.
|
||
Large-Index-Grid und originale Large-Pipelines sind ohne große GPU-Allokation
|
||
geprüft; keine Ausführung von Multi-GB-Copies daraus behauptet.
|
||
|
||
Prüfstand: **76/76 normal (41,86 s)**, **76/76 unretained (41,29 s)** und
|
||
**3/3 View-/Reshape-/Konvertierungsketten mit Fast-Fences (0,15 s)**.
|
||
Release-Test-Clippy, Produkt-Buildcheck, Format-/Diff-Prüfung und Quellen-/
|
||
Metallib-Hash-Prüfung bestanden; beide Referenz-Checkouts sauber auf den Pins.
|
||
Beleg: `local-eval-results/20260907-mtplx-port/dtype-copy-view-check.log`.
|
||
|
||
**Offen bleiben** die vollständige Array-Ops-API samt Promotion, weitere
|
||
Modellprimitive/logische QSA-Anbindung, CPU-Modelloperationen, Compile-Cache-
|
||
Clear und die Produktionsintegration mit Instrumentation. Weiterhin `cfg(test)`;
|
||
keine Gesamtmodell-/UI-/2%-Performance-Abnahme.
|
||
|
||
### Graph-eigene Array-Operationen statt externer Test-Zuordnung (2026-09-07)
|
||
|
||
Array-Deskriptoren können jetzt ihre konkrete Operation besitzen. Der neue
|
||
`ops::evaluate` verwendet unverändert den gemeinsamen Eval-/Async-Eval-Pfad,
|
||
liest den Payload aber aus dem Graphen, nicht aus einer externen ID-/Callback-
|
||
Tabelle. Detach gibt auch diesen Payload frei. Die bisherigen spezialisierten
|
||
Fixture-Callbacks bleiben verfügbar; der Produktionsmodellpfad ist noch nicht
|
||
umgeschaltet.
|
||
|
||
Lazy-Konstruktoren für Reshape, Transpose, Broadcast, AsType, Dtype-View,
|
||
ExpandDims und Squeeze übernehmen Shape-/Achsenprüfung, negative Achsen,
|
||
Reshape-Inferenz und die jeweiligen No-op-Regeln aus `ops.cpp`. ExpandDims
|
||
fügt Stride 1 ein, Squeeze entfernt nur die ausgewählten Strides; Flags,
|
||
Data-Größe und Offset bleiben geteilt wie in `common.cpp`. CPU-Ausführung
|
||
ist hier nur für diese gemeinsamen Views angeschlossen; CPU-Copy/Conversions
|
||
bleiben ausdrücklich offen und werden nicht still auf die GPU umgeleitet.
|
||
|
||
Der überwachte Test baut Qwens `pooled.astype(float32).swapaxes(1,2)[:,None]`
|
||
aus diesen Konstruktoren und verbindet weitere Reshape-/View-/Broadcast-
|
||
Verbraucher einschließlich GPU→CPU und Async→Sync. Vor Evaluation entstehen
|
||
keine GPU-Allokationen. Er prüft erwartete Shape/Strides, bytegenaue Werte,
|
||
No-op-Identitäten/Fehler und die Freigabe ursprünglicher Arrays und Operations-
|
||
Payloads. Das ist eine eigenständig ausführbare Layout-Graphfolge, noch keine
|
||
Anbindung des vollständigen QSA-Caches oder Qwen-Modells.
|
||
|
||
Prüfstand: **77/77 normal (41,19 s)**, **77/77 unretained (41,47 s)**;
|
||
neuer Graph mit Fast-Fences **1/1 (0,06 s)**. Release-Test-Clippy, Produkt-
|
||
Buildcheck, Format-/Diff- und Originalquellen-/Metallib-Prüfung bestanden.
|
||
Beleg: `local-eval-results/20260907-mtplx-port/owned-operations-check.log`.
|
||
|
||
### Slice-Normalisierung und Contiguous für Cache-Fenster (2026-09-07)
|
||
|
||
Der graph-eigene Slice-Konstruktor übernimmt die Normalisierung von Start/Stop,
|
||
Vorwärts-/Rückwärts-Schritten und Singleton-Strides aus `ops.cpp`. Die No-op-
|
||
Entscheidung verwendet das ursprüngliche Vorzeichen vor der Singleton-
|
||
Vereinfachung. Rangfehler und Schritt null werden vor Graphanlage abgewiesen.
|
||
Ausführung nutzt den vorhandenen geteilten Slice-Backend, ohne neuen Kernel.
|
||
|
||
`Contiguous` ist wie in `ops.cpp` immer ein eigener Knoten. Sein GPU-Backend
|
||
teilt row-contiguous oder ausdrücklich erlaubte column-contiguous Inputs nur
|
||
innerhalb der ursprünglichen 16-KiB-Backing-Grenze; sonst verwendet es den
|
||
gemeinsamen Original-General-Copy. Diese Entscheidung ist für Qwens
|
||
`cache[0] = contiguous(conv_input[:, -n_keep:, :])` relevant, damit ein kleines
|
||
Fenster nicht unbegrenzt ein großes Prefill-Backing hält.
|
||
|
||
Der überwachte Graph-Test prüft Slice-Werte/Identitäten/Strides, leere und
|
||
skalare Inputs, negative Grenzen/Schritte und Fehler. Dieselbe Zwei-Zeilen-
|
||
Cache-Ansicht wird einmal aus kleinem Backing geteilt und einmal aus großem
|
||
Backing kopiert; Column-Major erlauben/verbieten ist separat geprüft. Keine
|
||
Modellgewichte geladen; vollständige QSA-/Modellintegration und Performance-
|
||
Abnahme bleiben offen, der Port bleibt `cfg(test)`.
|
||
|
||
Prüfstand: **78/78 normale modellfreie Tests (41,85 s)**. Die beiden graph-
|
||
eigenen Operationsprüfungen bestehen zusätzlich **2/2 unretained (0,09 s)**
|
||
und **2/2 Fast-Fences (0,08 s)**; keine vollständige unretained-Wiederholung
|
||
in diesem Schritt. Release-Test-Clippy, Produkt-Buildcheck, Format-/Diff-
|
||
Prüfung und Quellen-/Metallib-Hashes bestanden. Beleg:
|
||
`local-eval-results/20260907-mtplx-port/slice-contiguous-check.log`.
|
||
|
||
### RMSNorm als rechnende Graphoperation (2026-09-07)
|
||
|
||
Der Array-Payload-Pfad unterstützt jetzt mehrere Eingaben; RMSNorm trägt Input
|
||
und Gewicht als normale Graphkanten. Der GPU-Konstruktor folgt `fast.cpp`
|
||
einschließlich der für RMSNorm gültigen Floating-Promotion, vorgeschalteter
|
||
AsType-Knoten und skalarem Eins-Gewicht im ungewichteten Fall. CPU-Fallback-
|
||
Arithmetik bleibt offen und wird ausdrücklich abgewiesen, nicht auf GPU
|
||
umgeleitet.
|
||
|
||
Der Backend übernimmt `metal/normalization.cpp` statt pauschal `contiguous`
|
||
aufzurufen: passende zusammenhängende letzte Dimension und zulässiger
|
||
vorletzter Stride; anschließend Donation oder gleichartiges Backing. Andere
|
||
Layouts werden einmal dicht kopiert, und dieses Backing wird zum Output.
|
||
Die Zeilenzahl folgt der physischen Data-Größe, nicht der virtuellen Shape.
|
||
Input-/Gewicht-/Output-Offsets und Gewicht-Stride gehen in den Originalkernel.
|
||
Der frühere BF16-Helper und der neue Graphbackend teilen denselben Dispatch;
|
||
kein neuer Normalisierungsshader, keine neue Flush-/Wait-Grenze.
|
||
|
||
Neue überwachte Prüfung: FP16/BF16/FP32, Breiten 1/128/4096/4097, vorhandene
|
||
Input-Aliase versus letzter Verbraucher, Broadcast-Backings, notwendige
|
||
Input-Copy, strided/versetzte Gewichte und Inputs, ungewichtete Norm,
|
||
BF16+FP16→FP32 sowie ungültige Shapes. Die vorhandenen BF16-Modul-/QSA-/GDN-
|
||
Fixtures prüfen zusätzlich den gemeinsam umgestellten Dispatch. Das bleibt
|
||
ein kanonischer `cfg(test)`-Port; vollständige Modellintegration und der
|
||
Gesamtmodell-Performance-Nachweis sind nicht damit erreicht.
|
||
|
||
Prüfstand: **79/79 normal (41,87 s)** und **79/79 unretained (41,49 s)**;
|
||
RMSNorm-Graph mit Fast-Fences **1/1 (0,08 s)**. Release-Test-Clippy,
|
||
Produkt-Buildcheck, Format-/Diff- und Originalquellen-/Metallib-Prüfung bestanden.
|
||
Beleg: `local-eval-results/20260907-mtplx-port/graph-rms-norm-check.log`.
|
||
|
||
### Quantisierte BF16-Projektionen als Graphoperation (2026-09-07)
|
||
|
||
Der normale transponierte Affine-Linear-Pfad der installierten Qwen-Gewichte
|
||
ist jetzt eine Operation mit vier Graphkanten (x, W, scales, biases). Output-
|
||
Allokation vor der Eingabevorbereitung und `ensure_row_contiguous_matrix`
|
||
folgen `metal/quantized.cpp`: nur die letzten beiden Strides entscheiden
|
||
über die notwendige General-Copy; kein Contiguous-Slack-Kriterium. Kopien
|
||
werden als Encoder-Temporaries bis zum GPU-Abschluss gehalten.
|
||
|
||
Graph und bestehende Modul-Fixtures benutzen denselben Affine-Dispatcher:
|
||
QMV/Quad/Wide, QMM/NAX/Split-K und die Split-Reduktion bleiben unverändert.
|
||
Die Eingaben erhalten ihre tatsächlichen Byte-Offsets und Array-Data-Größen
|
||
für Bindings und Submission-Zähler. Keine neuen Shader, Flushes oder Waits.
|
||
Der Graphzweig ist ausdrücklich BF16 mit zweidimensionalen 4/8-Bit-Gewichten,
|
||
Gruppengröße 32/64. Andere Dtypes und echte batched/expert-Matmul-Graphzweige
|
||
sind noch offen; sie werden nicht stillschweigend flachgerechnet.
|
||
|
||
Die neue überwachte Prüfung führt alle **78** bestehenden Referenz-Fixtures
|
||
jeweils dicht, mit führendem Storage-Offset und mit strided Eingaben aus.
|
||
Alle vier Eingaben werden variiert; x behält über ExpandDims eine zusätzliche
|
||
Batch-Dimension, ohne vorab per Reshape dicht kopiert zu werden. **234/234
|
||
Outputs sind exakt** gegenüber den gepinnten Referenz-Hashes. Kein Modell
|
||
geladen, kein Download, kein Gesamtmodell-Performance-Vergleich.
|
||
|
||
Prüfstand: **80/80 normal (42,51 s)** und **80/80 unretained (42,62 s)**;
|
||
der neue Graph-Test mit Fast-Fences **1/1 (0,99 s)**. Release-Test-Clippy,
|
||
Produkt-Buildcheck, Format-/Diff- und Originalquellen-/Metallib-Prüfung bestanden.
|
||
Produktintegration und vollständige Modelloperationen bleiben offen; dieser
|
||
Graph ist weiterhin `cfg(test)`. Prüfbeleg:
|
||
`local-eval-results/20260907-mtplx-port/graph-quantized-linear-check.log`.
|
||
|
||
### Elementweise Unary-Operationen im Graph (2026-09-07)
|
||
|
||
Negative, Square, Exp, Sigmoid, Tanh, Sqrt und Rsqrt sind jetzt eigene
|
||
Graph-Payloads. Konstruktoren folgen den jeweiligen `ops.cpp`-Typregeln:
|
||
Negative/Square erhalten den Typ, die übrigen verwenden `at_least_float`
|
||
mit vorgeschaltetem AsType; Negative/Bool und Sigmoid/Complex werden wie
|
||
in der Referenz abgewiesen. CPU-Arithmetik bleibt ausdrücklich unportiert.
|
||
|
||
Der gemeinsame Backend folgt `metal/unary.cpp`: physische Data-Größe bei
|
||
zusammenhängendem Backing, `v`/`vn`-Wechsel bei 65536 Elementen, `v2` für
|
||
große zusammenhängende Daten, sonst zusammengefasste Dimensionen und
|
||
`gn1`/`gn4large`. Kernel-Maximalgruppen und Original-Grid-Regeln werden
|
||
verwendet. Inputs und Outputs tragen ihre Byte-Offsets und Data-Größen.
|
||
Die Original-Metallib wird nicht verändert.
|
||
|
||
`set_unary_output_data` ist mit AsType geteilt: Donation nur bei eindeutiger
|
||
Ownership, gleicher Elementbreite und höchstens 16 KiB zusätzlichem Backing;
|
||
sonst physisches gleichartiges Backing bei Contiguous oder dichter Output
|
||
für allgemeine Strides. Der bisherige Single-Array-Collapse von Reshape
|
||
wird ebenfalls wiederverwendet, nicht mit dem Joint-Copy-Collapse vermischt.
|
||
|
||
Der überwachte Test prüft exakte dyadische Werte für FP16/BF16/FP32 bei
|
||
0/1/65535/65536/65537 Elementen, mit und ohne Alias, sowie transponierte,
|
||
strided, negative, Broadcast- und Offset-Views, übergroße Backings,
|
||
Integer-Square und Integer→Float-Sqrt. Eine anfänglich falsche Testannahme
|
||
zur Donation von Reverse-Views wurde anhand `check_contiguity` korrigiert:
|
||
negative Strides zählen dort nicht zur positiven physischen Contiguity;
|
||
der Backend erzeugte bereits korrekt einen neuen dichten Output.
|
||
Große >UINT32-Allokationen werden mit diesem Test nicht behauptet.
|
||
|
||
Prüfstand: **81/81 normal (43,88 s)** und **81/81 unretained (42,99 s)**;
|
||
Unary mit Fast-Fences **1/1 (0,41 s)**. Release-Test-Clippy, Produkt-Buildcheck,
|
||
Format-/Diff-Prüfung und unveränderte Originalquellen/Metallib bestätigt.
|
||
Produktgraph und vollständige Modellintegration bleiben offen. Prüfbeleg:
|
||
`local-eval-results/20260907-mtplx-port/graph-unary-check.log`.
|
||
|
||
### Binäre Graphoperationen und gemeinsame Typ-Promotion (2026-09-07)
|
||
|
||
Add/Subtract/Multiply/Divide/Maximum/Minimum/LogAddExp laufen jetzt als
|
||
binäre Graph-Payloads durch denselben Evaluator. Ihre Konstruktoren übernehmen
|
||
`ops.cpp`: Typ-Promotion, gegebenenfalls `at_least_float`, AsType beider
|
||
Eingaben und Broadcasting einschließlich der Null-Dimensionen.
|
||
|
||
Die vollständige Promotion der 14 Referenztypen ist gemeinsam in Dtype
|
||
implementiert und gegen alle **196** Einträge der gepinnten `dtype.cpp`-
|
||
Tabelle geprüft. RMSNorm und Unary benutzen die gemeinsamen Typregeln statt
|
||
eigener Teilabbildungen; ihre bestehenden Prüfungen bleiben erhalten.
|
||
|
||
Der Binary-Backend übernimmt `common/binary.h` und `metal/binary.cpp`:
|
||
Scalar/Scalar, Scalar/Vector, Vector/Scalar, gemeinsame Row-/Column-Vector-
|
||
Layouts und General. Scalar/Scalar allokiert ein neues physisches Element;
|
||
die übrigen Fälle erhalten referenzgleiche Donation-Priorität und Strides.
|
||
General kann einen passenden dichten Input übernehmen. Elementbreite,
|
||
Ownership und 16-KiB-Slack werden gemeinsam mit Unary/AsType geprüft.
|
||
|
||
General-Dispatch verwendet den Joint-Collapse von Input A, Input B und
|
||
Output; derselbe verallgemeinerte Helfer ersetzt den bisherigen Zwei-Layout-
|
||
Collapse für Kopien. `g1/g2/g3/gn2/gn4large` sowie `ss/sv/vs/vv` mit den
|
||
Vector-Arbeitsgrenzen werden aus den Originalregeln selektiert. Kernelquellen
|
||
und Metallib bleiben unverändert; keine neue Flush-/Wait-Grenze.
|
||
|
||
Überwachte GPU-Prüfung: BF16/FP32, alle sieben Operationen, leere Eingaben,
|
||
Scalar/Vector-Grenzen bei 1/65535/65536/65537, alle Donation-Prioritäten,
|
||
Column-/General-Layouts, zweiachsiges Broadcasting, rank-5 General-Dispatch,
|
||
nichtkonstante Reverse-/Offset- und rank-5-Indizierung, gemischte Typen und
|
||
Integer-Division mit Float-Promotion. Die erste Donation-Prüfung hielt ihre
|
||
ursprünglichen Eingaben durch Rust-Shadowing ungewollt weiter am Leben;
|
||
die Testeingaben werden nun vor der Auswertung ausdrücklich freigegeben.
|
||
Der Backend war in diesem Fall korrekt nicht-donierend. Keine Änderung der
|
||
Original-Ownership-Regeln zur Anpassung an eine falsche Testannahme.
|
||
|
||
Das bleibt `cfg(test)`-Grapharbeit; vollständige Modell-/Produktintegration
|
||
und der Gesamtperformance-Nachweis bleiben offen. Prüfstand: **83/83 normal
|
||
(44,06 s)**, **83/83 unretained (44,03 s)**, binärer Graph mit Fast-Fences
|
||
**1/1 (0,13 s)**. Release-Test-Clippy, Produkt-Buildcheck, Format-/Diff-Prüfung,
|
||
Originalquellen-/Metallib-Prüfung bestanden. Prüfbeleg:
|
||
`local-eval-results/20260907-mtplx-port/graph-binary-check.log`.
|
||
|
||
### Shared-Expert-MLP als zusammenhängender Graph (2026-09-07)
|
||
|
||
`_FusedGateUpMLP` ist jetzt aus normalen Graphknoten aufgebaut: quantisierte
|
||
fusionierte Gate/Up-Projektion → Split → der tatsächlich erfasste kompilierte
|
||
BF16-SiLU-Kernel → separater Multiply → quantisierte Down-Projektion. Kein
|
||
eager Mehrkernel-Callback und keine neue Shaderimplementierung.
|
||
|
||
Split ist ein gemeinsamer Mehrfach-Output-Knoten mit Geschwistern. Jedes
|
||
Geschwister trägt denselben Operation-Payload; der bestehende Evaluator kann
|
||
jedes davon als primären Output wählen. Der schnelle Split übernimmt exakt
|
||
die Flags-/Data-Größen-Regeln aus `common.cpp`, allgemeine Indizes gehen über
|
||
die Slice-Fallbackknoten aus `ops.cpp`. Das ist materiell für Submission:
|
||
bei `[2,6]` entlang der letzten Achse liefert Split pro Hälfte `data_size=6`,
|
||
nicht die überstrichene Spanne von 9 Elementen. Der neue Graph zählt das
|
||
referenzgleich; die älteren isolierten Buffer-Helper sind damit nicht pauschal
|
||
als graph-/scheduling-identisch erklärt.
|
||
|
||
Die SiLU-Graphoperation nutzt die unveränderten 19 erfassten JIT-Varianten.
|
||
Contiguity, Joint-Collapse, negative/large Indizes, dynamische Ränge und
|
||
Donation folgen `common/compiled.cpp` und `metal/compiled.cpp`. Insbesondere
|
||
hat compiled Donation keine 16-KiB-Slack-Grenze; diese wird nicht aus Unary
|
||
übertragen. Die Kernelwahl liest die Output-Data-Größe wie im Referenzcode
|
||
vor der Allokation, nicht ersatzweise die logische Shape. Dieser Port betrifft
|
||
den erfassten nichtskalaren BF16-SiLU-Pfad, nicht einen allgemeinen Compiler.
|
||
|
||
24 neue modellfreie Receipts wurden direkt durch die tatsächliche MTPLX-
|
||
Klasse erzeugt: 1/4/7/2048 Zeilen, installierte 2560→1280→640→2560-Projektionen
|
||
und kleine 128/64-Grenzfälle, 4-/8-Bit und Gruppen 32/64. Alle 24 finalen
|
||
Outputs sind exakt. Zusätzlich stimmen beide Outputs der zehn vorhandenen
|
||
SiLU/Gate-Up-Fixtures durch den echten Split-/Multiply-Graphen exakt.
|
||
Separate Layoutprüfungen decken Split-Geschwisterauswahl, wiederholte und
|
||
allgemeine Indizes, Strides/Offsets und compiled Donation ab.
|
||
Positive und negative nichtzusammenhängende Ränge 4/8 decken die festen und
|
||
dynamischen erfassten SiLU-Kernel ab. Die Donation eines Inputs mit negativer
|
||
Singleton-Stride übernimmt im strided compiled Zweig die Output-Strides;
|
||
diese beim abschließenden Source-Abgleich korrigierte Stelle hat einen eigenen
|
||
Regressionstest.
|
||
|
||
Der Referenzgenerator verwendet den bestehenden Pattern-/QuantizedLinear-
|
||
Aufbau gemeinsam mit den MoE-Fixtures; kein Download und kein Modellladen.
|
||
Referenzreceipts: `tests/fixtures/mtplx-shared-mlp.jsonl`. Produktanbindung,
|
||
übrige Modelloperationen und Gesamtmodell-Performance-Parität bleiben offen.
|
||
Prüfstand: gesamte Port-Suite **85/85 normal (43,50 s)** und **85/85 unretained
|
||
(43,79 s)**. Nach der abschließenden Singleton-Stride-Korrektur die beiden
|
||
betroffenen Tests erneut **2/2 normal (0,28 s)**, **2/2 unretained (0,31 s)**
|
||
und **2/2 Fast-Fences (0,27 s)**. Clippy, Produkt-Buildcheck, Python-Syntax,
|
||
Format-/Diff-Prüfung und Originalquellen-/Metallib-Prüfung bestanden.
|
||
Prüfbeleg: `local-eval-results/20260907-mtplx-port/graph-shared-mlp-check.log`.
|
||
|
||
### Qwen-Normalisierungsmodule als zusammenhängender Graph (2026-09-07)
|
||
|
||
`normalization.rs` bildet jetzt `GroupedRMSNorm` und `SigmoidRMSNormGated`
|
||
aus `qwen4_exp.py:350–386` als gewöhnliche Graphknoten ab. Gruppierte Norm:
|
||
Reshape → ungewichtete RMSNorm → Reshape → voller Gewichts-Multiply.
|
||
Die Gewichtung wird nicht in RMSNorm gezogen; die BF16-Rundungsstelle bleibt.
|
||
Gated Norm: gewichtete RMSNorm, Gate-Cast nach FP32 → Sigmoid,
|
||
Norm-Cast nach FP32 → Multiply mit Gate als erstem Operand → Rückkonvertierung
|
||
auf den Hidden-State-Typ. Auch ohne Gate erfolgt diese Rückkonvertierung.
|
||
Keine neuen Shader und kein eager Callback für das gesamte Modul.
|
||
|
||
Alle **25 bestehenden tatsächlichen MTPLX-Modulreceipts** stimmen exakt:
|
||
zehn Gruppierungs-/Kernelgrenzfälle und fünf Tokenzahlen (1/4/7/11/2048)
|
||
mit keinem, zusammenhängendem oder gestridetem Projektions-Gate. Projektions-
|
||
Gates entstehen durch echte Slice-/Reshape-Knoten, nicht vorab dichte Buffers.
|
||
Zusätzliche Prüfungen sichern gemischte Gewichtstypen, Rückkonvertierung
|
||
mit/ohne Gate und ungültige Gruppengrößen ab.
|
||
|
||
Prüfstand: gesamte Port-Suite **86/86 (44,38 s)**; beide Normalisierungs-
|
||
Graphprüfungen zusätzlich **2/2 unretained (0,26 s)** und **2/2 Fast-Fences
|
||
(0,26 s)**. Clippy, Produkt-Buildcheck und Originalquellen-/Metallib-Prüfung
|
||
bestanden. Beleg: `local-eval-results/20260907-mtplx-port/graph-norm-check.log`.
|
||
Der Graph bleibt `cfg(test)`; vollständige Modell-/Produktanbindung und
|
||
Gesamtmodell-Performance-Parität bleiben offen. Dies ersetzt keinen P16-Lauf.
|
||
|
||
### GDN-Decode als Zustandsgraph und Dispatch-Geometrie (2026-09-07)
|
||
|
||
`qwen_mtplx/gdn.rs` verbindet die Eingangsprojektionen, den tatsächlichen
|
||
dreifachen Custom-Kernel-Output und die Ausgangsprojektion als normale
|
||
Array-Knoten. Fusionierte Projektionen verwenden Split-Geschwister; getrennte
|
||
und gemischt quantisierte Projektionen bewahren qkv → z/Head-Reshape → b → a.
|
||
Conv- und FP32-Delta-Zustand werden als Graphwerte an den Folgeschritt gegeben.
|
||
Ein fehlender Conv-Zustand mit vorhandenem Delta-Zustand entsteht wie in der
|
||
Referenz als Broadcast-Nullarray, das erst am Custom-Kernel materialisiert wird.
|
||
|
||
Die Custom-Primitive folgt `metal/custom_kernel.cpp`: alle drei Outputs zuerst
|
||
allokieren, danach nicht-row-contiguous Inputs in Argumentreihenfolge per
|
||
General-Copy vorbereiten, Offsets/physische Data-Größen binden und Kopien bis zur
|
||
Command-Completion halten. Kein eager Mehrkernel-Callback und kein neuer Shader.
|
||
|
||
**Konkrete Geometrieabweichung korrigiert:** Der bisherige eager `gdn_decode`
|
||
übermittelte das MTPLX-Thread-Grid `[256,1,48]` mit `individual_threads=false`.
|
||
Die native Bridge führte damit `dispatchThreadgroups` aus: 256 Gruppen in X
|
||
statt einer, bei identischen Ausgaben aus redundanten Schreibvorgängen.
|
||
`gdn_step_fused.py:237`/`custom_kernel.cpp` verlangen `dispatchThreads`.
|
||
Der neue Graph und der alte Helper nutzen jetzt dieselbe korrekte Bindung.
|
||
Das ist eine Korrektur im bislang `cfg(test)`-Port, **keine Erklärung oder
|
||
Behebung des produktiven UI-Stalls**. Es wurde kein Gesamtmodell-Speedup daraus
|
||
abgeleitet.
|
||
|
||
Ein opt-in Test-Recorder erfasst erfolgreiche native Dispatch-Aufrufe mit
|
||
Kernelname, Grid, Gruppengröße und Thread-/Gruppensemantik. Regressionstests
|
||
prüfen den tatsächlichen GDN-Aufruf im eager und Graph-Pfad, nicht nur Hashes.
|
||
Der Recorder ist `cfg(test)` und gelangt nicht in Produktmessungen.
|
||
|
||
Zwölf bestehende tatsächliche `GatedDeltaNet.__call__`-Receipts stimmen exakt:
|
||
fused/separate/mixed, mit/ohne anfänglichen Conv-Zustand, jeweils zwei Schritte.
|
||
Jeder Fall läuft sowohl mit Evaluation pro Schritt als auch als ein verbundener
|
||
Graph mit gemeinsamer späterer Evaluation. Zwei weitere GDN-Kernelreceipts
|
||
prüfen gestridete Inputs mit Offset, General-Copies und Evaluation vom letzten
|
||
Output-Geschwister aus. Wiederverwendung des MLP-Affine-Fixture-Helfers; keine
|
||
neuen Referenzdaten, Modelle oder Downloads erforderlich.
|
||
|
||
Prüfstand: Port-Suite **88/88 normal (43,96 s)**; nach dem abschließenden
|
||
z-Reshape-Reihenfolgeabgleich **88/88 unretained (44,01 s)** und betroffene
|
||
Graphprüfungen **2/2 normal (0,18 s)** / **2/2 Fast-Fences (0,18 s)**. Clippy,
|
||
Produkt-Buildcheck, Format-/Diff-Prüfung und Originalquellen-/Metallib-Prüfung
|
||
bestanden. Beleg: `local-eval-results/20260907-mtplx-port/graph-gdn-check.log`.
|
||
Staged Prefill/Verify, Branch-/Capture-/Cache-Orchestrierung und vollständige
|
||
Modell-/Produktanbindung bleiben offen; P06 und die P16-Paritätsabnahme bleiben
|
||
unerledigt. Die neue Funktion ersetzt ausdrücklich nicht deren übrige Zweige.
|
||
|
||
### GDN-Verify, Delta-Update und gemeinsame Compiled-Ausführung (2026-09-07)
|
||
|
||
Der fusionierte Conv-Verify-Zweig für B=1/S=2..6 ist jetzt durchgehend als
|
||
Array-Graph verbunden: Eingangsprojektionen/Split → Conv/Norm → Delta-Update
|
||
→ SigmoidRMSNormGated → Ausgangsprojektion. Conv-/Delta-Zustand und die sechs
|
||
Capture-Commit-Eingänge werden referenzgleich weitergegeben. Capture hält
|
||
qkv/q/k/v/a/b nur bei aktivierter Erfassung; ohne Capture werden diese
|
||
zusätzlichen Referenzen nicht im Rückgabewert gehalten. Cache-Advance und
|
||
Modell-Branchauswahl bleiben Aufgaben der noch ausstehenden Orchestrierung.
|
||
|
||
`gated_delta_update` enthält normale Sigmoid-, Compiled-compute_g- und
|
||
Custom-Kernel-Knoten einschließlich optionalem FP32-Nullzustand und Maske.
|
||
Die ursprünglichen Conv/Norm- und Rekurrenzkernel verwenden gemeinsam die
|
||
CustomKernel-Allokations-/Copy-/Lebensdauerfolge des vorigen Decode-Ports.
|
||
Der GDN-Conv-Dispatch zählt 10240 Threads/1024 pro Gruppe; Delta zählt
|
||
`[32,128,B*48]` Threads mit `[32,4,1]` pro Gruppe. Die Testbeobachtung an der
|
||
nativen Grenze sichert diese Geometrien ab.
|
||
|
||
SiLU und compute_g verwenden den gemeinsamen `compiled.rs`-Evaluator für die
|
||
bereits erfassten nichtskalaren Kernel: Contiguity über alle Eingänge,
|
||
Broadcast-/Joint-Collapse, negative/large Indizes, Output-Allokation und
|
||
Donation gemäß `common/compiled.cpp`/`metal/compiled.cpp`. Kein neuer Shader
|
||
und kein allgemeiner JIT-Ersatz. Ein direkter DOT-Export aus dem gepinnten
|
||
Referenzprozess bestätigt A_log `[48]`, a `[1,1,48]` und dt_bias `[48]` als
|
||
direkte Compiled-Eingänge; die Softplus-Konstante ist im erfassten Shader.
|
||
Auch die einzelne GDN-Zeile wählt deshalb den kollabierten strided-1-Kernel,
|
||
nicht anhand der physischen Länge einen contiguous-Kernel. Die tatsächliche
|
||
compute_g-Kernelwahl wird für alle 80 Delta-Receipts mitgeprüft.
|
||
|
||
Nachweise: sechs Conv/Norm-Kernelreceipts und 80 tatsächliche Delta-Update-
|
||
Receipts exakt (1/4/7/32/2048 Zeilen, beide Gate-Layouts, Maske an/aus,
|
||
Initialzustand an/aus, zwei fortgesetzte Schritte). Zwölf vollständige echte
|
||
Verify-Modulreceipts bei 2/4/6 Zeilen stimmen einschließlich Q/K/V exakt;
|
||
alle drei Hauptoutputs ohne Capture sind dazu bytegleich. Der erste
|
||
Verify-Testversuch verwendete für vier Zeilen einen nicht existierenden
|
||
Forward-Fixturenamen; die Zuordnung wurde auf die vorhandenen vollständigen
|
||
Staged-Receipts korrigiert, keine Referenzwerte oder Hashprüfung abgeschwächt.
|
||
|
||
Prüfstand: gesamte Port-Suite **90/90 normal (46,46 s)** und **90/90 unretained
|
||
(45,17 s)**. Fast-Fences: GDN **4/4 (1,13 s)**, MLP **2/2 (0,28 s)**.
|
||
Nach zusätzlicher compute_g-Dispatch-Assertion derselbe betroffene Test erneut
|
||
normal/unretained/Fast-Fences bestanden (0,94/0,90/0,96 s). Clippy,
|
||
Produkt-Buildcheck, Format-/Diff-Prüfung und Originalquellen-/Metallib-Prüfung
|
||
bestanden. Beleg: `local-eval-results/20260907-mtplx-port/graph-gdn-verify-check.log`.
|
||
|
||
Offen bleiben der allgemeine Concatenate/Conv1d/Reduktions-Prefill-Graph,
|
||
maskierte/ragged Conv-Fallbacks, Single-Row-Output-Fusion als Graph, vollständige
|
||
Branch-/Capture-Commit-/Cache-Orchestrierung und Produktintegration. Die
|
||
2048-Zeilen-Rekurrenzprüfung ist **kein vollständiger Prefill-Nachweis**.
|
||
P06/P16 und das Drei-Modell-Performanceziel bleiben ausdrücklich offen.
|
||
|
||
### GDN-Conv1d-Prefill als zusammenhängender Array-Graph (2026-09-07)
|
||
|
||
Der unmaskierte, längenlose Conv1d-Fallback ist jetzt von den Eingangsprojektionen
|
||
bis zur Ausgangsprojektion verbunden: Concatenate → Contiguous-Conv-Zustand →
|
||
Depthwise-Conv1d → erfasste SiLU → Split/Head-Reshape → FP32-L2-Summe/Rsqrt →
|
||
BF16-Rückkonvertierung/Q-Skalierung → Delta-Update → SigmoidRMSNormGated →
|
||
Ausgangsprojektion. Auch S=1 bei abgeschalteter Fusion nimmt diesen Pfad.
|
||
Die vorherige Beschränkung auf den fusionierten Verify-Zweig entfällt damit
|
||
für unmaskierte Eingaben ohne Cache-Längen. Modellwahl und cache.advance(S)
|
||
sind weiterhin nicht durch diese Graphfunktion ersetzt.
|
||
|
||
Concatenate verwendet die gemeinsame Copy-Implementierung jetzt auch als
|
||
GeneralGeneral: gemeinsame Kollabierung von Quell-/Ziel-Strides, echte
|
||
Byte-Offsets, Referenz-Datengrößen und concurrent disjoint writers. Die
|
||
Output-Slices sind wie in der Referenz primitive-/speicherlose temporäre
|
||
Array-Deskriptoren mit anschließend geteiltem Output-Backing. Conv1d allokiert
|
||
zuerst den Output und materialisiert danach bei Bedarf Input und Gewicht in
|
||
dieser Reihenfolge. Kein neuer Shader und keine eigene Faltung: Der originale
|
||
`depthwise_conv_1d_*`-Kernel zählt `[C,Tout,B]` Threads. Die GDN-Summe wählt
|
||
referenzgleich zwischen row_reduce_looped (16 Köpfe bei S=1) und
|
||
row_reduce_simple (ab 32 Köpfen); die übrigen allgemeinen Reduktionspläne
|
||
werden nicht als portiert ausgegeben.
|
||
|
||
Der bestehende vollständige Modulreceipt-Test umfasst jetzt **52 Fälle**:
|
||
12 fusionierte Verify-Fälle und 40 Conv1d-Fallback-Fälle, S=1/2/4/6/7/32/2048,
|
||
Initialzustand an/aus, zwei fortgesetzte Schritte und die jeweils anwendbaren
|
||
Fusionsflags. Alle sechs Output-Hashes einschließlich q/k/v sowie beider
|
||
Folgezustände sind exakt. Ohne Capture stimmen die drei Hauptoutputs bytegenau
|
||
mit dem Capture-Lauf überein. Kernelwahl und Dispatch-Geometrie von Conv1d und
|
||
beiden Summen werden an der nativen Grenze zusätzlich geprüft. Der strided
|
||
V-Capture wird ausschließlich nach dem eigentlichen Forward für den
|
||
Fixture-Reader gepackt; der Modellgraph behält seinen originalen View.
|
||
Ein kleiner zusätzlicher Concatenate-Test prüft vierdimensionale transponierte
|
||
und rückwärts gerichtete Views, alle vier Achsen, Typ-Promotion, leere Inputs
|
||
und die Referenz-Single-Input-Identität vor Achsenvalidierung.
|
||
|
||
Prüfstand: komplette Port-Suite **91/91 normal (45,89 s)** und **91/91 unretained
|
||
(45,40 s)**; Fast-Fences: GDN **4/4 (1,84 s)**, Concatenate **1/1 (0,05 s)**.
|
||
Clippy, Produkt-Buildcheck, Format-/Diff-Prüfung bestanden. Originalquellen weiterhin
|
||
15 Körper / 35 Custom-Einstiegspunkte / 20 Runtime-Einheiten / 84 Runtime-
|
||
Einstiegspunkte plus dynamische QSA-Quellen exakt, unveränderte Metallib-SHA256
|
||
`dc59d1cceb1a5c7e578232e6e41e28e2c73c9463ac6dbc3886c3ee17ffc270ed`.
|
||
Prüfbeleg: `local-eval-results/20260907-mtplx-port/graph-gdn-prefill-check.log`.
|
||
|
||
**Weiter offen:** maskierter Conv-Select, ragged Cache-Längen/Gather,
|
||
Single-Row-Output-Fusion als Graph, vollständige Modell-/Cache-/Capture-Commit-
|
||
Orchestrierung und Produktintegration. P06/P16 bleiben offen. Der gesamte Port
|
||
ist weiterhin `cfg(test)`; weder UI-Responsivität noch Durchsatzparität sind
|
||
damit nachgewiesen. Die vollständigen Drei-Modell-Chats werden dadurch nicht
|
||
ersetzt; es gab keinen Modelllauf, Download oder Performance-Rollback.
|
||
|
||
### Maskierter und längenabhängiger GDN-Prefill (2026-09-07)
|
||
|
||
Der Conv1d-Graph enthält nun auch MTPLXs Maskierungs- und ragged-State-Zweig.
|
||
QKV wird vor Concatenate mit `where(mask[..., None], qkv, 0)` maskiert; Capture
|
||
bewahrt genau diesen QKV-Strom. Die ursprüngliche Maske geht zusätzlich an die
|
||
Delta-Rekurrenz. Für Cache-Längen bleibt die Referenzfolge als einzelne Knoten
|
||
erhalten: Maximum/Minimum auf `[0,S]` → ExpandDims → Arange(INT32) → Add →
|
||
ExpandDims → GatherAxis über das Conv-Fenster. Keine CPU-Auswertung des
|
||
Längentensors und kein vorgezogener GPU-Sync. Ohne Längen bleibt der bestehende
|
||
Contiguous-Tail-Zweig unverändert.
|
||
|
||
`indexing.rs` enthält die dazu verwendeten Select-, GatherAxis- und Prefix-
|
||
Arange-Primitiven. Select übernimmt Typ-/Broadcast-Regeln sowie Scalar-/Vector-/
|
||
General-Kernelwahl, Donation, Strides und Dispatch aus der gepinnten Runtime.
|
||
Gather verwendet die bereits exportierten BF16/I32- bzw. BF16/U32-Kernel mit
|
||
tatsächlichen Src-/Index-Contiguity-Flags, Größen, Strides und Byte-Offsets.
|
||
Statisches Broadcast wird von Binary, Select und GatherAxis gemeinsam genutzt.
|
||
Andere Gather-Dtypes bzw. dynamisches Broadcast-Tracing werden damit nicht als
|
||
portiert erklärt.
|
||
|
||
Eine ABI-Abweichung wurde an der gemeinsamen Bridge behoben: Leere Inline-
|
||
Vektoren werden von `ds4_gpu_mtplx_encode` nicht mehr pauschal zurückgewiesen.
|
||
Die Referenz bindet bei Rank-1-Gather tatsächlich null Byte für Shape/Strides.
|
||
Die Bridge führt jetzt denselben Metal-Aufruf aus; kein Dummy-Payload, keine
|
||
Shaderänderung. Nichtleere Nullpointer, Übergröße, Offsets und doppelte Slots
|
||
werden weiterhin zurückgewiesen. Der Rank-1-Gather-Test schließt rückwärts
|
||
gerichtete Source-/Index-Views mit nichtnull Byte-Offsets ein.
|
||
|
||
Der erweiterte vollständige GDN-Modultest prüft **116 MTPLX-Receipts exakt**,
|
||
jeweils sechs Outputs einschließlich beider Zustände, plus bytegleiche
|
||
Capture-off-Hauptoutputs. S=1/2/4/6/7/32/2048, maskiert/unmaskiert, zwei
|
||
fortgesetzte Schritte, Initialzustand an/aus und Längen unter/innerhalb/über der
|
||
Chunk-Grenze. Längenfälle hier S=4/7; S=1 bei aktivierter Output-Fusion bleibt
|
||
bis zum Port dieser Fusion offen. Die tatsächliche Select-/Gather-Kernelwahl
|
||
und Geometrie werden zusätzlich beobachtet. Ein kleiner Indexing-Test deckt
|
||
alle fünf Select-Layoutarten, Column-Layout, Broadcast-Gather, negative Indizes,
|
||
BF16/I32/U32, Rank-1-Leerargumente und leeres Arange ab.
|
||
|
||
Prüfstand: gesamte Port-Suite **92/92 normal (45,39 s)** und **92/92 unretained
|
||
(45,23 s)**. Fast-Fences: GDN **4/4 (2,62 s)**, Indexing **1/1 (0,06 s)**.
|
||
Clippy (8,87 s), Produkt-Buildcheck (3,26 s), Format-/Diff- und Originalquellen-/
|
||
Metallib-Prüfung bestanden. Prüfbeleg:
|
||
`local-eval-results/20260907-mtplx-port/graph-gdn-masked-lengths-check.log`.
|
||
|
||
Weiterhin offen sind Single-Row-Output-Fusion, vollständige Modell-/Cache-/
|
||
Capture-Commit-Orchestrierung und Produktintegration. Der Port bleibt
|
||
`cfg(test)`; keine Modell-/UI-/Performance-Paritätsbehauptung. P06/P16 und das
|
||
vollständige Drei-Modell-Ziel bleiben offen; keine Downloads oder Rücknahmen.
|
||
|
||
### Gemeinsamer GDN-Forward, Output-Fusion und Cache-Fortschreibung (2026-09-07)
|
||
|
||
Die getrennten kanonischen `fused_decode`-, `prefill`- und `fused_verify`-
|
||
Einstiege sind durch `gdn::forward` ersetzt. Dieser bildet für die installierte
|
||
Inferenzgeometrie die Reihenfolge von `GatedDeltaNet.__call__` ab: Projektionen,
|
||
Conv-State/Maskierung, Fused-Step oder Conv-Zweig, Capture, Delta-Update,
|
||
Cache-Fortschreibung und Output-Fusion oder Norm/Projektion. Die unveränderten
|
||
Kernel werden nicht anhand lokaler Geschwindigkeitsvergleiche ausgewählt.
|
||
|
||
- Capture sperrt den Live-Step, aber nicht pauschal Conv-/Output-Fusion.
|
||
Bereits gespeicherte Capture-Arrays bleiben erhalten, bis ein neuer Capture-
|
||
Aufruf sie ersetzt. Der Step-Zweig kehrt vor der separaten Output-Fusion zurück.
|
||
- Cache-Längen und Masken sperren Conv-Fusion; B>1 und fehlender Cache verwenden
|
||
den allgemeinen Conv-Zweig. Ohne Cache wird kein Cache-Tail-Graph erzeugt.
|
||
Die tatsächlichen einmaligen Single-/Multi-Row-Geräteproben werden wie in
|
||
MTPLX ausgeführt und ihr Erfolg pro Prozess gespeichert.
|
||
- `Cache::advance` subtrahiert S von Längen und linkem Padding als Tensor-
|
||
Operationen, bevor der Output-Graph aufgebaut wird; kein CPU-Readback.
|
||
Der aktuelle Vertrag für diese Metadaten ist INT32.
|
||
- Die Single-Row-Output-Fusion verwendet die Originalkörper für Gruppen32/64
|
||
und BF16/FP32-Eingabe, einschließlich exakt 81920 Threads in 1024er Gruppen.
|
||
|
||
Referenzabdeckung: alle **264 Forward-Receipts** mit fusionierten, getrennten
|
||
und gemischt quantisierten Eingangsprojektionen; jeweils sofortige und
|
||
verzögerte Auswertung zweier aufeinanderfolgender Aufrufe. Zusätzlich werden
|
||
die tatsächlich ausgeführten Step-/Conv-Fusionszweige gegen die Referenzdaten
|
||
geprüft. Alle **130 Staged-Receipts** sind nun eingeschlossen, auch die zuvor
|
||
fehlenden Single-Row-Fälle mit Output-Fusion. Vier direkte Output-Kernel-
|
||
Receipts sichern Typen, Gruppen und Dispatch-Geometrie ab.
|
||
|
||
`tools/mtplx-kernel-fixtures.py:gdn_graph_lifecycle_fixtures` erzeugt außerdem
|
||
**24 neue tatsächliche MTPLX-Modulreceipts**, nicht Rust-generierte Sollwerte:
|
||
B=1/2, S=1/7, kein Cache/leerer Cache/Metadaten, jeweils zwei Aufrufe mit Capture
|
||
nur beim ersten. Sie prüfen Ausgaben, Conv-/Delta-Zustände, Längen/Padding und
|
||
den Erhalt der Capture-Array-Identitäten beim Folgeaufruf.
|
||
|
||
Verifikation: vollständige Port-Suite **92/92 (48,75 s)**, mit unretained
|
||
Command Buffers **92/92 (48,96 s)**; GDN mit Fast-Fences **4/4 (5,46 s)**.
|
||
Release-Clippy, Produkt-Check, Format-/Diff-Check und unveränderter
|
||
Referenz-Shaderexport bestehen. Der Prüfbeleg liegt unter
|
||
`local-eval-results/20260907-mtplx-port/graph-gdn-forward-check.log`.
|
||
|
||
Weiter offen: äußerer Modellablauf mit Maskenerzeugung, Cache-Batchoperationen,
|
||
Capture-Commit/Repair, weitere Graphkomponenten und Produktintegration.
|
||
Der kanonische Graph bleibt `cfg(test)`. Diese Modulprüfungen sind weder eine
|
||
UI-Responsivitätsmessung noch ein Nachweis der Modell-/Performance-Parität;
|
||
P06/P16 und das Drei-Modell-Ziel bleiben offen.
|
||
|
||
### GDN-Capture-Commit mit nachfolgendem Decode (2026-09-07)
|
||
|
||
`gdn::Cache` übernimmt jetzt die Validierungsregeln und den reinen GDN-Zweig
|
||
von `Qwen4ExpTextModel.commit_verified_window`: validierte Capture-Zeilen auf
|
||
die angenommene Länge beschränken, Delta-Rekurrenz vom Snapshot ausführen,
|
||
Conv-Tape aus Snapshot und behaltenem QKV bilden, Capture freigeben. Fehlender
|
||
Conv-Snapshot wird wie in MTPLX durch einen Nullzustand ersetzt; Delta-Snapshot
|
||
und passende Capture-Breite sind verpflichtend. Längen/Padding werden dabei
|
||
weder zurückgesetzt noch fortgeschrieben.
|
||
|
||
Die Trennung zwischen Validierung und Replay erlaubt dem noch zu verbindenden
|
||
äußeren Modellablauf, zuerst **alle** Schichten zu validieren und erst danach
|
||
irgendeinen Cache zu verändern. Sie ersetzt diese globale Transaktion nicht.
|
||
QSA-Trim, PLE-Replay und die übergeordnete Fehler-/Rollback-Orchestrierung
|
||
bleiben ausdrücklich offen. Kein vollständiger P12-Abschluss.
|
||
|
||
**26 neue tatsächliche MTPLX-Commit-Receipts** decken Fenster1/2/4/6, jede
|
||
behaltene Präfixlänge und vorhandene/fehlende Conv-Snapshots ab. Die sieben
|
||
Ausgabehashes einschließlich des nachfolgenden Decode stimmen exakt; im Rust-
|
||
Graph sowohl bei sofortiger als auch verzögerter Commit-Auswertung. Native
|
||
Dispatch-Aufzeichnung prüft: keine Submission während der Commit-Konstruktion,
|
||
nur eine Delta-Rekurrenz und keine Projektionen/Conv-Kernel im isolierten Replay.
|
||
Ungültige Präfixe, fehlende/kurze Snapshots und fehlende/falsch breite Captures
|
||
werden ohne Veränderung der Cache-Array-Identitäten geprüft.
|
||
|
||
Ein zunächst abweichender Metadatenhash lag am Ablesezeitpunkt des Tests:
|
||
Pythons `mx.array.__isub__` überschreibt den Deskriptor des gespeicherten
|
||
Metadatenobjekts beim folgenden Decode. Der Rust-Test liest deshalb die dann
|
||
aktuellen Cache-Metadaten statt einer vorher angelegten Wertkopie. Die echten
|
||
MTPLX-Receipts wurden nicht geändert; der Commit selbst erhält die Metadaten.
|
||
|
||
Verifikation: Port-Suite **92/92 (49,60 s)**, unretained **92/92 (49,50 s)**;
|
||
GDN mit Fast-Fences **4/4 (5,90 s)**. Release-Clippy, Format-/Diff-Check und
|
||
unveränderter Shaderexport bestehen. Prüfbeleg:
|
||
`local-eval-results/20260907-mtplx-port/graph-gdn-commit-check.log`.
|
||
Der kanonische Port ist weiterhin ausschließlich `cfg(test)`; keine Aussage
|
||
über Produktperformance, UI-Responsivität oder die 2%-Abnahme.
|
||
|
||
### Hyper-Connection-Graph und Original-Quantisierung (2026-09-07)
|
||
|
||
Der kanonische Graph verbindet jetzt die Custom-Primitiven von
|
||
`hyper_connection.py` und `hyper_connection_v3.py` mit der originalen
|
||
`prepare_v3_pack`-Kette: Down/Inject konkatenieren, beide Matrizen mittels
|
||
`fast::Quantize` quantisieren, sechs Contiguous-Ausgänge auswerten. Die V3-
|
||
Geräteprobe führt beide echten Kernel mit den originalen Dummy-Geometrien aus
|
||
und speichert ihr Ergebnis pro Prozess. Die Probe bleibt vor der kostenpflichtigen
|
||
Pack-Vorbereitung dem noch zu verbindenden Modellselektor zugeordnet.
|
||
|
||
`linear::quantize` übernimmt Shape-/Parameterprüfung, drei Array-Siblings,
|
||
Allokationsfolge und Row-Contiguous-Kopie aus dem gepinnten Runtime-Backend.
|
||
Es bindet die unveränderten `affine_quantize_*`-Kernel aus derselben Metallib:
|
||
Gruppen32/64/128, Bits2/3/4/5/6/8, BF16/F16/F32. Die allgemeinen Elementkernel-
|
||
Typnamen sind hier nicht gültig; die originalen affinen Symboltypen lauten
|
||
`bfloat16_t`, `float16_t` und `float`. Diese Bindungsabweichung wurde bei der
|
||
ersten Ausführung erkannt und korrigiert, ohne Shaderänderung.
|
||
|
||
**59 tatsächliche Quantisierungsreceipts** decken alle 54 Typ-/Gruppen-/Bit-
|
||
Kombinationen sowie Slice, Transpose und Null-/Positiv-/Negativkonstanten ab.
|
||
U32-Packs werden roh gehasht, nicht verlustbehaftet nach Float konvertiert.
|
||
Der echte V3-Pack stimmt in allen sechs Ausgängen exakt mit MTPLX überein;
|
||
anschließende V3-Leseschritte stimmen sowohl mit neuen als auch bisherigen
|
||
Sollwerten überein. Die ursprünglichen Read-Kernel mit/ohne Injection bei
|
||
S=1/4/8 sind ebenfalls über den Graphen geprüft. R1/R2 verwenden genau ihre
|
||
11264/81920 Threads, jeweils 1024 pro Gruppe, und zusammen einen Command Buffer.
|
||
|
||
Der frühere direkte V3-Test mit `kernel_qwen_quantize_hyper_q8` ist entfernt;
|
||
seine Ausgabereferenz und One-Command-Buffer-Prüfung liegen jetzt im verbundenen
|
||
Test mit Originalquantisierung. Der letztere prüft den Zähler des tatsächlichen
|
||
Graph-Streams, nicht den globalen Zähler der alten Produktqueue.
|
||
|
||
Zu diesem Zwischenstand noch offen für `GatedResidual`: eager Norm/Matmul/Mean-
|
||
Kette, Modellselektion und Lebensdauer des pro Modul gecachten Packs sowie
|
||
Verbindung mit dem restlichen Modell und Produktpfad. Keine Rücknahme wegen
|
||
Mikrobenchmark-Ergebnissen; `cfg(test)`, P09/P16 und Gesamtparität bleiben offen.
|
||
|
||
Verifikation: vollständige Port-Suite **94/94 (51,84 s)**, unretained
|
||
**94/94 (51,14 s)**. Fast-Fences: Hyper **1/1 (0,09 s)**, Quantize
|
||
**1/1 (0,26 s)**. Release-Clippy, Format-/Diff-Check und unveränderter
|
||
Shaderexport bestehen. Prüfbeleg:
|
||
`local-eval-results/20260907-mtplx-port/graph-hyper-quantize-check.log`.
|
||
|
||
### Verbundener GatedResidual einschließlich eager Prefill (2026-09-07)
|
||
|
||
`hyper::GatedResidual` verbindet jetzt für die installierte BF16-Geometrie
|
||
den vollständigen Read: GroupedRMSNorm, Down/4, SiLU, Up/Sigmoid, gruppiertes
|
||
Produkt und Mean sowie die optionale Injection. Mean bleibt wie im Original
|
||
eine BF16-Summe mit anschließender BF16-Multiplikation mit1/4. Die dense
|
||
Projektion verwendet die unveränderte Runtime-Metallib mit originaler
|
||
M5-Max-Auswahl: GEMV, Wide-GEMV bis15 Zeilen, NAX-GEMM und NAX-Split-K samt
|
||
FP32-Zwischenergebnis und BF16-Akkumulationsausgang. Statisches Flatten/Unflatten,
|
||
Transpose-/Kopierprüfung, Function Constants, Bindings und Dispatch-Geometrie
|
||
folgen `ops.cpp`, `matmul.cpp` und `reduce.cpp` der gepinnten Runtime.
|
||
|
||
Der Modellselektor prüft zuerst V3 (eine Zeile, Combine, nichtquantisierter
|
||
Down, Geräteprobe), anschließend den ursprünglichen fusionierten Read
|
||
(bis8 Zeilen), ansonsten eager. Der V3-Pack gehört zur Modulinstanz, wird nur
|
||
einmal erzeugt und über spätere Fused-/Eager-Aufrufe hinweg erhalten. Der
|
||
Combine-Ausgang behält die ursprüngliche Hyper-Array-Identität. Quantisierte
|
||
HC-Projektionen bleiben entsprechend MTPLX auf der eager-Kette.
|
||
|
||
`hyper_forward_fixtures` ruft die tatsächliche MTPLX-Klasse auf, ohne sie
|
||
nachzuimplementieren. Alle **128 Fälle** stimmen exakt überein: dichte und
|
||
quantisierte Gewichte, mit/ohne Combine, S=1/2/4/8/15/16/32/2048 und alle vier
|
||
Kombinationen der beiden HC-Schalter. Geprüft sind beide Ausgänge, ausgewählter
|
||
Pfad (111 eager,15 fused,2 V3), Pack-Existenz/-Identität und die native
|
||
NAX-/Split-K-Auswahl. Keine Referenzwerte wurden an Rust-Ergebnisse angepasst.
|
||
|
||
Die Operatoren sind weiterhin nur Teil des kanonischen `cfg(test)`-Ports.
|
||
DecoderLayer/PLE, vollständige Modell- und Produktanbindung sowie P09/P16-
|
||
Gesamtabnahme bleiben offen. Die Beschränkung des dichten Wrappers auf die
|
||
installierten BF16-Projektionen ist kein Nachweis für beliebige Datentypen,
|
||
Dot-Produkte, leere Matrizen oder andere GPU-Architekturen. Es gab keine
|
||
Shaderänderung, kleinere Prefill-Chunks oder Rücknahme nach Mikrobenchmarks.
|
||
|
||
Verifikation: gesamte Port-Suite **95/95 (55,49 s)**, unretained
|
||
**95/95 (52,73 s)**, Hyper mit Fast-Fences **2/2 (0,94 s)**. Release-Clippy,
|
||
Format-/Diff-Check und unveränderter Shaderexport bestehen. Prüfbeleg:
|
||
`local-eval-results/20260907-mtplx-port/graph-hyper-forward-check.log`.
|
||
|
||
### PLE-Projektion und dilatierte Cache-Fortsetzung (2026-09-07)
|
||
|
||
Der kanonische Graph verbindet `PLELayer` ab dem Ergebnis von
|
||
`NGramEmbedding`: Embedding-Cast, Key-/Value-Projektionen, drei GroupedRMSNorms,
|
||
BF16-Produktsumme, Divisor/Signed-Sqrt-Gate, Sigmoid, Broadcast/Reshape und
|
||
Short-Conv mit anschließendem SiLU und Residual-Add. Vorhandene dichte und
|
||
quantisierte Projektionen sowie Graph-/Copy-/Norm-/SiLU-Operatoren werden
|
||
wiederverwendet. Abs/Sign folgen dem originalen Typvertrag. Die gemeinsame
|
||
Row-Sum-Auswertung erhält GDNs FP32x128-Route und ergänzt PLEs BF16x2560-Route
|
||
mit640 Threads und originaler Simple-/Looped-Grenze.
|
||
|
||
Die PLE-Faltung mit Kernel4/Dilatation3 ist **nicht** der GDN-Depthwise1D-Pfad.
|
||
Die gepinnte Runtime bettet sie in2D ein und verwendet
|
||
`implicit_gemm_conv_2d_bfloat16_bm32_bn8_bk16_wm4_wn1_channel_1_filter_l`.
|
||
Rust bindet diesen unveränderten Metallib-Kernel mit den originalen Conv-/GEMM-
|
||
Parametern und der Grid-Geometrie. Ausgabeallokation sowie Input-/Weight-Kopien
|
||
verwenden denselben vorhandenen Helper wie GDN, in Originalreihenfolge.
|
||
Der Cache speichert die letzten9 Zeilen des Fensters als lazy Slice; die
|
||
Faltung liest noch das ganze Fenster, bevor der letzteS-Abschnitt aktiviert wird.
|
||
|
||
**84 tatsächliche MTPLX-PLELayer-Receipts** prüfen dense/quantized, S=1/4/7/8/
|
||
32/2048 sowie Batch2/S7; kein, leerer oder12-zeiliger Vorzustand, jeweils mit
|
||
anschließendem Ein-Zeilen-Decode. Der zweite Embedding-Eingang ist FP32 und wird
|
||
wie im Modell auf BF16 gecastet. Ausgabe und Cache stimmen exakt überein,
|
||
sowohl bei unmittelbarer als auch gemeinsamer verzögerter Auswertung
|
||
(168 Vergleiche). Native Faltungsauswahl/-Geometrie ist zusätzlich geprüft.
|
||
Der Fixture-Provider ersetzt ausschließlich den Lookup-Eingang; der restliche
|
||
Aufruf ist die tatsächliche unveränderte MTPLX-Klasse. **Dies beweist keinen
|
||
N-Gram-Lookup, kein Staging und keine IO-/LRU-Parität.**
|
||
|
||
Noch offen: NGramEmbedding samt Graph- und Staging-Pfaden, Sidecar/Resident-
|
||
Auswahl, Dequantisierung und Hot-Cache-Vertrag sowie Decoder-/Modell-/Produkt-
|
||
Anbindung. Der bisherige Produkt-PleReader arbeitet noch anders als MTPLX
|
||
(u.a. erste-Auftritts-Deduplizierung statt sortierter Unique-IDs und fehlender
|
||
identischer4096-Unique-Row-Bypass). Er wird nicht durch diese PLE-Projektions-
|
||
Tests freigestellt. `cfg(test)`, P10/P16 und das Drei-Modell-Ziel bleiben offen.
|
||
|
||
Verifikation: gesamte Port-Suite **96/96 (51,40 s)**, unretained
|
||
**96/96 (51,07 s)**, PLE mit Fast-Fences **1/1 (1,48 s)**. Release-Clippy,
|
||
Format-/Diff-Check und unveränderter Shaderexport bestehen. Prüfbeleg:
|
||
`local-eval-results/20260907-mtplx-port/graph-ple-projection-check.log`.
|
||
|
||
### N-Gram-CPU-Staging-Hash und rohe History (2026-09-07)
|
||
|
||
`ngram::HashContract::rows` übernimmt den materialisierten CPU-Hash aus
|
||
`NGramEmbedding._rows_np` für den installierten Vertrag mit3-Grams/16 Heads.
|
||
Int64-Multiplikation, XOR, positiver Rest und Offsetaddition erhalten das
|
||
Overflow-Verhalten der NumPy-Referenz. EOS beeinflusst die verschobenen Tokens
|
||
erst **nach** dem Hash der EOS-Position; der zurückgegebene History-Cache behält
|
||
die tatsächlichen letzten2 Tokens. Eine EOS-normalisierte History ist nicht
|
||
die Cache-Repräsentation der Referenz. Der bisherige Produkt-Einzel-Token-Hash
|
||
bleibt davon getrennt; daraus allein wird kein Unterschied seiner fertigen
|
||
Row-IDs oder eine Ursache der UI-Verzögerungen behauptet.
|
||
|
||
**64 Original-Receipts** verwenden die installierte EOS-ID248044 und die
|
||
Originalkonstanten. B=1/2, S=0/1/4/2048, vorherige History-Längen0/1/2/5 und
|
||
jeweils ein Fortsetzungstoken stimmen in Roh-I64-Ausgabehashes und Shapes exakt
|
||
überein. Fälle enthalten aufeinanderfolgende EOS, negative Werte und Int64-
|
||
Grenzwerte. Auch die Python-Slice-Semantik bei S=0 (alle History-Rows) bleibt
|
||
erhalten. Eingabe-/History-Formen und positive Head-Größen werden geprüft.
|
||
Rust benötigt keine NumPy-Zwischenmatrizen; die gleiche Berechnung läuft in
|
||
einem Durchgang, ohne eine GPU-Auswertung oder Synchronisierung einzuführen.
|
||
|
||
Dies ist ausschließlich der CPU-Hash-Baustein, **noch kein verbundenes
|
||
`NGramEmbedding.stage`/`__call__`**. Lazy GPU-Hash, Stage-Auswahl/-Verifikation,
|
||
Sidecar/Resident-Gather, Dequantisierung und LRU/Bypass bleiben offen; der
|
||
pipelined-AR-Pfad wird nicht durch diesen CPU-Baustein ersetzt. P10/P16,
|
||
Produktintegration und Drei-Modell-Performanceabnahme bleiben offen.
|
||
|
||
Verifikation: CPU-Port-Suite **22 bestanden,75 GPU-Tests explizit ignoriert**;
|
||
Release-Clippy, Format-/Diff-Check bestehen. Keine neue GPU-Performanceprüfung
|
||
für diesen CPU-only-Baustein. Prüfbeleg:
|
||
`local-eval-results/20260907-mtplx-port/ngram-cpu-hash-check.log`.
|
||
|
||
### Lazy N-Gram-GPU-Hash bis zu den Tabellen-IDs (2026-09-07)
|
||
|
||
`ngram::GpuHash::rows` bildet nun die originale `_graph_path`-Kette bis zum
|
||
Tabellenaufruf nach: I64-Cast, History-Concat/-Slice, beide voneinander
|
||
getrennten `_shift_ignore_eos`-Graphen mit Arange/Select/Cummax/Gather,
|
||
Int64-Multiply/XOR/Remainder und Head-Offsets. Checkpointkonstanten bleiben
|
||
Array-Leaves. Der Konstruktor liest keine Tokenwerte zurück und wertet keine
|
||
GPU-Knoten aus; auch eine noch nicht ausgewertete History kann weitergereicht
|
||
werden. Kein fusionierter Eigenbau-Hash und kein Ersatz durch den CPU-Hash.
|
||
|
||
Gemeinsame Graphoperatoren wurden um Equal/GreaterEqual mit Bool-Ausgang,
|
||
BitwiseAnd/Xor und Remainder sowie I64-Arange/-Gather und inclusive Cummax
|
||
erweitert. Für Gather sind8 zusätzliche I64/I64-Spezialisierungen des
|
||
**unveränderten** Originaltemplates exportiert; der Original-Metallib-Hash ist
|
||
unverändert. Scan übernimmt seine eigene Allokations-/Donation-Regel ohne
|
||
die16KiB-Grenze des Unary-Helfers; diese Besonderheit wurde beim Quellabgleich
|
||
korrigiert und mit einem oversized backing separat geprüft.
|
||
|
||
**60 tatsächliche MTPLX-GPU-Receipts** stimmen in IDs, roher History und Shapes
|
||
exakt überein: B1/2, S1/4/2048, fehlende oder0/1/2/5-zeilige History und je ein
|
||
Decode-Folgeschritt. Sofortige und verzögerte Auswertung ergeben120 Vergleiche;
|
||
der Graphaufbau dispatcht nichts, beide Original-Scans und I64-Gather werden
|
||
tatsächlich ausgeführt. Zusätzliche30 Scan-Prüfungen decken row-/column-major,
|
||
Broadcast-Kopien, erhaltene Aliase und Threadgrößengrenzen bis4097 Elemente ab.
|
||
Ein passender Folgeschritt prüft außerdem lazy I32→I64-Tokens.
|
||
|
||
Die Referenz ruft `_graph_path` selbst auf; ausschließlich der Tabellenaufruf
|
||
gibt im Fixture seine IDs zurück. Lookup/Dequantisierung, Sidecar/Resident-
|
||
Wahl, Stage-Auswahl/-Verifikation/-Konsum, Hot-Cache/Bypass und Decoder-/Modell-
|
||
Anbindung bleiben offen. Kein Nachweis für beliebige leere Cummax-Eingaben,
|
||
kein vollständiger NGramEmbedding-Aufruf, keine Produkt- oder2%-Abnahme.
|
||
|
||
Verifikation nach der Scan-Donation-Korrektur: reguläre Port-Suite **98/98**
|
||
in51,93s, Unretained-Command-Buffer-Suite **98/98** in52,73s und der NGram-Test
|
||
mit `MLX_METAL_FAST_SYNCH=1` **1/1** in0,14s. Release-Clippy sowie Format-/Diff-
|
||
und Originalquellen-Prüfung bestehen. Diese Zeiten sind Testlaufzeiten, keine
|
||
Modell-Performancewerte. Prüfbeleg:
|
||
`local-eval-results/20260907-mtplx-port/ngram-gpu-hash-check.log`.
|
||
|
||
### Verbundener residenter N-Gram-Graph (2026-09-07)
|
||
|
||
`GpuHash::embedding` verbindet nun den originalen Hash mit
|
||
`ResidentTable::gather`, affiner Dequantisierung und Head-Reshape. Der residente
|
||
Pfad liest keine IDs auf die CPU zurück und fügt keine Auswertung hinzu.
|
||
Der Loader muss die Tabelle vorab materialisieren; Laden/Residency-Entscheidung,
|
||
Sidecar-I/O, Hot-Cache, Stage-Auswahl und Produktanbindung sind noch nicht portiert.
|
||
|
||
`indexing::take_rows` verwendet wie die Referenz Gather plus Squeeze. Bei
|
||
zusammenhängenden Tabellen und Indizes läuft der originale GatherFront; andere
|
||
Views verwenden den originalen allgemeinen Gather, ohne vorgeschaltete Kopie.
|
||
I64-Indizes, negative Indizes, rank0..4, BF16/F16/F32/U32, Byte-Offsets und die
|
||
große Indexvariante sind im Dispatch berücksichtigt. Die neue GPU-Dequantisierung
|
||
übernimmt Output-Allokation vor den drei Contiguous-Vorbereitungen, Bindings und
|
||
Grid/Thread-Geometrie. Quantize verwendet denselben vorhandenen Copy-Mechanismus.
|
||
Die Tabelle verwendet gleiche Floating-Dtypes für Scales/Biases; gemischte
|
||
Parameter-Dtypes und nicht-affine Quantisierung werden hier nicht beansprucht.
|
||
|
||
Originalquellen unverändert: 12 weitere GatherFront-Spezialisierungen sowie40
|
||
originale Gather-JIT-Wrapper, ausschließlich mit angepassten Einstiegspunktnamen.
|
||
Zwei zusätzliche geprüfte Runtime-Units; Export insgesamt15 Custom-Bodies,
|
||
35 Custom-Einstiege und22 Runtime-Units/144 Runtime-Einstiege. Der unveränderte
|
||
Original-Metallib-Hash bleibt `dc59d1cceb1a5c7e578232e6e41e28e2c73c9463ac6dbc3886c3ee17ffc270ed`.
|
||
Ein erster Compile-Versuch fand die falsche Reihenfolge der Gather-Abhängigkeiten;
|
||
behoben durch Platzierung nach dem Original-Utils-Export, ohne Kerneländerung.
|
||
|
||
Neue Original-Receipts, jeweils unmittelbar und verzögert exakt verglichen:
|
||
|
||
- 324 affine Dequantisierungen: BF16/F16/F32, group32/64/128,
|
||
bits2/3/4/5/6/8, plain/transpose/slice/offset/broadcast/batch.
|
||
- 162 tatsächliche `NGramTable._lazy_gather`-Aufrufe: BF16/F16, raw8/9/160 und
|
||
Q4x160, zusammenhängende/transpose/offset Tabellen, skalare bis4D IDs,
|
||
Slice- und Broadcast-ID-Views. GatherFront/Gather-Auswahl wird geprüft.
|
||
- 24 vollständige originale residente `_graph_path`-Ausgaben einschließlich
|
||
Decode-Folgeschritt: raw/Q4, B1/2, S1/4/2048. Tabelle bewusst klein (17 Zeilen),
|
||
echte Headbreite160 und Ausgang2560; Hashkonstanten für kleine Vokabelgrößen
|
||
angepasst. Kein Ersatz des Tabellenaufrufs. Embedding und rohe History stimmen
|
||
exakt überein, auch wenn beide Schritte vor der Auswertung aufgebaut werden.
|
||
|
||
Das sind Korrektheits-/Graphbelege, keine Vollmodell-Performanceabnahme. Der
|
||
kanonische Port bleibt `cfg(test)`; aus diesen Ergebnissen folgt kein behobener
|
||
UI-Stall und keine erreichte2%-Parität.
|
||
|
||
Verifikation: reguläre Port-Suite101/101 in53,44s und mit Unretained-Command-
|
||
Buffers101/101 in53,25s; Release-Clippy, Format-/Diff- und Originalquellen-Check
|
||
bestehen. Die drei NGram-GPU-Tests bestehen auch mit `MLX_METAL_FAST_SYNCH=1`
|
||
in0,49s. Testlaufzeiten sind keine Modell-Performancewerte. Prüfbeleg:
|
||
`local-eval-results/20260907-mtplx-port/ngram-resident-check.log`.
|
||
|
||
### Verbundener Sidecar-Gather und Tabellenauswahl (2026-09-07)
|
||
|
||
`ngram_sidecar::SidecarGather` portiert nun `_SidecarGather` als zusammenhängenden
|
||
Dateipfad: getrennte read-only Tensor-Mappings mit Random-Advice, sortierte
|
||
eindeutige I64-IDs und inverse Expansion, optionaler persistenter Prefetch-Pool
|
||
mit höchstens16 Threads und originaler Chunkformel `clamp(ceil(n/32),1,64)`.
|
||
Prefetch liest jede Map pro Zeile mit `pread`; erst anschließend sammelt die
|
||
Generation die Rohzeilen aus den Mappings. Prefetch verändert den Cache nicht.
|
||
Threads und Aufträge werden vor Freigabe sauber beendet; nur eigene temporäre
|
||
Testdateien werden entfernt.
|
||
|
||
Der Hot-Cache speichert Rohzeilen-Views auf gemeinsam gehaltene Fetch-Matrizen.
|
||
Damit behalten verbleibende Zeilen wie NumPy ihren zugrundeliegenden Fetch-Block.
|
||
Ein HashMap-basierter doppelt verketteter LRU bietet O(1)-Touch/Eviction ohne
|
||
unbeschränkt wachsende historische Touch-Liste. Misses werden zuerst eingefügt,
|
||
alle eindeutigen Zeilen danach in sortierter Reihenfolge berührt und erst dann
|
||
überzählige Einträge entfernt. Die Ergebnisreferenzen überleben diese Eviction.
|
||
Leere Gathers, deaktivierter Cache und mehr als4096 eindeutige IDs umgehen den
|
||
LRU vollständig, ohne dessen Zähler/Reihenfolge zu verändern.
|
||
|
||
`gather_np` erzeugt Integer-Arrays/View und die vorhandene originale affine
|
||
Dequantisierung, ohne einen Graph auszuwerten. Der nicht gestagte `gather` liest
|
||
hingegen wie `_SidecarGather.__call__` den einmal ausgewerteten ID-Graph auf der
|
||
CPU. Der Abgleich mit `mlx_to_nd_array` erhält Strides und Byte-Offsets; keine
|
||
zusätzliche Contiguous-GPU-Kopie oder zweite Auswertung. Die Rohzeilenausgabe
|
||
bleibt anschließend lazy. `Table::gather` übernimmt die Referenzpriorität:
|
||
bevorzugte residente Tabelle, sonst Sidecar, sonst Fehler im Sidecar-Modus oder
|
||
plain Gewicht. `GpuHash::embedding` verwendet jetzt diese gemeinsame Auswahl.
|
||
|
||
192 tatsächliche dateibasierte Original-Receipts: BF16/F16, raw/Q4x160,
|
||
Prefetch aus/an, Kapazität0/3/4096 Zeilen, wiederholte/negative IDs, leer,
|
||
4096/4097 eindeutige IDs und weitere Decode-Gathers. Exakte Ausgabehashes,
|
||
LRU-Reihenfolge, Hits/Misses, Eintragszahl und Prefetch-Batches stimmen überein.
|
||
Original `gather_np` und Original `__call__` liefern dieselben192 Receipts.
|
||
Rust prüft jede Folge materialisiert-sofort, materialisiert-verzögert und über
|
||
den nicht gestagten Tabellenpfad mit lazy strided IDs (576 Vergleiche).
|
||
Ausgaben bleiben auch nach Freigabe von Mappings, Pool und Cache korrekt.
|
||
Zusätzlicher Routingtest prüft resident/plain Priorität und fehlenden Sidecar.
|
||
|
||
Keine Kernel-/Bridge-Änderung in diesem Abschnitt. Vorhandene Array/View-,
|
||
Readback- und Dequantisierungsbausteine werden wiederverwendet; Rust-Stdlib
|
||
und das vorhandene memmap2 genügen, kein neues Crate. Eintrittspunkte nehmen
|
||
bereits aufgelöste Tensor-Metadaten und Prefetch-/Cache-Einstellungen entgegen.
|
||
Safetensors-Attach, Umgebungs-/Modellpolicy, Stage-Lifecycle und vollständige
|
||
Modell-/Produktanbindung bleiben offen. Kein Vollmodell- oder IO-Performance-
|
||
Vergleich und keine2%-Abnahme; Port weiterhin `cfg(test)`.
|
||
|
||
Verifikation: reguläre Gesamt-Port-Suite103/103 in55,27s; Unretained-Command-
|
||
Buffer-Suite103/103 in54,87s. Release-Clippy, Format-/Diff- und Quellen-Check
|
||
bestehen. Fast-Synchronisation besteht mit5/5 NGram-Tests in2,25s.
|
||
Prüfbeleg: `local-eval-results/20260907-mtplx-port/ngram-sidecar-check.log`.
|
||
Diese Testlaufzeiten sind keine Modell-Performancewerte.
|
||
|
||
### Verbundener N-Gram-Stage-Lifecycle (2026-09-07)
|
||
|
||
`ngram_stage::Embedding` verbindet jetzt CPU-Hash, Sidecar, GPU-Graph und History
|
||
mit dem originalen `stage`/`__call__`-Ablauf. Die CPU-Hashkonstanten werden beim
|
||
ersten tatsächlichen Stage-Aufruf gelesen und behalten; EOS bleibt der aktuelle
|
||
Modellwert. Stage selbst schreibt die Cache-History nicht. Gespeichert werden
|
||
Shape, lazy Embedding, neue rohe History und vorherige History für QA.
|
||
|
||
Kein Sidecar, deaktivierte Stage-Option oder `_stage_disabled` kehren wie die
|
||
Referenz zurück, ohne eine vorhandene Vorbereitung zu löschen. Tatsächliche
|
||
Vorbereitungsfehler löschen sie und warnen nur einmal, deaktivieren spätere
|
||
Versuche jedoch nicht dauerhaft. `forward` verbraucht die Vorbereitung zuerst
|
||
und prüft nur B/S, nicht Tokenidentität. Passende Vorbereitung aktualisiert erst
|
||
nach erfolgreicher optionaler QA den Cache und den Consumed-Zähler. Bei stale
|
||
Shape folgen Bypassed-Zähler und normaler Graph-Fallback. Dieser zählt Graph-
|
||
Calls und schreibt die neue History **vor** dem Tabellenzugriff, auch wenn der
|
||
Zugriff danach fehlschlägt. Census-Ausgabe und Warnung folgen der Referenz.
|
||
|
||
Die optionale QA verwendet die originale F32-`allclose`-Kette mit Atol1e-8,
|
||
Rtol1e-5, NaN-false und expliziter ±Inf-Korrektur. Vorhandene Binary-/Unary-
|
||
Operatoren sind um LessEqual, LogicalAnd/Or/Not erweitert; die ursprünglichen
|
||
Kernels stammen unverändert aus der gepinnten Runtime-Metallib. Die boolesche
|
||
Gesamtreduktion übernimmt die Original-Single-/Two-Pass-Geometrie sowie die
|
||
strikte64MiB-Grenze und4-Byte-Mindestallokation. Dieser Reducer deckt den dichten
|
||
Bool-Ausgang der Stage-QA ab, nicht beliebige andere Reduktionspläne.
|
||
|
||
Der gemeinsame `ops::read_i64` folgt der NumPy-Konvertierung für Integer-Arrays:
|
||
einmal auswerten, dann Strides/Byte-Offsets auf dem gemeinsam gehaltenen Speicher
|
||
lesen und auf der CPU nach I64 konvertieren. Der Sidecar nutzt denselben Helfer
|
||
nach seinem originalen Flatten; Stage fügt kein GPU-Flatten oder Cast hinzu.
|
||
|
||
136 tatsächliche Original-Lifecycle-Receipts mit realer kleiner Sidecar-Datei:
|
||
raw/Q4, B1/2, 4-Token- und ausgewählte2048-Token-Prefills, jeweils Decode-Folge.
|
||
Normal, QA, Graph-only, Stage-disabled, stale Shape, andere Tokens gleicher
|
||
Shape, QA-Mismatch, übersprungene Vorbereitung bei deaktivierter Policy oder
|
||
fehlendem Sidecar, wiederholter Vorbereitungsfehler, kein Cache, längere History,
|
||
überschriebene Vorbereitung und Graphfehler sind enthalten. Ausgabe- und
|
||
History-Hashes, unveränderte History nach Stage, Consumed/Bypassed/Graph-Zähler,
|
||
Warnstatus, Pending-State und Fehler stimmen unmittelbar und bei verzögerter
|
||
Ausgabeauswertung überein (272 Vergleiche). Zusätzliche38 Original-Receipts
|
||
prüfen die QA-Sonderwerte und Reduktionsgrenzen einschließlich >64MiB.
|
||
|
||
Keine neue Metal-/Bridge-Änderung und keine neue Dependency. Policywerte werden
|
||
explizit übergeben; deren Auflösung, Safetensors-Attach, Loader und gesamte
|
||
Decoder-/Modell-/Produktanbindung bleiben offen. Der Port ist weiterhin
|
||
`cfg(test)`. Diese Belege sind keine UI-/Vollmodell-Performanceabnahme.
|
||
|
||
Verifikation: reguläre Port-Suite105/105 in56,27s und Unretained-Command-Buffer-
|
||
Suite105/105 in56,17s; Release-Clippy, Format-/Diff- und Quellen-Check bestehen.
|
||
Die sieben NGram-Tests bestehen auch mit Fast-Synchronisation in2,60s.
|
||
Prüfbeleg: `local-eval-results/20260907-mtplx-port/ngram-stage-check.log`.
|
||
Testlaufzeiten sind keine Modell-Performancewerte.
|
||
|
||
### Vollständiger PLE-Aufruf mit Safetensors-Ladeanbindung (2026-09-07)
|
||
|
||
`ple::Ple::forward` verbindet jetzt das tatsächliche NGramEmbedding mit der
|
||
Projektion, dem Gate und der dilatierten Faltung. Der äußere Stage-Prepass bleibt
|
||
außerhalb des Aufrufs. Cache-Slot3 wird durch den Lookup vor der Projektion
|
||
aktualisiert; Slot2 erst durch die Faltung. Die bisherigen numerischen
|
||
Projektionsoperatoren werden unverändert weiterverwendet.
|
||
|
||
144 tatsächliche Original-`PLELayer`-Receipts, ohne Ersatz-Embedding: BF16-Tabelle
|
||
und Q4-Tabelle, dichte und quantisierte Projektionen, Stage/QA/Graph/residenter
|
||
Pfad, B1/2, 7/2048 Prefill-Tokens und folgende Decode-Schritte einschließlich EOS,
|
||
kein/leerer/vorbelegter Cache. Die Referenz erzeugt kleine lokale Safetensors und
|
||
benutzt jetzt auch `attach_sidecar`/`attach_resident`; deren 144 Ergebnisse sind
|
||
unverändert zu den zuvor direkt angebundenen identischen Tabellen. Rust prüft
|
||
Ausgabe, Faltungszustand und rohe Token-History sofort und verzögert (288 Vergleiche).
|
||
|
||
`Table::attach_sidecar` übernimmt Metadaten-Defaults, Entfernen eines vorhandenen
|
||
Plain-Weights, Prefetch-/Hot-Cache-Konfiguration und die existierende mmap-LRU.
|
||
`attach_resident` materialisiert die ausgewählten Arrays vor Rückkehr, setzt bei
|
||
Erfolg `prefer_lazy=false` und löscht bei Fehler die residente Bindung. Stage-
|
||
Flags werden mit den originalen exakten Stringvergleichen gelesen.
|
||
|
||
Der erforderliche CPU-`Load` ist an den vorhandenen Graph/Scheduler/Allocator
|
||
angeschlossen: eigener Vier-Worker-Load-Pool, unabhängiger Vier-Worker-Pread-Pool,
|
||
32MiB-Batches, direkter Rest, CPU-Stream wartet auf das Load-Future. Header und
|
||
Payload werden über denselben gehaltenen Dateideskriptor gelesen. Worker halten
|
||
die Zielallokation bis zum Ende ihrer disjunkten Schreibaufträge. Die bestehende
|
||
Header-Validierung wird weiterverwendet, einschließlich ihrer Schutzgrenzen.
|
||
Zusätzlicher Loader-Test: leer/klein und unter/auf/über32MiB sowie >64MiB,
|
||
Payload erst nach Graphkonstruktion geschrieben, Datei vor Auswertung entfernt,
|
||
sofortige/asynchrone CPU→GPU-Folge, gemeinsame Allocator-Buchung und nachträglich
|
||
abgeschnittene Datei mit propagiertem Fehler. Keine großen Modellgewichte geladen.
|
||
|
||
Unveränderte Original-Metal-Quellen und Metallib; keine neue Dependency. Offen
|
||
bleiben die modellweite Residency-/Memory-Plan-Auswahl, Laden/Sanitize der übrigen
|
||
Gewichte, Decoder-/Gesamtmodell-/Produktanbindung und vollständige Messabnahme.
|
||
Der Port ist weiterhin `cfg(test)`; diese Nachweise schließen P10 oder das
|
||
2%-Gesamtziel nicht ab. Belege: `tests/fixtures/mtplx-ple-connected.jsonl` und
|
||
`local-eval-results/20260907-mtplx-port/ple-connected-load-check.log`.
|
||
|
||
Verifikation: Port-Suite107/107 in58,72s, abschließende Unretained-Command-
|
||
Buffer-Suite107/107 in59,00s; Release-Clippy, Format-/Diff- und Quellen-Check
|
||
bestehen. Der bestehende Safetensors-Boundary-Test besteht ebenfalls.
|
||
Die abschließenden Fast-Synchronisationschecks bestehen für PLE in2,76s und
|
||
den CPU-Loader in0,14s.
|
||
Die Testlaufzeiten sind keine Modell-Performancewerte.
|
||
|
||
### Verbundene Attention-Matrixpfade und Softmax (2026-09-07)
|
||
|
||
P08/P09: Der gemeinsame BF16-Matmul übernimmt jetzt auch führende Batchachsen,
|
||
gemeinsames Broadcasting mit zwei ausgesparten Matrixachsen, Stride-Collapse,
|
||
Broadcast-Batch-in-M-Collapse und ursprüngliche Transpose-/Copy-Vorbereitung.
|
||
Wide-GEMV, GEMV und NAX-GEMM erhalten die originalen Batchformen/-strides und
|
||
Dispatchbedingungen; Split-K bleibt auf Batch1 begrenzt. Die vorhandenen dichten
|
||
Projektionen benutzen denselben Operator. Nicht abgedeckt sind allgemeine
|
||
Dot-/Vektor-/N1-/Empty-Matmul-Fälle und andere Datentypen oder Geräte.
|
||
|
||
Der Last-Axis-Softmax ist ein eigener lazy Operator mit ursprünglicher
|
||
Contiguous-Prüfung, Donation oder Stride-erhaltender Allokation, notwendiger
|
||
Kopie sowie Block-/Looped-Auswahl an der4096-Grenze. BF16/F16 verwenden bei
|
||
`precise` die originale präzise Spezialisierung; F32 die normale. Der Speicher-
|
||
Reuse-Test synchronisiert nur seine Eingabevorbereitung: ein GPU-Event-Wait
|
||
garantiert weder hier noch in der Referenz, dass Completion-Callbacks ihre
|
||
Data-Referenzen schon freigegeben haben. Keine zusätzliche Synchronisation im
|
||
Laufzeitoperator oder Evaluator.
|
||
|
||
`attention::sdpa_fallback` verbindet die originalen BF16-Q-Skalierung,
|
||
GQA-Views, QK-Matmul, Bool-/additive Maskierung, präzisen Softmax und PV-Matmul.
|
||
Bool-false setzt hier BF16-finfo.min, nicht minus unendlich. Die Routenzuordnung
|
||
stammt aus MTPLXs gepinntem `fast.cpp` und Metal-SDPA: Qwen hat GQA12/D256;
|
||
S3–8 überschreitet die Fused-Vector-Bedingung S*GQA<=32. Größere D256-Prefills
|
||
mit expliziter Array-Maske benutzen ebenfalls diesen Fallback. Das ist eine
|
||
Quellzuordnung, keine gemessene Ursache für die Gesamt-MTP-Geschwindigkeit.
|
||
|
||
`attention::rows_gather` portiert getrennt den tatsächlichen MTPLX-Aufruf
|
||
`_qsa_rows_gather_attention`: zwei per-row Gathers über Cache-Achse2, gruppierte
|
||
Views ohne zwölfmaliges Materialisieren von K/V, BF16-QK **vor** F32-Cast und
|
||
Skalierung, minus-unendlich-Maskierung, F32-Softmax, BF16-Probabilities und PV.
|
||
Hier wäre ein Aufruf des obigen SDPA-Fallbacks numerisch und funktional falsch.
|
||
Der bereits vorhandene Tabellen-Gather wurde zum gemeinsamen Original-`take`
|
||
mit Gather/Transpose/Squeeze erweitert; NGram benutzt weiterhin dessen Achse0.
|
||
14 zusätzliche I32/BF16-Instanziierungen aus unverändertem Gather-Körper und
|
||
originalem JIT-Wrapper sind exportiert. Keine neue algorithmische Kernelversion,
|
||
Bridge oder Dependency; die ursprüngliche Runtime-Metallib bleibt unverändert.
|
||
|
||
Tatsächliche Original-Receipts (keine Performance-Mikrobenchmarks):
|
||
|
||
- 34 Batch-Matmul-Fälle, jeweils sofort/lazy:68 exakte Vergleiche. GQA-QK/PV,
|
||
B1/2, S1/3/8/16/64/2048, Cache-Strides, Transposes, Cross-Broadcast,
|
||
Batch-Collapse, nicht ausgerichtete Offsets und erforderliche Kopien.
|
||
- 48 Softmax-Fälle, jeweils mit/ohne gehaltene Eingabe:96 exakte Vergleiche.
|
||
BF16/F16/F32, `precise` aus/an,17/4097 Spalten, plain/swapped/strided/offset;
|
||
außerdem Stride- und kontrollierte Donation-Prüfung.
|
||
- 21 tatsächliche `mx.fast.scaled_dot_product_attention`-Aufrufe, sofort/lazy:
|
||
42 exakte Vergleiche. GQA12 oder gleiche Headzahl, bis2048 Prefillzeilen,
|
||
Cache-Backing-Offsets, keine/Bool/additive Maske, vollständig maskierte Zeile.
|
||
- 18 tatsächliche MTPLX-Rows-Gather-Aufrufe, sofort/lazy:36 exakte Vergleiche.
|
||
S1/3/8/16/64,8/17/1025/4097 gewählte Tokens, GQA12 oder gleiche Headzahl,
|
||
volle/versetzte/strided Cacheansichten; zwei originale Gathers und ein
|
||
F32-Softmax werden im Dispatch nachgewiesen.
|
||
|
||
**Weiter offen:** Full-SDPA-Auswahl und Bindung, vollständiges Attention-Modul mit
|
||
Projektionen/RoPE/Cache/Selektor, Decoder/Gesamtmodell und Produktionsumstellung.
|
||
Diese Operatoren bleiben `cfg(test)`; P08/P09/P16 und das2%-Ziel sind nicht
|
||
abgeschlossen. Belege: `tests/fixtures/mtplx-{dense-batch,softmax-graph,
|
||
sdpa-fallback,qsa-rows-attention}.jsonl` und
|
||
`local-eval-results/20260907-mtplx-port/attention-graphs-check.log`.
|
||
|
||
Verifikation: reguläre Port-Suite111/111 in61,32s, Unretained-Command-Buffer-
|
||
Suite111/111 in61,78s; die zwei verbundenen Attention-Tests bestehen zusätzlich
|
||
mit Fast-Synchronisation in0,96s. Release-Clippy, Format-/Diff- und Quellen-
|
||
Check bestehen. Diese Testlaufzeiten sind keine Modell-Performancewerte.
|
||
|
||
### Gekachelter portabler Prefill-Gather (2026-09-07)
|
||
|
||
`attention::prefill_gather` verbindet nun auch MTPLXs tatsächlichen
|
||
`_qsa_prefill_gather_attention`-Ablauf: pro Kachel absolute I32-Positionen,
|
||
Integer-Divide, vollständige ausgewählte Blöcke, kausaler Tail, Bool-Repeat,
|
||
Concatenate und sichere Nullindizes für ungültige Slots; danach der oben
|
||
geprüfte Rows-Gather auf den **vollen** KV-Backings. Keine Vollkontext-Kopie.
|
||
Das unbenutzte Python-Argument `total_tokens` benötigt keinen Rust-Operand;
|
||
die Auswahl adressiert wie im Original ausschließlich die übergebenen Backings.
|
||
|
||
Jede Kachel wird vor der nächsten ausgewertet. Bei nur einer Kachel ist das
|
||
Ergebnis schon ausgewertet; sonst bleibt ausschließlich die abschließende
|
||
Concatenate-Operation lazy. Die Python-Lokalen werden auch in Rust über die
|
||
Auswertung hinweg gehalten und erst in Referenzreihenfolge beim nächsten
|
||
Schleifendurchlauf ersetzt. Zusätzliche Schattenbindungen kurzlebiger Ausdrücke
|
||
und vorzeitig bewegte Concatenate-Eingaben wurden vermieden, weil sie Donation
|
||
und Data-Lebensdauer trotz passender Ausgabehashes verändern würden.
|
||
|
||
Die vorhandenen Arange- und Binary-Operatoren übernehmen Startwerte und
|
||
Integer-Floor-Divide: Letzteres verwendet wie `ops.cpp` den vorhandenen Divide-
|
||
Kernel ohne True-Divide-Promotion nach F32. Keine neue Metal-/Bridge- oder
|
||
Dependency-Änderung. Die restliche SDPA-/Attention-/Produktanbindung bleibt offen.
|
||
|
||
34 tatsächliche MTPLX-Receipts, jeweils mit lazy bzw. vorher ausgewerteten
|
||
Eingaben (68 Vergleiche): GQA12/gleiche Headzahl, S1/7/17/2048,
|
||
Kompressionsratio1/4/128, Position0/3/127/511, Kachelgrößen1/4/64/2048,
|
||
dichte I32- und versetzte/strided I64-Blockauswahl, ungültige negative IDs.
|
||
Der Referenzgenerator protokolliert die tatsächlichen `mx.eval`-Aufrufe samt
|
||
Tile-Shapes. Rust prüft deren Reihenfolge/Form im ausgewerteten Ausgabegraph,
|
||
zwei Gathers und einen F32-Softmax je Kachel sowie das exakte Ausgabehash.
|
||
Belege: `tests/fixtures/mtplx-qsa-prefill-gather.jsonl` und
|
||
`local-eval-results/20260907-mtplx-port/prefill-gather-check.log`.
|
||
Das ist weiterhin ein `cfg(test)`-Portnachweis, keine P08-/P16-Gesamtabnahme.
|
||
|
||
Verifikation: reguläre Port-Suite112/112 in62,24s, Unretained-Command-Buffer-
|
||
Suite112/112 in62,50s; alle drei Attention-Tests mit Fast-Synchronisation
|
||
in1,37s. Release-Clippy, Format-/Diff- und Quellen-Check bestehen; ursprüngliche
|
||
Metallib unverändert. Die Testlaufzeiten sind keine Modell-Performancewerte.
|
||
|
||
### Fused-Vector-SDPA und typisierte Metal-Konstanten (2026-09-07)
|
||
|
||
Der BF16/D256-Vector-SDPA ist jetzt als eigene Primitive verbunden. Die
|
||
gemeinsame `attention::scaled_dot_product`-Auswahl verwendet bei Qwens normalen
|
||
Aufrufen ohne bzw. mit expliziter Array-Maske den originalen Vector-Pfad für
|
||
S<=8, S<=T und S*GQA<=32; sonst den bereits geprüften D256-Fallback.
|
||
Der direkte Vector-Aufruf unterstützt zusätzlich die kausale Maske; bei S1
|
||
bleibt ihr Kernel-Flag wie im Original ausgeschaltet.
|
||
|
||
Die Bindung übernimmt Q-/KV-/Masken-Kopierbedingungen, Query-Donation,
|
||
Allokationsreihenfolge, Offset-/Stride-Bindings, Bool-/additive Maske und
|
||
Ein-/Zwei-Pass-Auswahl. Zwischenpuffer werden wie in der Referenz als
|
||
Encoder-Temporaries gehalten. Die drei unveränderten Originalkerne kommen
|
||
direkt aus derselben gepinnten Runtime-Metallib.
|
||
|
||
**Live korrigierte Hardwarezuordnung:** `mx.device_info` meldet für diesen
|
||
Apple M5 Max `applegpu_g17s` (Max), nicht `...d` (Ultra). Beim ersten Zwei-Pass-
|
||
Vergleich führte die falsche Zuordnung zu einem abweichenden Ausgabehash.
|
||
Für GQA12 ergibt die tatsächliche Max-Policy64 Blöcke bei T1024,128 bis8192,
|
||
256 bis32768,512 bis65536, danach1024; nicht die Ultra-Grenzen. Die Auswahl
|
||
verwendet jetzt den bereits vorhandenen Architektur-Bridge-Helfer gemeinsam
|
||
mit dem Scheduler und dem `MLX_METAL_GPU_ARCH`-Override. Alle originalen
|
||
Architekturzweige und `MLX_SDPA_BLOCKS` mit `atoi`-Semantik/32er-Aufrundung
|
||
sind abgebildet. Die zuvor falsche Annahme ist kein Modell-Performancebefund.
|
||
|
||
Der gemeinsame Bridge-Konstantentyp unterstützt jetzt Bool und echtes I32
|
||
statt ausschließlich Bool. Der Pipeline-Cache-Schlüssel enthält auch den Typ;
|
||
ungültige Typen, Bool-Werte und doppelte Indizes werden weiterhin verworfen.
|
||
Alle alten Bool-Aufrufe sind auf denselben neuen ABI-Typ umgestellt. Keine
|
||
neue parallele Dispatch-Bridge und keine Änderung der Kernelkörper.
|
||
|
||
48 tatsächliche Referenzfälle, jeweils lazy/vorbereitet (96 exakte Vergleiche):
|
||
B1/2, GQA12, S1/2, T17/33/1023/1024/16384/65536, transponierte Query bzw.
|
||
Copy-erforderliche Strides, versetzte KV-Backings, keine/Bool/additive/kausale
|
||
Maske. Der Dispatch prüft die tatsächlich erwartete Ein-/Zwei-Pass-Folge;
|
||
wechselnde Blockzahlen prüfen auch die Integer-Konstante und Cachetrennung.
|
||
Belege: `tests/fixtures/mtplx-sdpa-vector.jsonl` und
|
||
`local-eval-results/20260907-mtplx-port/vector-sdpa-check.log`.
|
||
|
||
Offen bleiben Full-SDPA einschließlich NAX-D256-Causal-Split, Sinks/andere
|
||
Datentypen und Head-Dimensionen außerhalb des installierten Qwen-Aufrufs,
|
||
vollständiges Attention-/Modulrouting, Modell-/Produktanbindung und P16.
|
||
Der kanonische Port bleibt `cfg(test)`; keine Vollmodell-Performanceabnahme.
|
||
|
||
Verifikation: reguläre Port-Suite113/113 in64,07s, Unretained-Command-Buffer-
|
||
Suite113/113 in63,75s; Fused-SDPA-Fast-Synchronisationscheck in1,25s.
|
||
Release-Clippy, Format-/Diff- und Quellen-Check bestehen; ursprüngliche
|
||
Metallib unverändert. Die Testlaufzeiten sind keine Modell-Performancewerte.
|
||
|
||
### Originale RoPE-Graphen und KV-Cache-Objektsemantik (2026-09-07)
|
||
|
||
`rope.rs` bildet `_rope_inv_freq_and_scaling`, `_rope_cos_sin`,
|
||
`_build_mrope_axes`, `_mrope_cos_sin` und `_apply_partial_rope` als gewöhnliche
|
||
Graphknoten ab. F32-Arange, Power, Sin/Cos und Typgrenzen verwenden dieselben
|
||
Runtime-Kerne, keine CPU-Frequenztabelle und keinen Ersatz-RoPE-Kernel.
|
||
Host-F64 bleibt auf die originalen Python-math-Schritte von statischem YaRN
|
||
beschränkt. Der Modell-Konfigurationsparser wird dadurch noch nicht ersetzt.
|
||
|
||
48 tatsächliche MTPLX-Referenzfälle, jeweils lazy/vorbereitet:96 exakte Vergleiche
|
||
für Frequenzen, Cosinus, Sinus und rotierte BF16-Ausgabe. Enthalten sind Rotary64
|
||
und256, partielle/vollständige Rotation, S1/7/64/2048, Positionen bis1048576,
|
||
Default/static YaRN einschließlich Amplituden-/mscale-Verhältnis und ungekürzter
|
||
Rampe sowie gleiche, interleaved und abschnittsweise M-RoPE-Achsen. Geslicte
|
||
Eingaben bleiben geslict. Die Referenz-Funktionen, nicht eine nachgebaute
|
||
Python-Formel, erzeugen `tests/fixtures/mtplx-rope-graph.jsonl`.
|
||
|
||
`cache.rs` portiert den von QSACache benutzten gewöhnlichen KVCache:
|
||
256er-Wachstum, Teilkapazitäts-Slice vor Wachstum, Full/Concatenate/SliceUpdate,
|
||
Trim und State-Roundtrip. `ops::slice` und `slice_update` teilen die ursprüngliche
|
||
Indexnormalisierung; Full und SliceUpdate verwenden die gemeinsamen Copy-Kerne
|
||
mit den originalen Scalar/Vector/General-/Donation-Regeln. GeneralGeneral-Copy
|
||
verwendet bei Ausschnitten weiterhin die Datengröße des vollständigen
|
||
Ziel-Arrays für Large-Dispatch und Encoder-Abhängigkeiten.
|
||
|
||
**Tatsächlich gefundene Besitzabweichung:** Eine reine `Array::clone`-Übernahme
|
||
bildete Python-Aliase auf `cache.keys`/`values` nicht ab. `mlx_set_item` überschreibt
|
||
den Descriptor des bestehenden Python-Arrayobjekts; gehaltene Python-Objektaliase
|
||
folgen dieser Änderung, bereits gebaute Graphknoten behalten dagegen ihren
|
||
ursprünglichen Descriptor. Der Rust-Cache trennt deshalb `Rc<RefCell<Array>>`
|
||
auf der Modellobjekt-Ebene von den unveränderten Array-Deskriptoren im Graphen.
|
||
Wachstum ersetzt das Objekt, SliceUpdate ersetzt nur seinen Descriptor. Das
|
||
ist weder eine zusätzliche GPU-Kopie noch ein geänderter Shader.
|
||
|
||
Die12 unveränderten tatsächlichen KVCache-Referenzfälle bestehen danach exakt:
|
||
Startlängen0/1/255/256/257/2048, mehrere Updates, Trim/Overwrite, Wiederherstellung
|
||
eines gehaltenen Zustands, vollständiger Trim und Wiederaufnahme; jeweils
|
||
sofortige bzw. verzögerte Auswertung. Geprüft werden sowohl logische Zustände
|
||
als auch vollständige Backings und Kapazitäten. Beim vollflächigen Ersatz kann
|
||
ein transponiertes Eingabelayout erhalten bleiben; der reine Test-Readback
|
||
wurde deshalb wie NumPy in logischer C-Reihenfolge exportiert. Die Referenzhashes
|
||
wurden nicht angepasst. Zusätzliche SliceUpdate-Prüfungen decken negative
|
||
Strides, leere Updates, Broadcast/Typkonversion und tatsächliche Donation ab.
|
||
|
||
Nur12 weitere originale F32/I32-Gather-Instanziierungen für M-RoPE;15 Custom-
|
||
Kernelkörper,35 Custom-Einstiege und22 Runtime-Quellblöcke sind weiterhin
|
||
unverändert zur Referenz. Der Export enthält jetzt170 Runtime-Einstiege;
|
||
die originale Runtime-Metallib bleibt bytegleich.
|
||
|
||
P08 bleibt offen: vollständiger Attention-Aufruf mit QKV-/Indexer-Fusion,
|
||
QSA-Arraygraph und dessen veränderlichen Cacheobjekten, sämtliche Auswahlzweige
|
||
und das nachfolgende Modellrouting sind noch nicht verbunden. Insbesondere
|
||
darf der bisherige Buffer-/Rc<QsaArray>-Pfad die hier aufgedeckte
|
||
Objekt-/Descriptor-Unterscheidung bei der Integration nicht verlieren.
|
||
Modell-/Produktanbindung und P16 sind weiterhin offen; der Port bleibt
|
||
`cfg(test)`. Keine Modell-Performance- oder Responsiveness-Abnahme aus diesen
|
||
Fixtures. Belege: `tests/fixtures/mtplx-kv-cache-graph.jsonl` und
|
||
`local-eval-results/20260907-mtplx-port/rope-cache-check.log`.
|
||
|
||
Verifikation: Port-Suite115/115 in64,78s, Unretained-Suite115/115 in64,77s;
|
||
zusätzliche Fast-Synchronisationschecks: RoPE1/1 in0,49s und KVCache1/1
|
||
in0,29s. Release-Clippy,
|
||
Format-/Diff- und Quellenprüfung bestehen. Die Laufzeiten bezeichnen
|
||
Modell-freie Prüfungen, keine Inferenz-Performance.
|
||
|
||
### Direkte Sparse-Attention-Consumer im Arraygraph (2026-09-07)
|
||
|
||
`sparse_attention.rs` bindet jetzt die unveränderten MTPLX-Körper
|
||
`qsa_flash_skip.py::_SRC` und `qsa_prefill_flash.py::_SOURCE` als jeweils eine
|
||
CustomKernel-Primitive ein. Decode übernimmt die originalen Flatten-Aufrufe,
|
||
Host-Parameter, GQA-Spezialisierung und256 Threads; Prefill verwendet32 Threads
|
||
pro (Query-Zeile, KV-Head) und die originalen Metal-4-MPP-Matmulfragmente.
|
||
Es gibt weder ein Gather-/Dense-Ersatzverfahren innerhalb dieser Primitive
|
||
noch einen stillen Retry nach einem Dispatchfehler.
|
||
|
||
Der Prefill-Aufruf übernimmt die statischen Unterstützungsbedingungen:
|
||
macOS>=26.2 und GPU-Generation17 (Telefonklasse18), aktiver GPU-Stream,
|
||
B1/H24/KV2/D256, BF16/F16, I32-/Bool-Selektionen[S,512], S>1, exakter Suffix,
|
||
Kapazitätsgrenze, maximal1048576 Tokens, mehr als512 vollständige Blöcke und
|
||
Host-Scale exakt0.0625. Die Plattformantwort ist wie `_mlx_nax_available`
|
||
gecached; die Bridge liefert nur Betriebssystem-/Gerätedaten, Rust entscheidet.
|
||
Die Scale-Prüfung erfolgt auf Host-F64, vor der originalen F32-Kernelkonversion.
|
||
|
||
Ausgabeallokation, Input-Bindings und Lebensdauer folgen CustomKernel:
|
||
Decode verwendet den vorhandenen `gdn::custom_evaluate` einschließlich
|
||
General-Copies nicht zeilenkontiguierlicher Argumente und Encoder-Temporaries.
|
||
Prefill übernimmt `ensure_row_contiguous=False` und bindet alle fünf
|
||
Input-Stridetabellen sowie Byte-Offsets direkt. Die kanonischen Tests prüfen
|
||
bei vorab ausgewerteten Eingaben ausdrücklich genau einen Prefill-Dispatch,
|
||
auch bei geslicten Features und Selektionstabellen; keine versteckte KV-Kopie.
|
||
|
||
50 tatsächliche MTPLX-Fälle, jeweils lazy/vorbereitet:100 exakte Vergleiche.
|
||
Decode: GQA12/1, nur Tail bzw.512/17 ausgewählte Blöcke, T3/4099/2052.
|
||
Prefill: S2/8/137/2048, Start2050/8191/32767/2048; BF16/F16, transponierte
|
||
Query, ungerader Elementoffset, nichtkontiguierliche Features, Selektion mit
|
||
Strides, ungültige IDs und Gültigkeitslücken bis Slot511. Die Referenz ruft
|
||
die beiden tatsächlichen Sparse-Kerne direkt auf, keine nachgebaute Formel.
|
||
Belege: `tests/fixtures/mtplx-sparse-attention.jsonl` und
|
||
`local-eval-results/20260907-mtplx-port/sparse-attention-check.log`.
|
||
|
||
Der Quellenexport umfasst nun17 unveränderte Kernelkörper und41 Custom-
|
||
Einstiege;22 Runtime-Quellblöcke/170 Runtime-Einstiege und die originale
|
||
Runtime-Metallib bleiben unverändert. Die zusätzlichen instanziierten
|
||
Decode-Varianten sind BF16/F16 mit GQA1/12; andere GQA-/Dtype-Spezialisierungen
|
||
sind damit nicht als abgedeckt behauptet.
|
||
|
||
P08 ist weiterhin offen: Der vollständige Attention-Aufruf muss QKV-/Indexer-
|
||
Fusion, Norm/RoPE, KV-Update, Vision-Bypass und alle originalen Auswahlzweige
|
||
zusammenführen. Besonders die requestbezogene Prefill-Phase und die
|
||
32K-Crossover-Policy dürfen nicht durch bloßes `prefill_supported` ersetzt
|
||
werden. Der kanonische QSA-Indexer-/Cachegraph, Modell- und Produktanbindung
|
||
sowie P16 fehlen weiterhin. Keine Vollmodell-Performance-Abnahme aus diesen
|
||
Tests und kein produktiver Verhaltenswechsel.
|
||
|
||
Verifikation: gemeinsamer Release-Lauf116/116 in64,16s vor der abschließenden
|
||
Plattform-Cache-/Host-F64-Präzisierung. Auf dem finalen Code besteht der gesamte
|
||
Unretained-Lauf116/116 in65,21s; der fokussierte Normal- und FastSync-Lauf
|
||
jeweils1/1 in1,75s. Release-Test-Clippy, Format-/Diff- und Quellenprüfung
|
||
bestehen. Diese Zeiten sind Prüfzeiten ohne Modell, keine Performance-Abnahme.
|
||
|
||
### Vollständige QSA-Blockmaskenrekonstruktion (2026-09-07)
|
||
|
||
`attention::blocks_to_dense_mask` übernimmt den tatsächlichen
|
||
`_qsa_blocks_to_dense_mask`-Graph: zeilenweise vollständige Blöcke, originale
|
||
I32-Vergleiche/Bool-Bitoperationen, ungültige IDs auf eine zusätzliche
|
||
Sentinel-Spalte, `put_along_axis`, Sentinel-Slice, Repeat, optionale Null-Padding-
|
||
Spalten, Tail und abschließende Kausalmaske. Dies ist der originale Consumer-
|
||
Fallback, kein Ersatz für den zuvor portierten direkten Flash-Prefill-Zweig.
|
||
|
||
Die gemeinsame ScatterAxis-Primitive übernimmt Cast/Squeeze/Broadcast-Reihenfolge,
|
||
Scalar-/Vector-/General-Quellkopie, Vector-Donation, leere Updates, Achsen- und
|
||
Stride-Bindings sowie die originale Dispatch-Geometrie. Bool/I64-QSA verwendet
|
||
jetzt alle vier Update-/Index-Layoutkombinationen und Int-/Int64-Adressierung
|
||
des unveränderten Runtime-Kernels:22 unveränderte Runtime-Quellblöcke und176
|
||
Runtime-Einstiege;17 Custom-Körper und41 Custom-Einstiege bleiben unverändert.
|
||
Keine selbstgeschriebene Scatter-/Masken-Metal-Implementierung.
|
||
|
||
44 direkte MTPLX-Maskenfälle und64 direkte `put_along_axis`-Fälle werden lazy
|
||
und vorab ausgewertet verglichen:216 exakte F32-Readback-Hashes. Masken decken
|
||
S0/1/2/5/8/9/137/2048, Kontext bis32904, Ratio1/4/7, leere Selektionen,
|
||
gültige/ungültige/duplizierte IDs, vollständig gesperrte Blöcke und geslicte
|
||
Selektionstabellen ab. Scatter prüft Rank1/2/3, Achsen0/1, skalare/vollständige
|
||
Updates, negative Indizes und skalare/Offset-/Strided-Quellen. Zusätzlich:
|
||
führende Singleton-Updates, Achsenfehler, leere Updates und nachgewiesene
|
||
Vector-Donation ohne zusätzlichen Kopierdispatch.
|
||
|
||
Belege: `tests/fixtures/mtplx-qsa-dense-mask.jsonl`,
|
||
`tests/fixtures/mtplx-scatter-axis.jsonl` und
|
||
`local-eval-results/20260907-mtplx-port/qsa-mask-scatter-check.log`.
|
||
Gemeinsame Release-Verifikation:118/118 normal in68,82s und118/118 mit
|
||
unretained Command Buffers in68,04s. Release-Test-Clippy, Format-/Diff- und
|
||
Quellenprüfung bestehen. Das sind modellfreie Prüfzeiten, keine Inferenzdaten.
|
||
P08 bleibt bis zum vollständigen
|
||
QSA-Indexer-/QSACache-/Attention-Aufruf und der Produktintegration offen.
|
||
Keine Modellmessung, kein Abweichen vom vollständigen Port wegen Laufzeiten.
|
||
|
||
### Positionaler QSACache im kanonischen Arraygraph (2026-09-07)
|
||
|
||
`cache::QsaCache` verwendet den bereits portierten KVCache und dessen
|
||
`ArrayObject`-Semantik. Raw-/Pooled-Schreibbereiche liegen an absoluten
|
||
Positionen; Vergrößerung erfolgt geometrisch mit256er-Ausrichtung, nicht
|
||
durch Anhängen oder Vollkopien je Dekodeschritt. Originale Full/SliceUpdate/
|
||
AsType-/Transpose-/View-Primitiven bilden die Mutationen ab; keine neue
|
||
Puffer-COW-Implementierung neben dem Arraygraph.
|
||
|
||
Der FP32-Spiegel wird beim ersten Zugriff aus dem vollständigen vorhandenen
|
||
Pooled-Inhalt aufgebaut, bei Schreibzugriffen inkrementell aktualisiert und
|
||
nach Session-Restore verworfen. Eine Reservierung vergrößert in MTPLX den
|
||
Spiegel ausdrücklich nicht sofort; diese Reihenfolge bleibt erhalten.
|
||
Die originale `nbytes`-Eigenschaft zählt KV/Raw/Pooled, aber nicht den
|
||
abgeleiteten Spiegel. Dies wird unverändert übernommen, nicht als Messung
|
||
des gesamten realen GPU-Speicherverbrauchs ausgegeben.
|
||
|
||
`QSAIndexer::_ensure_compiled_backings` ist mit dem Cache verbunden: Originale
|
||
Zweierpotenz-Buckets, ausstehende Reservierungen und der physisch notwendige
|
||
ceil(S/ratio)-Pooling-Bereich werden vor der Graphausführung berücksichtigt.
|
||
Session-Restore behält die vier Arrayobjekte, setzt Reservierungen auf die
|
||
restaurierten Ausdehnungen zurück und rekonstruiert den Spiegel erst bei Bedarf.
|
||
|
||
16 direkt ausgeführte MTPLX-Lifecycle-Sequenzen prüfen1896 exakte Tensor-Hashes
|
||
sowie Offsets, Kapazitäten, Reservierungen und `nbytes` nach jedem Schritt:
|
||
BF16/F16/F32, Ratio1/4/7, Indexbreite17/32/128, Initiallängen0/1/255/256/257/1025,
|
||
sofortige/verzögerte Auswertung, gehaltene Arrayobjekte und geslicte Zustände,
|
||
Rollback, Überschreiben, Restore, Mirror-Views und1025-Token-Replay-Reservierung.
|
||
Belege: `tests/fixtures/mtplx-qsa-cache-graph.jsonl` und
|
||
`local-eval-results/20260907-mtplx-port/qsa-cache-graph-check.log`.
|
||
|
||
Die erste gebündelte Referenzausgabe war abgeschnitten und enthielt dadurch
|
||
eine syntaktisch gültige, aber vermischte Zeile. Alle aus abgeschnittenen
|
||
Ausgaben übernommenen Zeilen wurden verworfen und einzeln aus unveränderten
|
||
Originalaufrufen neu erfasst. Keine Anpassung von Implementierung oder
|
||
Referenzhashes an einen fehlgeschlagenen Vergleich.
|
||
|
||
Verifikation:119/119 gemeinsame Release-Tests normal in67,06s und119/119
|
||
unretained in67,38s; fokussierter FastSync-Lauf1/1 in1,00s. Release-Test-Clippy,
|
||
Format-/Diff- und unveränderte Quellenprüfung bestehen. Das sind modellfreie
|
||
Prüfzeiten, keine Inferenz-Performance-Werte.
|
||
|
||
P08 bleibt offen: Die vollständige kanonische Indexer-Ausführung inklusive
|
||
kompiliertem Graphbank-Pfad und das Attention-Modul müssen diese Cache-Objekte
|
||
noch nutzen. Der Port bleibt `cfg(test)`; keine Produkt-/Performance-Parität.
|
||
|
||
### Parametrisierte QSA-Query-/Pooling-Primitiven (2026-09-07)
|
||
|
||
`qsa_prepare.rs` übernimmt die öffentlichen Query-/Pooling-Aufrufe aus
|
||
`qsa_indexer_prepare.py` einschließlich statischer Eignungsprüfung,
|
||
BF16/F16/F32, Kopfbreiten bis128, geradem partiellem/vollem RoPE, beliebigem
|
||
positivem Pooling-Verhältnis, RMS-Epsilon und positiver endlicher
|
||
Attention-Skalierung. Host-I32-Positionen werden zu einer Array-Konstante;
|
||
Tensor-Positionen werden nur auf ein I32-Element validiert und umgeformt,
|
||
ohne `.item()` oder Synchronisation.
|
||
|
||
Die Spezialisierung verwendet die bereits hashgeprüften Originalkörper
|
||
`_prepare_queries_kernel` und `_pool_keys_kernel` aus dem vorhandenen Export.
|
||
Nur Header-Konstanten, Datentyp-Instanziierung und Exportname ändern sich;
|
||
die Arithmetik bleibt bytegleich. Der vorhandene native CustomKernel-Compiler
|
||
verwendet Safe-Math und die originale Sprachversion. Der Pipeline-Schlüssel
|
||
enthält auch EPS-/Skalierungsbits, damit unterschiedliche Konfigurationen
|
||
nicht versehentlich dieselbe Kompilierung verwenden.
|
||
|
||
Originale Ausgabeallokation vor Kompilierung, vier Array-Inputs, drei
|
||
Stride-Tabellen, Byte-Offsets und Datenlebensdauer bleiben erhalten.
|
||
`ensure_row_contiguous=False`: keine impliziten General-Copies. Query verwendet
|
||
32 Threads je Zeile/Kopf, Pooling32 je Block; kein Fehler-Retry auf Eager.
|
||
|
||
72 direkte MTPLX-Fälle mit je zwei Ausgaben werden lazy/vorbereitet geprüft:
|
||
288 exakte Tensorvergleiche. S1/3/7/137/2048, H1/2/3/4/7, D2/17/64/128,
|
||
RoPE2/16/32/64/128, Ratio1/3/4/7/8, negative und große Positionen,
|
||
Plain-/Offset-/Strided-/Broadcast-Inputs, dynamische GPU-Positionen sowie
|
||
unterschiedliche EPS bei sonst gleichen Parametern. Vorbereitete Inputs
|
||
erzeugen genau zwei Dispatches; die dynamischen Kernelkörper werden zusätzlich
|
||
byteweise mit den geprüften Exportkörpern verglichen.
|
||
Belege: `tests/fixtures/mtplx-qsa-prepare-graph.jsonl` und
|
||
`local-eval-results/20260907-mtplx-port/qsa-prepare-graph-check.log`.
|
||
Verifikation:120/120 gemeinsame Release-Tests normal in67,95s und120/120
|
||
unretained in68,37s; fokussierter FastSync-Lauf1/1 in0,82s. Release-Test-Clippy,
|
||
Format-/Diff- und Quellenprüfung bestehen. Das sind modellfreie Prüfzeiten,
|
||
keine Inferenz-Performance-Werte.
|
||
|
||
P08 bleibt offen: Diese Primitiven müssen mit dem vollständigen kanonischen
|
||
QSAIndexer einschließlich Eager-Orakel und kompiliertem Graphbank-Pfad sowie
|
||
mit Attention/Modell/Produktausführung verbunden werden. Weiterhin `cfg(test)`;
|
||
keine Vollmodellmessung oder Rücknahme aufgrund isolierter Laufzeiten.
|
||
|
||
### Gemeinsame Float-Summen und QSA-Mittelwert (2026-09-07)
|
||
|
||
`reduce.rs` übernimmt für BF16/F16/F32 die gemeinsame Sum-Factory und den
|
||
Reduktionsplan aus `ops.cpp`, `backend/common/reduce.cpp` und
|
||
`backend/metal/reduce.cpp` der gepinnten MTPLX-Laufzeit. Keine neuen Metal-
|
||
Körper: sämtliche Reduktionskernel stammen aus der unveränderten originalen
|
||
Metallib. Die drei bisherigen speziellen GDN-/PLE-/HC-Summen wurden entfernt;
|
||
ihre kanonischen Modellgraphen verwenden jetzt dieselbe Sum-Operation.
|
||
|
||
Enthalten sind sortierte/validierte Achsen, `keepdims`/Squeeze, No-op-Achsen,
|
||
leere Reduktionen mit dem originalen Init-Kernel, zusammengefasste reduzierte
|
||
Achsen, Stride-Sortierung, General-Copy nur beim originalen GeneralReduce-Plan,
|
||
Row-Small/Simple/Looped sowie Col-Small/Looped/LongColumn/TwoPass und AllReduce
|
||
mit originalen Schwellen, Zwischenpuffern, Argumentlayouts und Threadgeometrien.
|
||
Shape-Collapse und zweidimensionale Grid-Faktorisierung werden mit den bereits
|
||
portierten Views geteilt. Der Runtime-Identitätszweig bewahrt beim Vector-Copy
|
||
auch kompakte Broadcast-Speicherung; er darf daraus keinen Full-Fill machen.
|
||
|
||
`mean_f32` bildet genau den im QSA-Eager-Pooling benötigten Ausdruck ab:
|
||
expliziter F32-Input, Sum und anschließendes Multiply mit einem aus Host-F64
|
||
auf F32 gerundeten Kehrwert. Kein Divide, eigener Mittelwertkernel oder
|
||
Zusammenziehen mehrerer Primitiven. Dies ist kein vollständiger allgemeiner
|
||
Mean-/Integer-Reduce-/Shapeless-Compiler-Port.
|
||
|
||
232 tatsächliche MTPLX-Referenzfälle werden lazy und mit vorbereiteten Eingaben
|
||
geprüft:928 bitgleiche Tensorvergleiche für Sum und F32-Mean. Enthalten sind
|
||
alle neun Kernelfamilien, ein-/mehrdimensionale Reduktionen, zwei und fünf
|
||
Kernel-Reduktionsdimensionen, Plain-/Offset-/Transpose-/Strided-/Reverse-/
|
||
Broadcast-Layouts, No-ops und leere Achsen. Grenzfälle decken insbesondere
|
||
31/32 Outputzeilen, Breiten512/513/1024/1025, Spaltenlängen31/32/256/257/
|
||
1023/1024/32768 sowie AllReduce4096/4097 und die64-MiB-Schwelle ab.
|
||
Zusätzlich werden konkrete Kernelnamen, Dispatch-/Threadgroup-Geometrien und
|
||
Threads-vs-Threadgroups an14 ausgewählten Grenzen geprüft. Ein separater
|
||
Runtime-Identitätscheck prüft physische Broadcast-Datengröße und Strides.
|
||
|
||
Belege: `tests/fixtures/mtplx-sum-graph.jsonl` (SHA256
|
||
`d0963276ff75305d7903b91cb34f8d0db2472330fba444199f70dfd7fbebcdd1`)
|
||
und `local-eval-results/20260907-mtplx-port/sum-graph-check.log`.
|
||
Gemeinsame Release-Suite:121/121 normal in69,63s und121/121 unretained in71,85s.
|
||
Nach der abschließenden Korrektur des Runtime-Identitätszweigs bestehen auch
|
||
die fokussierten Checks normal in2,39s, unretained in2,27s und FastSync in2,32s,
|
||
jeweils1/1 einschließlich aller928 Tensorvergleiche und Dispatch-Verträge.
|
||
Die vollständigen Suites liefen vor dieser letzten Identitätskorrektur.
|
||
Release-Test-Clippy, Format-/Diff- und unveränderte Quellenprüfung bestehen.
|
||
Prüfzeiten sind keine Modell-Performance-Werte.
|
||
|
||
P08 bleibt offen: insbesondere Sort/Argpartition für den Eager-Indexer,
|
||
dessen vollständige Auswahl-/Cache-/Graphbank-Kette,
|
||
Attention und produktive Modellintegration. Der Port bleibt `cfg(test)`.
|
||
Keine Aussage zur UI-Responsivität oder erreichten Performance-Parität;
|
||
keine Rücknahme aufgrund isolierter Laufzeiten.
|
||
|
||
### Kanonischer Float-Matmul und verbundener QSA-Score-Pfad (2026-09-07)
|
||
|
||
`dense.rs` verwendet jetzt eine gemeinsame Matmul-Factory für BF16/F16/F32,
|
||
Typ-Promotion, Vektoren, Matrix-/Vektorprodukte, Broadcast-Batches, statisches
|
||
Flatten/Unflatten und leere Matrizen. `nn.Linear` delegiert direkt an diese
|
||
Factory; seine duplizierten Expand-/Reshape-/Squeeze-Pfade wurden entfernt.
|
||
Alle bisherigen Attention- und HC-Aufrufer verwenden dieselbe Operation.
|
||
|
||
Der Metal-Backendport für den M5 Max übernimmt aus dem gepinnten
|
||
`backend/metal/matmul.cpp` beide GEMV-Richtungen, DotProduct mit F32-Partials,
|
||
originalem AllReduce und Scalar-Copy, F16/BF16-GEMV-Wide (ausdrücklich nicht für
|
||
F32), NAX/SIMD-Split-K und reguläre NAX-/SIMD-GEMM-Auswahl. Kernel, Partitions-
|
||
größen, Schwellen, Strides, Byte-Offsets, Zwischenpuffer, Function Constants
|
||
und Dispatch-Geometrien stammen aus dieser Referenz. Keine neuen Metal-Körper.
|
||
`MLX_ENABLE_TF32` wird wie `env::enable_tf32` einmal mit `atoi` gelesen, Default1;
|
||
TF32-off wählt die originalen SIMD-F32-Kernel, Vektoren bleiben bei GEMV.
|
||
Dies erweitert den M5-Max-Port, nicht Complex-Matmul oder den Shapeless-Compiler.
|
||
|
||
`attention::qsa_scores` verbindet den ursprünglichen Ausdruck aus
|
||
`qsa_indexer_prefill_scores`/`QSAIndexer._select_eager`: F32-Query-Cast bei
|
||
bereits F32-Poolingoperand gemäß Originalvertrag, Matmul, ReLU je Kopf, Sum über Achse2,
|
||
Division durch Host-F64-sqrt(D), auf F32 gerundet, und Auswahl von Batch0.
|
||
Der zuvor portierte gemeinsame Reduktionspfad wird direkt verwendet.
|
||
|
||
228 zusätzliche Original-Matmul-Fälle sind mit TF32 on/off erfasst:
|
||
BF16/F16/F32, gemischte Eingabetypen, alle vier Transponierungsrichtungen,
|
||
Dot-/linke/rechte Vektoren, Kreuz-Broadcasts, Copy-/Offset-/Collapse-/Flatten-
|
||
Layouts, ungerade K, Split-K-Grenzen und leere Matrizen. Lazy/vorbereitete
|
||
Ausführung ergibt456 bitgenaue Tensorvergleiche über beide TF32-Prozesse.
|
||
Zusätzlich bestehen384 vorhandene direkte MTPLX-QSA-Score-Receipts jetzt auch
|
||
durch den kanonischen Arraygraph, einschließlich S2048, N1/7/16/32/40/63/64/
|
||
128/129/513 und acht Speicherlayouts. Zusammen840 neue Matrix-/Score-
|
||
Vergleiche; die bisherigen68 BF16-Attention-Vergleiche bleiben erhalten.
|
||
Konkrete F32-Kernelnamen und Threadgeometrien für GEMV, beide Split-K-Varianten
|
||
und gebatchte reguläre GEMM werden zusätzlich geprüft.
|
||
|
||
Beim Erfassen der Referenz stürzte `numpy.asarray` auf einem leeren F32-
|
||
Matmul-Ergebnis ab. Ein unabhängiger Minimalaufruf bestätigt: `mx.eval`
|
||
schließt ab; erst das Auslesen der Null-Datenadresse stürzt ab. Der gemeinsame
|
||
Fixture-Emitter hasht daher bei `size==0` die leere Bytefolge nach erfolgreichem
|
||
Eval, ohne NumPy-Lesen. Keine Änderung an Referenzmodell/-runtime, Berechnung
|
||
oder nichtleeren Hashes. Die abgebrochene F32-Capture-Gruppe wurde vollständig
|
||
neu erfasst. Form und Abschluss leerer Ergebnisse bleiben geprüft.
|
||
|
||
Belege: `tests/fixtures/mtplx-dense-float.jsonl` (SHA256
|
||
`24ac569b5fe6f4dc6757cb21870bc3d9ae0fd2c7eff690240284b61d0ce76037`),
|
||
vorhandene `qsa_f32_score_*`-Receipts und
|
||
`local-eval-results/20260907-mtplx-port/dense-float-graph-check.log`.
|
||
|
||
Verifikation des finalen Standes:123/123 gemeinsame Release-Tests mit
|
||
Default-TF32 in72,44s;123/123 mit `MLX_ENABLE_TF32=0` und unretained Command
|
||
Buffers in72,34s; fokussierte Matrix-/QSA-Gruppe3/3 mit TF32 und FastSync
|
||
in2,00s. Release-Test-Clippy, Format-/Diff- und unveränderte Quellenprüfung
|
||
bestehen. Diese Prüfzeiten sind keine Inferenz-Geschwindigkeitswerte.
|
||
|
||
P08 blieb an diesem Messstand offen: kanonisches Sort/Argpartition, fehlende Indexier-Dtypes,
|
||
vollständige Indexer-Auswahl/Cache-/Compiled-Graphbank und Attention-Aufruf.
|
||
Auch Modell-/Produktausführung und abschließende Performance-Abnahme bleiben
|
||
offen. Der Port ist weiterhin `cfg(test)`; kein Vollmodell-Speed oder UI-
|
||
Responsiveness-Nachweis wird aus diesen modellfreien Prüfungen abgeleitet.
|
||
|
||
### Gemeinsames kanonisches Sort/Argpartition (2026-09-07)
|
||
|
||
`sort.rs` portiert die vier ursprünglichen Factories Sort, ArgSort, Partition
|
||
und ArgPartition und deren gemeinsamen Metal-Merge-Sort. Partition bleibt wie
|
||
in der Referenz ein vollständiger Sort; `kth` wird normalisiert, geprüft und
|
||
im Graph-Primitiv erhalten. Negative Achsen, Flatten bei fehlender Achse,
|
||
BF16/F16/F32/I32/U32/I64/U64, Layout-/Offset-Auswertung, der originale
|
||
Contiguous-/Noncontiguous-Dispatch, Blockgrößengrenzen einschließlich der
|
||
64-Bit-Ausnahme, Ping-Pong-Partition/Merge und abschließende Vector-/General-
|
||
Kopie verwenden den ursprünglichen Ablauf und unveränderte Metallib-Kernel.
|
||
Die Kopie benutzt die vorhandenen gemeinsamen Copy-Funktionen.
|
||
|
||
Der bisherige Buffer-Argsort für Router, MoE und QSA ist auf einen Adapter
|
||
mit denselben Form-/Pufferprüfungen reduziert; seine duplizierte Sortier- und
|
||
Kopierschleife wurde entfernt. Adapter und kanonischer Arraygraph gehen durch
|
||
dieselbe Backendfunktion. Zurückgegebene Zwischenpuffer bleiben für vorhandene
|
||
Buffer-Aufrufer bis zum GPU-Abschluss erhalten; im Arraygraph werden sie vom
|
||
Encoder gehalten.
|
||
|
||
161 zusätzliche Original-Referenzfälle (23 Profile × sieben Dtypes) prüfen
|
||
jeweils alle vier Operationen, verzögert und mit vorbereiteten Eingaben:
|
||
1.288 bitgenaue Tensorvergleiche. Enthalten sind gleiche Sortierschlüssel,
|
||
negative Werte, beliebige Achsen, Transponierung, Schritt-/negative Strides,
|
||
Broadcast, Offset, Flatten sowie Ein-/Mehrblockgrenzen bis8.193 Elemente.
|
||
Für die Grenzprofile werden zusätzlich konkrete Kernel-Namen, Blockgrößen,
|
||
Grids und Anzahl der Merge-/Partition-Runden geprüft. Ungültiges `kth` wird
|
||
vor dem Dispatch abgewiesen. Leere Sortierachsen sind kein abgenommener Fall:
|
||
Der Originalbackend teilt durch die Achsengröße; der Rust-Port liefert bei0
|
||
einen Fehler statt einen erfolgreichen Sort vorzutäuschen.
|
||
|
||
Beleg: `tests/fixtures/mtplx-sort-graph.jsonl`, SHA256
|
||
`a655665801dae88d9186faa60c4678bbf5af08b8b4797e95d836d5ab51cbd2b8`.
|
||
Erfassung direkt mit `sort_graph_fixtures` im gepinnten MTPLX-0.32.2-Prozess,
|
||
ohne Modellgewichte oder Downloads. Der erste gemeinsame Release-Durchlauf
|
||
besteht124/124 Tests in73,96s, einschließlich bestehender Router-, MoE- und
|
||
QSA-Aufrufer. Dieser Lauf enthält die Ergebnisprüfungen; die anschließend
|
||
ergänzten Dispatch-Verträge werden im abschließenden Lauf geprüft.
|
||
|
||
Der finale gemeinsame Durchlauf mit unretained Command Buffers besteht
|
||
124/124 Tests in73,13s, einschließlich der Dispatch-Verträge. Die fokussierte
|
||
FastSync-Prüfung besteht ebenfalls. Release-Test-Clippy, Format-/Diff-Prüfung
|
||
und unveränderte Quellenprüfung bestehen. Vollständiges Prüfprotokoll:
|
||
`local-eval-results/20260907-mtplx-port/sort-graph-check.log`.
|
||
Diese Prüfzeiten sind keine Modell-Performancewerte.
|
||
|
||
P08 bleibt offen: fehlende Indexier-Dtypes, vollständige kanonische
|
||
Indexer-Auswahl/Cache-/Compiled-Graphbank und Attention-Aufruf. Der gesamte
|
||
kanonische Port ist weiterhin `cfg(test)`; Produktmigration, vollständige
|
||
Funktionsparität, UI-Responsivität und die2%-Performance-Abnahme sind damit
|
||
ausdrücklich nicht abgeschlossen.
|
||
|
||
### Verbundene kanonische Eager-QSA-Auswahl (2026-09-07)
|
||
|
||
`attention::select_eager` verbindet nun den zuvor portierten F32-Scoregraph
|
||
und Sort/Argpartition mit dem tatsächlichen `QSAIndexer._select_eager`-
|
||
Ablauf, dem kanonischen QSACache und allen fünf Ausgabeformen. Der gepoolte
|
||
F32-Spiegel kommt direkt aus `QsaCache::pooled_f32_view`, einschließlich
|
||
seiner gepaddeten, nicht-kontiguierlichen Ansicht. Causal-Blockgrenzen,
|
||
Minus-Unendlich-Maskierung und F32-Tie-Break werden vor Argpartition wie
|
||
im Original berechnet; die gewählten Indices bleiben eine Array-Ansicht.
|
||
|
||
Die Rückgabereihenfolge ist unverändert: chronologische Prefill-Blöcke
|
||
mit Gather-Validität und Nullersatz; Flash-Decode mit Host-Tailgrenze;
|
||
Decode-Gather mit vollständigen Blocktokens plus Rest; Rows-Gather mit
|
||
gepaddeten Tailtokens und Gültigkeit; sonst vollständige kausale Maske.
|
||
Flash gewinnt bei gleichzeitiger Aktivierung vor Decode-Gather. Gekachelte
|
||
Scores schließen Rows-Gather wie im Original aus. Jede Kachel führt vor
|
||
dem Anhängen der Indices ein echtes synchrones Eval aus; kein Ersatz durch
|
||
Flush oder Async-Eval. Ungekachelte Auswahl und ungenutzte dichte Zwischen-
|
||
ausdrücke bleiben verzögert. Die bestehenden Optionsfelder enthalten die
|
||
vom Aufrufer aufgelöste Phase-/Positions-/Umgebungspolitik, nicht eine neue
|
||
Heuristik allein anhand der Zeilenzahl.
|
||
|
||
Bool/I64-GatherAxis verwendet jetzt alle vorhandenen Stride-/Adressierungs-
|
||
varianten des Originaltemplates. Sieben zusätzliche Instanziierungen, keine
|
||
geänderten Kernelkörper. Der Quellenabgleich bestätigt weiterhin17 Original-
|
||
Metal-Körper und22 Runtime-Einheiten; die Runtime-Einstiegspunkte steigen
|
||
von176 auf183. Alle vier Bool/I64-Row-Contiguity-Kombinationen einschließlich
|
||
negativer Indices und negativer Source-/Index-Strides haben einen ausführbaren
|
||
Check. Der gemeinsame `ops::repeat` übernimmt Expand/Broadcast/Reshape aus
|
||
`ops.cpp` einschließlich Null-/Eins-/Fehlerfällen; auch die bestehende
|
||
Blockmaskenrekonstruktion verwendet ihn statt eines duplizierten Ausdrucks.
|
||
|
||
Die ursprünglichen Host-Lane-Zähler sind ebenfalls angeschlossen:
|
||
`eager_selector`, `decode_flash_skip`, `decode_gather` und
|
||
`decode_dense_mask`; Rows-Gather zählt wie das Original keinen dieser
|
||
Zähler. Snapshot und optionaler Bericht bei Prozessende über
|
||
`MTPLX_QSA_PREFILL_DEBUG` bleiben von GPU-Abschlussmessungen getrennt.
|
||
|
||
144 neue Receipts rufen direkt den gepinnten MTPLX-`QSAIndexer._select_eager`
|
||
mit dem originalen QSACache auf:24 Profile × BF16/F16/F32 × TF32 on/off.
|
||
Lazy und vorbereitete Rust-Ausführung ergeben420 bitgenaue Tensorvergleiche.
|
||
Abgedeckt sind alle Ausgabeformen, echte Kachelgrenzen und deren
|
||
Nichtaktivierung bei tile>=S, beide Gather-Schwellen, Flash-Priorität,
|
||
Prefill-vs-Verify-Phase, partielle Tails, ungültige frühe Top-k-Slots,
|
||
S2048, Kontext32768 sowie parametrisierte Ratio1/4/8. Der Test prüft Formen,
|
||
Host-Tailwerte, Lane-Zähler und Kernelarbeit vor der Rückgabe: ausschließlich
|
||
bei aktiven Score-Kacheln. Cache und Query werden vor dem abschließenden
|
||
Eval freigegeben, sodass auch die Graph-Lebensdauer geprüft wird.
|
||
|
||
Fixture: `tests/fixtures/mtplx-qsa-eager-graph.jsonl`, SHA256
|
||
`25ea1819857c0eb91ff6700298f597ba47ccebe418cc5259a1dde76aae7bca2b`.
|
||
Der erste fokussierte TF32-on-Test besteht in1,78s; der gemeinsame TF32-off-
|
||
Durchlauf mit unretained Command Buffers besteht125/125 Tests in74,83s.
|
||
Dieser erste Gesamtlauf liegt vor den zusätzlichen Bool-Layout- und
|
||
Lane-Zähler-Checks; deren finale Prüfung wird separat protokolliert.
|
||
|
||
Finaler Stand: gemeinsamer Standard-TF32-Durchlauf125/125 in75,49s;
|
||
TF32-off/FastSync-Auswahlprüfung1/1 in1,00s. Der Prozessabschluss meldet
|
||
die erwarteten Lane-Zähler (42 eager_selector,18 decode_flash_skip,
|
||
12 decode_gather,6 decode_dense_mask). Release-Test-Clippy, Format-/Diff-
|
||
und Quellenprüfung bestehen. Vollständige Protokolle:
|
||
`local-eval-results/20260907-mtplx-port/eager-selection-graph-check.log`.
|
||
Diese Testlaufzeiten sind keine Modell-Durchsatzwerte.
|
||
Die finale TF32-off/unretained-Gruppe für Eager-Auswahl, Bool-Gather-Layouts
|
||
und Repeat/Arraygraph besteht zusätzlich3/3 Tests in1,04s.
|
||
|
||
P08 bleibt offen: vollständiger Indexer-Aufruf mit Projektion, Query-/Pooling-
|
||
Vorbereitung und Cache-Update, Fused-/Compiled-Selektoren im kanonischen
|
||
Graph und Attention-Aufruf. Die Eager-Auswahl ist verbunden und geprüft,
|
||
nicht der gesamte Indexer und nicht das Produkt. Weiterhin `cfg(test)`;
|
||
keine Vollmodell-Performance-, UI-Responsiveness- oder2%-Abnahme.
|
||
|
||
### Gemeinsamer QSA-Indexer-Vorlauf und fortlaufender Cache (2026-09-07)
|
||
|
||
`qsa_indexer::Indexer::prepare_rows` verbindet jetzt den nicht-kompilierten
|
||
gemeinsamen Vorlauf von `QSAIndexer._call_rows`: vorhandenes Dense-/Quantized-
|
||
Linear oder direkt übergebene QK-Zeilen; Split/Reshape; Query-RMSNorm/RoPE;
|
||
positionsbezogenes Schreiben der Rohschlüssel; Vervollständigen ganzer Pool-
|
||
Blöcke, Norm/RoPE und Schreiben in gepoolten Cache samt F32-Spiegel.
|
||
Die vorher geprüften Array-, Linear-, RoPE-, Reduktions-, Cache- und Custom-
|
||
Kernel-Funktionen werden direkt wiederverwendet, keine zweite Mathematik.
|
||
|
||
Query und Pool verwenden bei tatsächlich erfüllter Original-Eligibility die
|
||
MTPLX-Prepare-Kernel; sonst den ursprünglichen Eager-Ausdruck. Pooling mittelt
|
||
zuerst inF32, castet zurück zum Eingabetyp, normiert und rotiert danach.
|
||
Blockpositionen stammen von `min(cache.pooled_len,total/ratio)`, nicht von
|
||
der gerade gelieferten Chunkgrenze. Dadurch werden unvollständige Blöcke
|
||
über mehrere Aufrufe korrekt vervollständigt und nach Rollback neu berechnet.
|
||
Der Indexer verschiebt `kv.offset` nicht; das bleibt Aufgabe von Attention.
|
||
|
||
Unterhalb/einschließlich des Blockbudgets erfolgt der originale Rücksprung
|
||
nach den Cache-Updates. Die dabei ungenutzte Query-Vorbereitung bleibt ein
|
||
verworfener Lazy-Ausdruck; der Test prüft ausdrücklich, dass ihr CustomKernel
|
||
nicht trotzdem dispatcht wird. Oberhalb des Budgets werden Query, gepoolte
|
||
Ansicht und Frontier an die bereits verbundene Eager-Auswahl weitergegeben.
|
||
Fused-/Compiled-Auswahl wird dadurch nicht stillschweigend ersetzt.
|
||
|
||
306 neue Receipts benutzen den unveränderten ursprünglichen `QSAIndexer`-
|
||
Aufruf und QSACache, mit kleinen lokalen Testgewichten und ohne Downloads:
|
||
BF16/F16/F32, Dense und übergebene nicht-kontiguierliche QK-Zeilen,
|
||
BF16-QuantizedLinear4/8bit, ganze/partielle RoPE, Prepare-Kernel an/aus,
|
||
Originalfallback bei D256 bzw. abweichendem Norm-Dtype, TF32 on/off.
|
||
Die Referenzflags wählen regulär Eager-Selection mit beiden Prepare-Pfaden;
|
||
es werden keine Methoden ersetzt. Diese Fixturekonfiguration ist kein
|
||
Produkt-Performance-Arm.
|
||
|
||
Jedes Profil führt neun Aufrufe mit einem weiterbenutzten Cache aus:
|
||
3,1,5,2041,1,4 Tokens, dann fünf Tokens trimmen,8,33,1 Tokens. Das umfasst
|
||
Blockvervollständigung, die512-Block-Schwelle, Cache-/Spiegelwachstum,
|
||
Rewriting nach Trim, Rows-Gather, Dense und Decode-Gather. Verglichen werden
|
||
vollständige Roh-/Pooling-/Spiegel-Backings inklusive Shape/Kapazität,
|
||
Frontiers und Auswahl-Ausgaben. Lazy/vorbereitete Ausführung über beide
|
||
TF32-Prozesse ergibt2.108 bitgenaue Tensorvergleiche.
|
||
|
||
Beim ersten Rust-Vergleich wurden die physischen Bytes des transponierten
|
||
F32-Spiegels als Row-Major gehasht. Roh- und Poolingcache stimmten bereits;
|
||
der Fehler betraf nur die Test-Auslesereihenfolge. Der Fixture-Leser stellt
|
||
jetzt wie NumPy `tobytes` die logische Reihenfolge her, ohne Cache- oder
|
||
Modellberechnung zu ändern. Die unveränderten Referenzhashes bleiben Maßstab.
|
||
|
||
Fixture: `tests/fixtures/mtplx-qsa-indexer-prefix.jsonl`, SHA256
|
||
`0f25280aab05b72158c7d596b67702c2bf67f2985bfa44fd9642430a14da5078`.
|
||
Der fokussierte Standard-TF32-Vergleich besteht in2,76s.
|
||
Prüfprotokoll: `local-eval-results/20260907-mtplx-port/indexer-prefix-check.log`.
|
||
|
||
Finaler gemeinsamer Stand:126/126 Tests bei Standard-TF32 in76,36s,
|
||
126/126 bei TF32-off und unretained Command Buffers in78,51s.
|
||
Die zusätzliche fokussierte FastSync-Sequenz besteht ebenfalls.
|
||
Release-Test-Clippy, Format-/Diff- und unveränderte Quellenprüfung bestehen.
|
||
Die genannten Prüfzeiten sind keine Inferenz-Performancewerte.
|
||
|
||
P08 bleibt offen: kanonische Fused-/Compiled-Selektoren samt durchgängigem
|
||
Routing und vollständiger Attention-Aufruf. `prepare_rows` ist kein
|
||
Ersatz für diese offenen Routen und kein neuer Produktionsfallback.
|
||
Der Port bleibt `cfg(test)`; die vollständige Produktmigration und
|
||
Funktions-/Responsiveness-/2%-Performance-Abnahme sind weiterhin offen.
|
||
|
||
### Fused-QSA-Selektor im kanonischen Arraygraph (2026-09-07)
|
||
|
||
`qsa_select` bildet nun den originalen `qsa_indexer_select_metal`-Aufruf
|
||
als Mehrfachausgabe-Primitive ab: Block-IDs/Gültigkeit/Scores, Token-IDs/
|
||
Gültigkeit oder Dense-Maske, jeweils mit dem privaten F32-Score-Scratch als
|
||
weiterem Graph-Sibling. Auswerten eines öffentlichen Ergebnisses führt den
|
||
gemeinsamen Kernel genau einmal aus. Verwerfen der Eingabehandles vor Eval
|
||
verliert weder Strides/Offsets noch dynamische Frontiers oder Scratch.
|
||
|
||
BF16, F16 und F32 werden für Query und Pool unabhängig gebunden, ohne
|
||
Kontiguierungs- oder Typkonvertierungsdispatch vor dem Originalkernel.
|
||
Der Host baut dessen unveränderten Header/Körper/Epilog mit den originalen
|
||
Formkonstanten und NAX/TF32-Bedingungen zusammen. Alle Ausgabepuffer werden
|
||
wie beim originalen CustomKernel vor der Kompilierung angelegt. Ein gemeinsamer
|
||
Encoder übernimmt Bindings, Datenumfänge, Grid und Threadgroup-Größe;
|
||
auch die bisherige Buffer-Schnittstelle verwendet jetzt diesen Backendpfad.
|
||
Es wurde keine zweite Implementierung desselben Shaders eingeführt.
|
||
|
||
`Indexer::select_fused` übernimmt `_select_fused`: Query-Zeilen werden nach
|
||
32MiB Score-Scratch aufgeteilt, niemals die History. Dense-Ausgaben verwenden
|
||
die stabile physische Breite `(backing_blocks+1)*ratio`; nach Concatenate
|
||
folgt die logische Ansicht bis `total`. Zwischen den Chunks wurde kein
|
||
zusätzliches Eval oder Flush eingeführt.
|
||
|
||
126 neue unveränderte Referenz-Receipts umfassen alle drei Ausgabeformen,
|
||
BF16/F16/F32, gemischte Eingabedtypen, transponierte/gestridete/gebroadcastete
|
||
Ansichten, Top-k1/3/7/512, Ratio1/3/4, verschiedene Headgeometrien,
|
||
leere bzw. gepaddete History und eine echte 127+2-Zeilen-Aufteilung bei
|
||
65537 Backing-Blöcken. Für die Chunkfälle wird MTPLXs ursprüngliche
|
||
`QSAIndexer._select_fused`-Methode mit ihrem ursprünglichen Chunkhelper
|
||
aufgerufen; keine Ersatzmethoden. TF32 on/off und lazy/vorbereitete Eingaben,
|
||
zusätzlich Host-/Tensor-Frontiers für direkte Aufrufe, ergeben936 bitgenaue
|
||
Tensorvergleiche. Der Test prüft außerdem Sibling-Eigentümerschaft, verzögerte
|
||
Konstruktion und die tatsächlich dispatchten Geometrien.
|
||
|
||
Fixture: `tests/fixtures/mtplx-qsa-fused-graph.jsonl`, SHA256
|
||
`56d8b82dd8978ecd8ab0d69d918744668ce7bf596ac61815f5c5e9cd666f3b19`.
|
||
Prüfprotokoll: `local-eval-results/20260907-mtplx-port/fused-selection-graph-check.log`.
|
||
|
||
Der gemeinsame Stand besteht127/127 Tests bei Standard-TF32 in78,54s
|
||
und127/127 bei TF32-off mit unretained Command Buffers in78,98s.
|
||
Der fokussierte Fused-Graph-Test besteht zusätzlich mit FastSync, TF32-off
|
||
und unretained Command Buffers in1,65s.
|
||
Release-Test-Clippy sowie Format-/Diffprüfung bestehen. Die Quellenprüfung
|
||
bestätigt weiterhin17 originale Körper,41 Custom-Entrypoints und22 Runtime-
|
||
Einheiten mit183 Einträgen; an den Shaderdateien war keine Änderung nötig.
|
||
Diese Testzeiten sind keine Modell-Inferenzmessung.
|
||
|
||
P08 bleibt offen: kanonischer vektorisierter Prefill-Selektor und Compiled-
|
||
Indexer, vollständiges Routing sowie Attention-Aufruf. Der neue Fused-Pfad
|
||
ist kein Ersatz für diese anderen Originalrouten und wird nicht als
|
||
allgemeiner Prefill-Fallback eingesetzt. Produktion bleibt unverändert auf
|
||
dem alten Graphen (`qwen_mtplx` ist weiterhin `cfg(test)`). Deshalb sind
|
||
Funktions-/Responsiveness-/2%-Performance-Parität des Gesamtmodells weiterhin
|
||
nicht nachgewiesen; dieser Schritt hat keine Performance-Auswahl oder
|
||
begründungslose Rücknahme eines MTPLX-Bestandteils vorgenommen.
|
||
|
||
### Zweistufiger Prefill-Selektor im kanonischen Arraygraph (2026-09-07)
|
||
|
||
`qsa_prefill::select` verbindet jetzt den originalen
|
||
`qsa_indexer_prefill_metal`-Graphen: statische Score-Produzentenwahl,
|
||
produzentenabhängiges Workspace-/Alignment-Budget, Query-Slices, Scores,
|
||
exakter Top-k-Selektor und Concatenate aller öffentlichen Ergebnisblätter.
|
||
BF16/F16 mit gleicher Eingabedtype und H4/D128 verwenden bei originaler
|
||
NAX-Eligibility den unveränderten TensorOps-Score-Kernel. Sonst wird der
|
||
bereits geprüfte `attention::qsa_scores`-Ausdruck verwendet: F32-Matmul,
|
||
ReLU pro Head, F32-Summe, Division. Der transponierte F32-Pool entsteht
|
||
in dieser Route nur einmal und wird zwischen Chunks geteilt.
|
||
|
||
Es gibt keinen Laufzeit-Fallback nach ausgewähltem TensorOps-Dispatch.
|
||
Ein Fehler bleibt sichtbar. Score-Workspace zählt dort nur eine Ebene,
|
||
beim allgemeinen Ausdruck H+1; große Teilchunks werden nach unten auf32
|
||
Zeilen ausgerichtet, eine irreduzible Zeile darf ein kleineres Budget
|
||
überschreiten. Wie im Original kommt kein zusätzlicher Chunk-Eval/Flush hinzu.
|
||
|
||
Beide neuen CustomKernel-Primitive teilen ihre Encoder mit den vorherigen
|
||
Buffer-Aufrufern. Der Top-k-Quellgenerator ist nun Ratio-parametrisch statt
|
||
auf4 festgelegt. Header/Körper/Epilog bleiben aus dem gepinnten Export.
|
||
Top-k besitzt den ursprünglichen Mehrfachausgabe-Vertrag ohne zusätzlichen
|
||
Scratch-Sibling. Der CustomKernel legt zuerst alle Ausgaben an, führt dann
|
||
bei nicht-row-kontiguierlichen Eingaben die originale General-Copy aus und
|
||
kompiliert/dispatcht anschließend. TensorOps konsumiert tatsächliche Strides
|
||
und Offsets ohne solche impliziten Eingabekopien. Dynamische Frontiers
|
||
bleiben im Graphen; auch `pos+row_start` wird nicht auf dem Host ausgelesen.
|
||
|
||
144 neue Receipts aus unveränderten MTPLX-Aufrufen prüfen BF16/F16/F32,
|
||
gemischte Dtypes, Original-Fallbacks für andere Headgeometrien,
|
||
transponierte/gestridete/gebroadcastete Eingaben, alle drei Ausgabeformen,
|
||
kleinstes Workspace sowie produktionsnahe K512-/Ratio4-Geometrien.
|
||
Der65-Zeilen-Fall erzwingt im TensorOps-Pfad32+32+1 Zeilen, im allgemeinen
|
||
H4-Pfad8-Zeilen-Chunks plus Rest. Eigenständige Top-k-Fälle prüfen außerdem
|
||
gestridete Scores und kleinere/mehrstufige Radix-Kandidatenmengen.
|
||
TF32 on/off, lazy/vorbereitete Eingaben und Host-/Tensor-Frontiers ergeben
|
||
1.152 bitgenaue Tensorvergleiche. Tatsächliche Producer-/Top-k-Geometrien,
|
||
Copy-Anzahl und verzögerte Konstruktion werden separat geprüft.
|
||
|
||
Die erste neue Testassertion zählte Concatenate fälschlich als einen
|
||
Dispatch; tatsächlich kopiert das Original jedes Chunk-Blatt einzeln.
|
||
Nur diese Erwartung wurde korrigiert, keine Referenzhashes oder Shader.
|
||
Der anfängliche33-Zeilen-Fall passte noch in einen Chunk und wurde für
|
||
einen echten Alignment-/Restchunk-Nachweis mit65 Zeilen neu aufgenommen.
|
||
|
||
Fixture: `tests/fixtures/mtplx-qsa-prefill-graph.jsonl`, SHA256
|
||
`f223b1157d13833e899fb1b73e35a5343f26fb48940ee3c908829df14f6ae289`.
|
||
Prüfprotokoll: `local-eval-results/20260907-mtplx-port/prefill-selection-graph-check.log`.
|
||
Der fokussierte Standard-TF32-Test besteht in2,17s; keine Inferenzzeit.
|
||
|
||
Gemeinsamer Stand:128/128 Port-Tests bei Standard-TF32 in82,49s und
|
||
128/128 bei TF32-off mit unretained Command Buffers in80,25s bestanden.
|
||
Der fokussierte Prefill-Test besteht zusätzlich mit FastSync, TF32-off und
|
||
unretained Command Buffers in2,04s.
|
||
Release-Test-Clippy, Format-/Diffprüfung und die unveränderte Quellenprüfung
|
||
(17 Körper,41 Custom-Entrypoints,22 Runtime-Einheiten/183 Einträge) bestehen.
|
||
Die ursprünglichen Shaderdateien benötigten keine Änderung.
|
||
|
||
P08 bleibt offen: kanonischer Compiled-Indexer, vollständige Verbindung der
|
||
vorhandenen Selektoren mit Indexer-Routing und Attention, Full-SDPA sowie
|
||
Produktmigration. Der gesamte neue Graph bleibt `cfg(test)`. Es wurde kein
|
||
Produkt-Performance-/Responsiveness-Pass aus diesen Kernelprüfungen abgeleitet.
|
||
|
||
### Dynamische Cache-Fenster im kanonischen Arraygraph (2026-09-07)
|
||
|
||
Die noch fehlenden `DynamicSlice`/`DynamicSliceUpdate`-Operationen des
|
||
Compiled-Indexer-Graphen sind nun im gemeinsamen Array-/Eval-Pfad vorhanden.
|
||
Achsenprüfung, Broadcast/Cast des Updates, leere Ergebnisse/Updates,
|
||
Copy-/Donation-Auswahl und dynamische Geräteoffsets folgen dem gepinnten
|
||
Runtime-Original. Die Updates benutzen denselben General/GeneralGeneral-
|
||
Copy-Encoder wie statische Operationen, mit den ursprünglichen dynamischen
|
||
Runtime-Kerneleinträgen. Es kommen weder Host-Readback der Position noch
|
||
zusätzlicher Eval/Flush oder eine Ersatzimplementierung des Indexers hinzu.
|
||
|
||
Die Offset-Berechnung verwendet den erfassten ursprünglichen Shaderkörper
|
||
mit den originalen acht Integer-Typinstanziierungen. Auch die bisherigen
|
||
Buffer-basierten Cache-Aufrufer verwenden jetzt diesen gemeinsamen Encoder;
|
||
deren doppelte Offset-Implementierung ist entfernt.
|
||
Originales Last-use-Donation kann Metadaten des Indexpuffers unverändert an
|
||
den internen int64-Offset weitergeben, einschließlich abweichender Dtype,
|
||
Scalar-Rank und `data_size`. Dafür gibt es die originale unqualifizierte
|
||
`copy_shared_buffer`-Variante; die vorhandene explizite View-Prüfung bleibt
|
||
unverändert. Physische Zugriffsgrenzen werden weiterhin geprüft.
|
||
Beim Ergänzen des Donation-Tests fiel im Quellvergleich eine fehlende
|
||
Output-Byteoffset-Bindung auf; sie ist korrigiert. Tests mit Offset 0/8 prüfen auch,
|
||
dass vorangestellte Sentinel-Bytes unverändert bleiben.
|
||
|
||
30 Fälle aus unveränderten Referenzaufrufen liefern 360 bitgenaue Tensorvergleiche:
|
||
BF16/F16/F32, acht Integer-Indextypen, lazy/vorbereitete Eingaben,
|
||
behaltene/freigegebene Quellen, Transpose/Stride/Broadcast/negative Strides,
|
||
mehrere Achsen, leere und skalare Updates sowie verkettete Cache-Fenster.
|
||
Zusätzlich werden Dispatch-Anzahl, verzögerte Konstruktion und gemeinsame
|
||
beziehungsweise getrennte Pufferidentität geprüft.
|
||
Fixture: `tests/fixtures/mtplx-dynamic-slice-graph.jsonl`, SHA256
|
||
`86d170991c68c9009b10eeead9479bc575e89b7eef6528e2a39677220d218acc`.
|
||
|
||
Gemeinsame Regression: 129/129 Port-Tests bestehen mit Standard-TF32
|
||
(80,93 s) und mit TF32-off/unretained Command Buffers (81,71 s).
|
||
Der fokussierte neue Test besteht zusätzlich mit FastSync (0,81 s).
|
||
Release-Test-Clippy, Format-/Diffprüfung und die unveränderte Quellenprüfung
|
||
(17 Körper, 41 Custom-Entrypoints, 22 Runtime-Einheiten/183 Einträge) bestehen.
|
||
Protokoll: `local-eval-results/20260907-mtplx-port/dynamic-slice-graph-check.log`.
|
||
Dies sind Testlaufzeiten, keine Inferenz-Leistungsdaten.
|
||
|
||
P08 bleibt offen: Dies schließt eine Abhängigkeit des kanonischen Compiled-
|
||
Indexers, nicht dessen Graphbank/Replay und Routing. Full-SDPA, vollständiger
|
||
Attention-Aufruf und Produktmigration bleiben erforderlich. Weiterhin
|
||
`cfg(test)`; kein Gesamtmodell-, UI- oder Performance-Paritätsnachweis.
|
||
|
||
### Reiner Compiled-Indexer und kanonisches Graph-Replay (2026-09-07)
|
||
|
||
`qsa_compile::Body` verbindet nun die reine zehnargumentige Grenze von
|
||
`QSACompiledIndexerCore`: bereits projizierte Q/K-Zeilen oder interne
|
||
Projektion, explizite Norm-/RoPE-Eingänge, dynamische Raw-/Pool-Updates,
|
||
begrenztes rückwärtiges Pool-Fenster, Query-Vorbereitung und alle fünf
|
||
Ausgabeformen. Die vier State-Ergebnisse bleiben Array-Ausgänge; Position
|
||
und logische Blockzahl werden unverändert als Eingangsdescriptoren
|
||
zurückgegeben. Der Body mutiert keinen Host-Cache und liest keine Frontiers
|
||
auf dem Host aus.
|
||
|
||
`compiled::Replay` übernimmt die feste DFS-/Sibling-Tape-Struktur und
|
||
`compile_replace`-Semantik: einmalige Tracer-Platzhalter, danach neue
|
||
Ausgabe-Descriptoren mit gemeinsamem unveränderlichem Primitiv und jeweils
|
||
aktuellen Eingangsarrays. Konstanten/Load-Blätter bleiben geteilt, Shapes
|
||
und Dtypes sind fest, Strides/Offsets und Werte keine Trace-Konstanten.
|
||
Die Konstruktion und das Replay dispatchen keine GPU-Arbeit. Ein eigener
|
||
Hosttest prüft vertauschte Sibling-Root-Reihenfolge, Descriptor-/Primitiv-
|
||
Identität, neue Eingänge sowie Fehler für falsche Signaturen und unzulässig
|
||
geschlossene ursprüngliche Aufrufseingänge.
|
||
|
||
Die Clamp-/Multiply-/Chunk-Position-Knoten verwenden die unverändert
|
||
erfassten fusionierten Compiled-Shader, keine Reihe einzelner Binary-Kernel.
|
||
Sie teilen den bereits vorhandenen Compiled-Evaluator einschließlich
|
||
Layout-/Donation-Auswahl. Auch die vorherigen Buffer-Aufrufer benutzen
|
||
jetzt diesen Backendpfad; drei doppelte Skalar-Encoder sind entfernt.
|
||
Quellgenerierung und JSON-Auswertung geschehen nur beim ersten Compile,
|
||
nicht bei jedem Decode-Schritt. Der Prefill-Body teilt den bisherigen
|
||
Zweistufen-Selektor; im Compiled-Aufruf ist die Chunk-Position ebenfalls
|
||
der originale fusionierte Add-Knoten.
|
||
|
||
198 bestehende unveränderte Referenzfälle prüfen Q/K und vier affine
|
||
Hidden-Projektionsvarianten (4/8 Bit, Gruppen32/64), alle fünf Modi,
|
||
Zeilenzahlen1/4/5/33/65/2048, zwei Scratch-Budgets sowie wechselnde
|
||
Q/K-Strides640/704. Ausgaben, neue/alte Cache-Hashes und die aus dem
|
||
Original-DOT abgeleiteten geordneten Abhängigkeits-/Sibling-Fingerprints
|
||
stimmen überein. Die Testbank verwendet bei Stride-Wechseln denselben
|
||
Replay-Eintrag; sie ist nicht die noch ausstehende produktive Host-Graphbank.
|
||
Die Referenzfälle sind BF16/H4/D128, Prefill verwendet MPP auf diesem M5 Max.
|
||
|
||
Der Test führt diese Fälle anschließend jeweils mit behaltenen und ohne
|
||
behaltene Cache-Snapshots aus: 396 Replays und 2.052 Tensor-/Cache-Hashes.
|
||
Mit Snapshot müssen alte Zustände unverändert bleiben und neue Backings
|
||
entstehen; ohne Snapshot müssen Raw- und Pool-Ausgabe die ursprüngliche
|
||
Data-Identität wiederverwenden. Die Graphbank selbst hält keine alten
|
||
Aufrufseingänge und verhindert diese Donation nicht.
|
||
|
||
131/131 gemeinsame Port-Tests bestehen bei Standard-TF32 (80,79 s; vor
|
||
Erweiterung des neuen Tests auf beide Snapshot-Varianten) und bei TF32-off
|
||
mit unretained Command Buffers (82,09 s; alle 396 Replays).
|
||
Die 396 Replays bestehen zusätzlich bei Standard-TF32 mit FastSync (1,33 s).
|
||
Release-Test-Clippy, Format-/Diffprüfung und die unveränderte Quellenprüfung
|
||
(17 Körper, 41 Custom-Entrypoints, 22 Runtime-Einheiten/183 Einträge) bestehen.
|
||
Protokoll: `local-eval-results/20260907-mtplx-port/compiled-indexer-replay-check.log`.
|
||
Dies sind Testlaufzeiten, keine Modell-Inferenzmessungen.
|
||
|
||
P08 bleibt offen: der Host-Core mit Bucket-/Frontier-Validierung, vollständigen
|
||
Compile-Schlüsseln, Engagement-Statistik und Indexer-Routing; außerdem
|
||
weitere Compiled-Geometrien/Dtypes einschließlich der allgemeinen
|
||
Nicht-MPP-Score-Fusion, Full-SDPA, Attention und Produktmigration.
|
||
Replay ist ausdrücklich kein allgemeiner Ersatz für die ursprünglichen
|
||
Compiler-Simplify-/Fuse-Pässe. Deren Wirkung ist für die oben genannten
|
||
erfassten Graphen nachgewiesen, nicht pauschal für beliebige Ausdrücke.
|
||
Weiterhin `cfg(test)`, keine Modell-/UI-/2%-Performance-Abnahme.
|
||
|
||
### Kanonischer Compiled-Host-Core und Engagement (2026-09-07)
|
||
|
||
`qsa_core::Core` implementiert nun zusätzlich zum reinen Replay-Test den
|
||
Host-Vertrag von `QSACompiledIndexerCore`: unveränderliche Konfiguration,
|
||
Norm-/RoPE-Eingänge, optionale interne Projektion und getrennte Hidden-/QK-
|
||
Schlüssel. Sämtliche Shape-/Dtype-/Head-/Top-k-/Ratio-/Dense-Capacity-/Producer-
|
||
und Chunk-Felder des ursprünglichen `_CompileKey` werden berücksichtigt.
|
||
Werte, Strides und Offsets sind weiterhin keine zusätzlichen Schlüssel.
|
||
Die ursprüngliche Standardkonfiguration und benutzerdefinierte Bucket-
|
||
Untergrenzen sowie die abschaltbare Bucket-Pflicht bleiben erhalten.
|
||
|
||
Der Core prüft Projektions-/Cache-/Norm-Dtypes, Backing-Geometrien, feste
|
||
Pool-Fenster, Host-Frontiers und Backing-sichere Dense-Ausgabebreiten vor dem
|
||
Dispatch. Tensor-Frontiers werden lediglich auf ein int32[1]-Array normalisiert,
|
||
nicht synchron auf dem Host ausgelesen. Die Rückgabe trennt Auswahl und vier
|
||
explizite State-Blätter. Host-Cache-Commit und Aufrufroutenauswahl liegen
|
||
weiterhin beim noch anzuschließenden Indexer.
|
||
|
||
Calls, Source-/Mode-/Producer-Zähler, Selector-Dispatches, Capacity-Transitions,
|
||
Bucket-Zähler und vollständig sortierte Compile-Key-Berichte folgen dem
|
||
Original. Ein nach erstem Trace-Fehler leerer Laufzeit-Eintrag bleibt im
|
||
Host-Core bestehen: Wiederaufruf versucht den Trace erneut, ohne einen zweiten
|
||
Core-Trace-Request zu zählen oder einen halb aufgebauten Replay zu verwenden.
|
||
Bereits als Tracer übergebene Arrays bauen wie im Original direkt den Body,
|
||
statt den gecachten Replay zu verwenden. Kein Eager-Fehlerfallback wurde ergänzt.
|
||
|
||
32 neue Receipts wurden mit unverändertem MTPLX-Core aufgenommen: elf echte
|
||
aufeinanderfolgende Aufrufe mit wechselnden Shapes, Strides, Positionen,
|
||
Kapazitäten, Hidden-/QK-Quellen und allen fünf Modi (66 bitgenaue Output-/State-
|
||
Hashes), vollständige Zwischen-/Endberichte, 17 Validierungsfälle und zwei
|
||
aufeinanderfolgende fehlgeschlagene Erst-Traces. Der zulässige Tensor-Frontier-
|
||
Fall wird nur lazy aufgebaut und ausdrücklich nicht auf der GPU ausgeführt;
|
||
sein Host-Gegenstück wird vorher abgewiesen. Neun zusätzliche Konstruktor-
|
||
Assertions sichern die direkt aus dem Quellcode portierten Grenzen ab.
|
||
|
||
Fixture: `tests/fixtures/mtplx-qsa-core-host.jsonl`, SHA256
|
||
`05d3642cbf08a12f6f1c1ad7cac0b529d2ef51f3bfb9c27ab6ab229aa1017022`.
|
||
Der fokussierte Referenztest besteht (0,75 s; keine Inferenzzeit).
|
||
|
||
Gemeinsame Regression: 132/132 Port-Tests bei Standard-TF32 (82,51 s) und
|
||
TF32-off/unretained Command Buffers (82,61 s); fokussierter Host-Core mit
|
||
FastSync ebenfalls bestanden (0,07 s). Release-Test-Clippy, Format-/Diff-
|
||
prüfung und unveränderte Quellenprüfung (17 Körper, 41 Custom-Entrypoints,
|
||
22 Runtime-Einheiten/183 Einträge) bestehen. Protokoll:
|
||
`local-eval-results/20260907-mtplx-port/compiled-host-core-check.log`.
|
||
Die Laufzeiten sind keine Modell-Performance-Abnahme.
|
||
|
||
P08 bleibt offen: Parameter-Identitätssiegel und Core-Lebenszyklus im Indexer,
|
||
automatische Backing-Reservierung/Commit, vollständiges Fused-/Eager-/Compiled-
|
||
Routing, übrige Compiled-Geometrien/Dtypes und Nicht-MPP-Score-Fusion,
|
||
Full-SDPA, Attention und Produktmigration. Der Host-Core ist noch nicht der
|
||
vollständig verbundene Modellaufruf; weiterhin `cfg(test)` und keine
|
||
Modell-/UI-/2%-Performance-Abnahme.
|
||
|
||
### Durchgehender kanonischer Indexer und Cache-Commit (2026-09-07)
|
||
|
||
`qsa_indexer::Indexer` verbindet jetzt den gemeinsamen Vorlauf, den persistenten
|
||
Compiled-Core sowie Compiled-/Prefill-/Fused-/Eager-Routing in einem Aufruf.
|
||
Die ursprünglichen Phase-/Shape-/Dtype-/Projektions-/Cache-Prüfungen entscheiden
|
||
vor der Reservierung; Dispatchfehler führen nicht zu einem Eager-Wiederanlauf.
|
||
Die vorhandene Modusregel wird auch vom alten Buffer-Aufrufer verwendet und
|
||
nimmt nun Ratio/Top-k explizit entgegen, statt die Modellgeometrie festzusetzen.
|
||
Die bereits geprüften Selektoren, Cache-Operationen und Engagement-Zähler werden
|
||
gemeinsam genutzt. Es gibt keinen zusätzlichen Flush, Wait oder Readback im
|
||
Compiled-Aufruf; ursprüngliche Eager-Kachel-Evals bleiben unverändert.
|
||
|
||
Das Identitätssiegel erfasst Normen, Frequenzen und Projektionsgewicht sowie
|
||
Quantisierungsskalen/-biases. Ein ausgetauschtes Blatt baut den Core neu auf;
|
||
gleiche Bytes genügen nicht zum Wiederverwenden. Unveränderte Blätter behalten
|
||
den Core und dessen ursprünglich erfasste Speicherbudgets. Fehlgeschlagene
|
||
Neukonstruktion lässt den bisherigen Core samt Siegel bestehen. Backings werden
|
||
vor dem Core-Aufruf reserviert; dessen explizite Ergebnisse ersetzen die
|
||
Cache-Arrayobjekte, aktualisieren die logische Pool-Länge und verwerfen den
|
||
F32-Spiegel. Alte Snapshots bleiben unverändert. `cache.kv.offset` wird nicht
|
||
vorweggenommen; dessen Fortschreibung gehört weiterhin zu Attention.
|
||
|
||
26 neue, unveränderte MTPLX-Aufrufe prüfen fortlaufend alle fünf Rückgabeformen,
|
||
Hidden-/QK-Quellen, dichte/quantisierte Projektion, Gewichtswechsel, Budget-
|
||
Wiederverwendung, Backing-Wachstum, Trim und gescheiterte Core-Ersetzung.
|
||
52 Rust-Aufrufe mit/ohne gehaltene Snapshots stimmen in 216 Output-/State-
|
||
Hashvergleichen überein; vollständige Core-Berichte stimmen ebenfalls.
|
||
Fixture: `tests/fixtures/mtplx-qsa-indexer-commit.jsonl`, SHA256
|
||
`ed4dde278663e0f7d684fc78ea51474f68ab5326f467f3022ef521a7cf93939e`.
|
||
|
||
Zusätzlich stimmen die 200 vorhandenen vollständigen Indexer-Referenzaufrufe
|
||
einschließlich 2K-Prefill, aller Lane-Wechsel, Cache-Inhalte und Graphbank-Zähler
|
||
mit dem kanonischen Arraygraph überein. Die 720 vorhandenen statischen
|
||
Zulässigkeitsfälle stimmen ohne GPU-Dispatch überein, einschließlich inkonsistenter
|
||
Frontiers und nicht gebucketeter/leer vorhandener Backings. Diese Nachweise
|
||
betreffen die erfasste B1/BF16/H4/D128-Modellgeometrie, nicht beliebige Typen.
|
||
|
||
Gemeinsame Regression: 134/134 bei Standard-TF32 (84,69 s; vor Ergänzung der
|
||
720 statischen Assertions) und TF32-off/unretained Command Buffers (84,18 s;
|
||
einschließlich dieser Assertions). Die drei Indexer-Tests bestehen außerdem
|
||
bei Standard-TF32 mit FastSync (3,36 s), ebenfalls einschließlich aller
|
||
720 Assertions. Release-Test-Clippy, Format-/Diffprüfung
|
||
und die unveränderte Quellenprüfung (17 Körper, 41 Custom-Entrypoints,
|
||
22 Runtime-Einheiten/183 Einträge) bestehen. Protokoll:
|
||
`local-eval-results/20260907-mtplx-port/indexer-lifecycle-routing-check.log`.
|
||
Diese Laufzeiten sind Korrektheitstestzeiten, keine Inferenzmessungen.
|
||
|
||
P08 bleibt offen für übrige Compiled-Geometrien/Dtypes einschließlich der
|
||
allgemeinen Nicht-MPP-Score-Fusion, Full-SDPA, den vollständigen Attention-Aufruf
|
||
und die Produktmigration. Der Port bleibt `cfg(test)`; die alte UI-Ausführung
|
||
ist damit noch nicht ersetzt und das 2%-Gesamtziel bleibt offen.
|
||
|
||
### Verbundener Qwen-Attention-Modulaufruf (2026-09-08)
|
||
|
||
`qsa_attention::Attention` verbindet nun den vollständigen BF16/D256-Aufruf
|
||
der MTPLX-Klasse: separate Q/K/V-Projektionen oder gemeinsame Drei-/Vierfach-
|
||
Projektion, Indexer vor KV-Fortschreibung, per-Head-Norm, Query-/Gate-Aufteilung,
|
||
partielles RoPE/M-RoPE, KV-Update, sämtliche QSA-Consumer, Sigmoid-Ausgangsgate
|
||
und Ausgangsprojektion. Biased separate Projektionen sowie fehlender Indexer
|
||
sind ebenfalls abgebildet. Die bereits geprüften Operationen/Kernel werden
|
||
verwendet, nicht neu implementiert.
|
||
|
||
Ein beim Anschluss geschlossener Referenzunterschied: Die originale
|
||
Vierfachfusion entfernt `indexer.index_qk_proj`. `Indexer::projection` ist
|
||
deshalb jetzt optional. Zugelieferte QK-Zeilen funktionieren ohne diese
|
||
Projektion; das Identitätssiegel enthält dann nur Normen/Frequenzen und der
|
||
Compiled-Core erfasst keine versteckte zweite Projektion. Ein Hidden-Aufruf
|
||
ohne Projektion wird nicht durch einen erfundenen Ersatz bedient.
|
||
|
||
Die Consumer-Reihenfolge bleibt Flash-Skip, Prefill-Flash, optionaler
|
||
Prefill-Gather, Dense-Rekonstruktion, Rows-Gather und gewöhnliches SDPA.
|
||
Sparse-Flash liest die KV-Backings und ihre Kapazitätsstrides direkt. Die
|
||
ursprünglichen Engagement-Zähler und die expliziten Gather-Tile-Evals bleiben
|
||
erhalten; es gibt keine zusätzliche Aufmerksamkeitssynchronisation.
|
||
Ein Vision-Request überspringt nur die Sparse-Auswahl, nicht den Indexer und
|
||
seine Cache-Updates. M-RoPE verwendet innerhalb der Tabelle deren Achsen;
|
||
danach die normale Positionsfolge mit Request-Delta. Ohne konfigurierte
|
||
M-RoPE-Achsen bleibt das originale Plain-RoPE-Verhalten erhalten.
|
||
|
||
**Keine stillschweigende Full-SDPA-Abkürzung:** Qwens normaler D256-Aufruf
|
||
verwendet eine explizite Array-Maske oder keine Maske. Die gepinnte Runtime
|
||
selektiert hier für S>8 den Matmul-Fallback. Der NAX-D256-Split wird dagegen
|
||
nur für kausale String-Maske ohne Array-Maske und S>=1024 gewählt
|
||
(`scaled_dot_product_attention.cpp:750–767`). Der Modellport behält diese
|
||
Originalauswahl; die allgemeine Full-SDPA-Erweiterung bleibt separat offen.
|
||
|
||
56 Receipts stammen aus der unveränderten MTPLX-Attention-Klasse, je 28 mit
|
||
TF32 an/aus. Zehn fortlaufende Szenarien umfassen kalten 2K-Prefill,
|
||
Prefill ab 32768 mit ursprünglichem Sparse-Flash, Decode/Verify, alle Consumer,
|
||
Cache-Trim, Projektionsfusion mit wirklich entfernter Indexer-Projektion,
|
||
Bias/no-indexer und Vision inklusive des ersten Schritts nach dem Tabellenende.
|
||
Die Referenz protokolliert die tatsächlich aufgerufenen Consumer durch reine
|
||
weiterleitende Beobachter; keine Berechnung wird ersetzt. 288 Referenzhashes
|
||
decken Ausgabe und KV-/Raw-/Pool-/F32-Mirror-Backings ab. Rust prüft zusätzlich
|
||
Shapes, Frontiers, vollständige Core-Berichte, Engagement-Deltas und die
|
||
tatsächlichen Sparse-Flash-Graphknoten/-Dispatches.
|
||
Fixture: `tests/fixtures/mtplx-qsa-attention-module.jsonl`, SHA256
|
||
`d0fdbd1ad13820004a672a7634e50a66cf50a708180a9d037720920619f02016`.
|
||
|
||
112 Rust-Aufrufe (jeweils lazy/vorbereitet, TF32 an/aus) bestehen mit
|
||
576 bitgenauen Ausgabe-/Cache-Hashvergleichen. Gemeinsame Regression135/135
|
||
bei Standard-TF32 (120,88 s) und TF32-off/unretained Command Buffers
|
||
(121,01 s); vollständiger Attention-FastSync-Test ebenfalls bestanden
|
||
(1,34 s). Release-Test-Clippy, Format-/Diffprüfung und unveränderte
|
||
Quellenprüfung (17 Körper,41 Custom-Entrypoints,22 Runtime-Einheiten/183
|
||
Einträge) bestehen. Die Testlaufzeiten sind keine Modell-Performancewerte.
|
||
Protokoll: `local-eval-results/20260908-mtplx-port/attention-module-check.log`.
|
||
|
||
Der vollständige Modell-/Decoder-/Serving-Aufruf und die Produktionsumstellung
|
||
bleiben offen, ebenso andere SDPA-Dtypes/Geometrien und übrige Compiled-
|
||
Geometrien/Nicht-MPP-Score-Fusion. `cfg(test)` ist weiterhin aktiv;
|
||
dies ist weder eine UI-Responsivitäts- noch eine Gesamtperformance-Abnahme.
|
||
|
||
Aktuelle Reproduktionsbefehle für die Kernel-Korrektheit:
|
||
|
||
```sh
|
||
python3 tools/mtplx-kernel-source.py local-eval-results/mtplx-reference-e652d55 --gated-delta-source local-eval-results/mtplx-reference-env-0.32.2/lib/python3.12/site-packages/mlx_lm/models/gated_delta.py --check
|
||
cargo test --release mtplx_canonical_source_bodies_preserve_pinned_hashes -- --nocapture
|
||
cargo test --release mtplx_canonical_hyper_and_gdn_kernels_match_reference -- --ignored --nocapture --test-threads=1
|
||
cargo test --release qwen_mtplx -- --include-ignored --test-threads=1
|
||
```
|
||
|
||
## Auftrag und Grenzen
|
||
|
||
Qwen muss funktional und hinsichtlich Durchsatz und Verzögerungen dem tatsächlich
|
||
aktivierten MTPLX-Pfad entsprechen oder schneller sein. Die Referenzzuordnung ist
|
||
verbindlich und gilt auch für spekulatives Decoding:
|
||
|
||
| Modell | Golden Master | Andere Implementierungen |
|
||
| --- | --- | --- |
|
||
| DeepSeek V4 Flash | antirez/ds4, einschließlich DSpark | MTPLX nur als zusätzliche Optimierungsquelle |
|
||
| GLM 5.3 Flash | antirez/ds4, einschließlich integriertem MTP | MTPLX nur als zusätzliche Optimierungsquelle |
|
||
| Qwen3.8 Flash Next | MTPLX | DS4 nur für gemeinsame Infrastrukturideen, nicht als Qwen-Orakel |
|
||
|
||
Ein möglicherweise besserer MTPLX-Ansatz für DeepSeek/GLM ersetzt deren Golden
|
||
Master nicht. Verbesserungen müssen die antirez/ds4-Verhaltens- und Sampling-
|
||
Verträge erhalten; eine abweichende Semantik braucht vor Umsetzung eine ausdrückliche
|
||
Nutzerentscheidung. Die UI und die Headless-Harness müssen dieselbe
|
||
Produkt-Inferenz ausführen. Ein kleinerer Qwen-Prefill-Chunk, niedrigere Leistung
|
||
oder zusätzliche Wartezeiten sind kein Ersatz für Ursachenklärung.
|
||
|
||
Dieser Abgleich inventarisiert die Ausführungskette und ordnet belegte Unterschiede,
|
||
bereits korrigierte Fehler und noch fehlende Nachweise ein. Er behauptet **nicht**,
|
||
dass jede numerische Operation und jeder seltene Fallback bereits als identisch
|
||
bewiesen ist. Diese offenen Nachweise haben unten eigene Tasks mit Abnahmekriterien.
|
||
Für die weitere Umsetzung gilt die verbindliche Auftragspräzisierung oben.
|
||
|
||
Nur vorhandene Modelle; keine Downloads. Keine neuen Projekt-Gates, externen Issues
|
||
oder Codex-Tasks. Die folgende Liste ist die lokale Arbeitsquelle. Bestehende
|
||
ungecommittete Änderungen bleiben erhalten.
|
||
|
||
## Festgehaltene Referenzen und Belege
|
||
|
||
- DS4Server: Arbeitsbaum auf `b99ce2a`, inklusive ungecommittierter Änderungen.
|
||
- MTPLX: `local-eval-results/mtplx-reference-e652d55`, Commit
|
||
`e652d55e2652137a4abcf1312357abbf3eb9d692`, installierte Runtime0.32.2.
|
||
Am2026-09-06 identisch wiederhergestellt, nachdem im früheren temporären
|
||
Checkout `/private/tmp/MTPLX-analysis-20260901` Quelldateien fehlten.
|
||
- DS4: `/Users/gb/Projects/ds4`, Commit
|
||
`ec7642cdd9ec81d01ad4b1fd8f8a3d1511533748`. C-Code nur lesen, nicht in DS4Server
|
||
übernehmen, kompilieren oder als Inferenz-Backend aufrufen.
|
||
- Qwen: vorhandenes Bare-Speed-Artefakt unter
|
||
`/Users/gb/Library/Application Support/de.rfc1437.ds4server/models/qwen3.8-flash-next`.
|
||
- Messbelege und Methoden: [Qwen-Responsiveness-Bericht](/Users/gb/Projects/DS4Server/docs/qwen-reference-responsiveness-20260905.md).
|
||
Rohdaten: `/private/tmp/ds4-ongoing-verified.16vzVw/`.
|
||
|
||
Der wiederholte MTPLX-AR-Lauf mit expliziter Session hatte maximal **2,974 ms**
|
||
GPU-Canary-Completion im Prefill, MTPLX-MTP **0,550 ms**. DS4Server-AR hatte
|
||
**4090,027 ms**. Gleiche native Probe, im jeweiligen Inferenzprozess; keine
|
||
fehlgeschlagenen Probes. Das belegt eine reale Responsiveness-Differenz, aber noch
|
||
nicht deren vollständige Aufteilung auf Scheduling und einzelne Kernel.
|
||
|
||
Die bisherigen Durchsatzwerte sind keine saubere 2%-Abnahme: Tokenisierung und
|
||
Cache-Wiederverwendung unterscheiden sich, die Canary war aktiv, und es fehlt eine
|
||
wiederholte, vollständig normalisierte Sechs-Zellen-Matrix. Historische GLM-MTP-Daten
|
||
mit überlappenden Workern sind ungültig.
|
||
|
||
### Tatsächlich aktive Qwen-Referenz statt allgemeiner MLX-Defaults
|
||
|
||
Die `/health`-Receipts in `mtplx-ar-session.jsonl` und `mtplx-mtp.jsonl` belegen:
|
||
Turbo, Chunk 2048, Kontextkapazität 131072, Low, Temperatur 1, top-p 0,95,
|
||
top-k 20, Seed 12345; committed MTP history, batched verify,
|
||
`linear-gdn-from-conv-tape`, lazy target distributions, family capture commit.
|
||
Fused HC V3, GDN input/step/convnorm, verify convnorm und gate/up sind aktiviert.
|
||
**NAX verify ist für diese Familie deaktiviert**, trotz des generischen
|
||
Turbo-Profils. Aktiviertes Environment allein beweist noch keinen Kernel-Aufruf;
|
||
Form- und Gerätegrenzen müssen ebenfalls passen.
|
||
|
||
Die Referenz lädt den MTP-Kopf auch beim AR-Server. Ihr Ready-Receipt zeigt noch
|
||
laufende Background-Warmup-Schritte. DS4Server lädt den Kopf bei abgeschaltetem MTP
|
||
nicht und die Harness führt einen eigenen separaten Warmup aus. Ladezeit,
|
||
Speicherbedarf und Kaltstart dürfen deshalb noch nicht direkt gleichgesetzt werden.
|
||
|
||
### Veröffentlichte M5-Max-Zahlen: Orientierung, keine Ersatzmessung
|
||
|
||
Der lokal gepinnte MTPLX-Releasebericht
|
||
[2.10.0](/private/tmp/MTPLX-analysis-20260901/docs/releases/v2.10.0.md:21)
|
||
nennt für Flash-Next 61 tok/s AR und 63–76 tok/s MTP je nach Workload.
|
||
[2.10.1](/private/tmp/MTPLX-analysis-20260901/docs/releases/v2.10.1.md:5)
|
||
nennt für lange Prefills 175,7 → 114,5 s bei 98k Tokens und 810 tok/s bei 131k.
|
||
Diese Angaben sind keine Referenz für einen beliebigen kurzen Summary-/Story-Chat.
|
||
Die Online-Abfrage der gepinnten MTPLX-Dateien war nicht abrufbar; die Zahlen sind
|
||
aus dem aktuell lokal geprüften Referenzcheckout, nicht als online neu bestätigt
|
||
ausgegeben.
|
||
|
||
Der [DS4-Speedabschnitt](https://github.com/antirez/ds4#speed) beschreibt dagegen
|
||
2048-Token-Schritte und 128 greedy Tokens mit *Promessi sposi*. Im lokalen Pin
|
||
stehen bei Kontext 2048 rund 790,18 Prefill- und 39,35 Decode-tok/s. Das ist eine
|
||
andere Arbeit als drei freie Antworten bis EOS. Nicht vermischen.
|
||
|
||
## Abdeckungsmatrix der Ausführungskette
|
||
|
||
Status: **M** gemessen; **Q** Unterschied im Quellcode belegt, Kosten/Tragweite
|
||
noch nicht vollständig gemessen; **T** Teilnachweis vorhanden; **O** Nachweis offen.
|
||
Quellstellen beziehen sich auf den oben genannten Arbeitsstand.
|
||
|
||
| Bereich | DS4Server | Referenz / Befund | Status / Task |
|
||
| --- | --- | --- | --- |
|
||
| Frontend → Engine | `src/app/generation.rs:780`, `src/model_eval.rs:803`, `src/runtime.rs:108` | Gleicher `GenerationService`, eigener `model-runtime`-Thread, LocalChat. Harness hat keinen echten GUI-Eventloop und bildet nicht jede UI-Nebenarbeit ab. | T/Q · P02, P04 |
|
||
| Systemprompt / Tools / Skills | `src/app/generation.rs:2469` | Headless-Helper lädt ExtensionRegistry und hängt verfügbare Skill-Instruktionen an. Kein Beleg für ausgeführte Tools, aber noch kein sauber isolierter Test ohne deren Prompt-Anteile. | Q · P02 |
|
||
| Qwen-Chatfortsetzung | `src/engine/tokenizer.rs:524`, `src/engine.rs:1420` | Zusätzliche Low-Systemnachricht bei Checkpoint-Fortsetzung erzeugte 30 zusätzliche Tokens. Lokal korrigiert und Regressionstest bestanden; End-to-end-Vergleich noch offen. | M/T · P02 |
|
||
| Cache / ongoing Chat | `src/engine/metal/qwen.rs:5312`, `src/model_eval.rs:907` | MTPLX AR wiederverwendete jedes Mal 5120 Tokens; MTP 5120/7840/8861. Vollständige History ist nicht gleich identischer Cache-Arbeit. | M · P03 |
|
||
| Laden / Warmup / Speicher | `src/engine/qwen.rs:362`, `src/engine/metal/qwen.rs:409` | Volle Kontextpuffer, andere Aktivierungs-Speichertypen; Referenz mit MTP-Kopf und Background-Warmup. | Q/O · P01, P09, P15 |
|
||
| Command-Buffer-Scheduling | `src/engine/metal/qwen.rs:844`, `native/metal/ds4_metal.m:11878` | Qwen bei 100% ein CB über alle Prefill-Layer. MLX automatische asynchrone Commit-Grenzen nach Operationen/Bytes. | M/Q · P05 |
|
||
| PLE-Hash / Gather / SSD | `src/engine/qwen.rs:224`, `src/engine/metal/qwen.rs:1024` | Beide 16 Leser und nominell 1 GiB Hot Rows. MTPLX staged vor Graphaufbau, große Gathers umgehen Row-LRU; Rust liest bei Layer 1 und cached auch große Gathers. | T/Q · P10 |
|
||
| HC / Normalisierung | `src/engine/metal/qwen.rs:1247`, `metal/qwen38.metal` | MTPLX `GatedResidual` und `hc_read_v3`; Formgrenzen, Fusions- und Rundungsstellen nicht lückenlos durchgetestet. | T/O · P09 |
|
||
| GDN Prefill / Decode / Verify | `src/engine/metal/qwen.rs`, `encode_gdn_conv_norm_rows` | Große Conv/Norm-Prefills nun zeilenparallel mit referenzgleichen BF16-Grenzen; modellfreier Boundary-Test exakt. Delta-Threadgeometrie und vollständige Layer-/State-Parität weiter offen. | T/M · P06 |
|
||
| Router / MoE / Shared Expert | `src/engine/metal/qwen.rs:2738`, `:2826`, `:2919` | Rust sortiert ab S=5, MTPLX bei ≥64 Routen (bei top-10 ab S=7). Rust Prefill gate/up getrennt, aktive MTPLX-Fusionsklasse gemeinsam. | Q/T · P07 |
|
||
| QSA / KV / FlashAttention | `src/engine/metal/qwen.rs:2134`, `:2551` | Rust baut dichte KV-Stagingansichten erneut auf; F16-Flash-Staging versus BF16-Referenzpfad. Sparse-Grenzen und tatsächliche Kernel prüfen. | Q/T · P08 |
|
||
| QMV / QMM / Quantisierung | `src/engine/metal/qwen.rs:3178`, `metal/qwen38.metal` | Frühere logische Output-Länge/BF16-Rundung korrigiert. Golden-Test gilt für geprüfte Formen, nicht alle Matmuls. | T · P09 |
|
||
| MTP Draft / Verteilung | `src/engine/metal/qwen.rs:4428`, `:4894` | Rust D3 fest, Referenz unterstützt D1..D5 (Default D3); Rust berechnet Target-Verteilungen für gesamten Verify-Block, MTPLX lazy entlang Acceptance-Pfad. | Q · P11 |
|
||
| MTP Commit / Repair / EOS | `src/engine/metal/qwen.rs:4735` | Rust kann gesamten Kontext scalar replayen; Referenz captured-prefix commit / begrenzte Repair-Pfade. Pending-/EOS-/Cancel-Zustände vollständig prüfen. | Q/T · P12 |
|
||
| DeepSeek DSpark | `src/settings.rs`, `src/engine/metal.rs` | Default Confidence war 0,8 statt DS4 Metal 0,6. Jetzt lokal korrigiert, einschließlich temperaturabhängigem Exact-Default; End-to-end-Messung offen. | Q/T · P13 |
|
||
| GLM MTP | `src/engine/metal/glm.rs:1788`, `src/engine/metal.rs:4531` | Rust akzeptiert über einzelne Target-Forwards, DS4 verifiziert kompatibles Paar im 2-Row-Batch. Sampled Dispatch ist opportunistisch, nicht exact. | Q · P14 |
|
||
| DS/GLM Prefill / Power | `src/engine/metal.rs:3910`, `src/engine/metal/glm.rs:4596` | DS4 hat echte Keepalive-Commit-Grenzen; GLM-Rust Flush hängt an `read_logits && rows>8`, Referenz zusätzlich an Progress-/Stage-/Kontextbedingungen. | Q/O · P15 |
|
||
| Metriken / Abschluss | `src/model_eval.rs:327`, `src/app.rs:1354`, `native/metal/ds4_metal.m:1041` | Gleiche native Probe, andere Host-Einbettung. Verifier-Zeit überlappt Repair; Prefill-Zähler nicht referenzgleich; Canary/Profiling können Messung verändern. | M/Q · P04, P16 |
|
||
|
||
## Priorisierte Tasks
|
||
|
||
Für Qwen ist eine Abweichung von der geforderten Kernel-/Funktionsidentität ein
|
||
offener Portierungsbestandteil, unabhängig vom isolierten Geschwindigkeitswert.
|
||
Kein Task wird allein durch einen plausiblen Textoutput oder einen einzelnen
|
||
schnelleren Lauf geschlossen.
|
||
|
||
### P01 — Reproduzierbare Ausgangslage sichern
|
||
|
||
Priorität P0; keine Abhängigkeit; teilweise gesichert, neue Messbaseline offen.
|
||
|
||
**Referenz-Warmup-Abnahme präzisiert (2026-09-06):** Der bestehende MTPLX-Runner
|
||
wartet nun nach `/health.ok` zusätzlich auf `warmup.background.state == done`
|
||
und verwirft fehlgeschlagene/abgebrochene Schritte, bevor er den separaten
|
||
Chat-Warmup einreicht. Zuvor zeigte das archivierte Ready-Receipt noch einen
|
||
laufenden512er Schritt und einen ausstehenden2560er Schritt. Ein sofortiger
|
||
Foreground-Prompt kann diese laut gepinntem Servercode unterbrechen und später
|
||
fortsetzen lassen. Keine Veränderung am MTPLX-Server oder dessen Warmup-Defaults;
|
||
Probe und Fortschritts-/Speicherwatchdog laufen während der gesamten Wartephase.
|
||
Der neue Abschlussbeleg erfasst die vollständige Health-Antwort. Pending/Done/
|
||
Fehlerzustände wurden modellfrei geprüft; neue echte Läufe unter
|
||
`local-eval-results/20260906-qmm-k-tile/`. Unterschiedliche Warmup-Arbeit zwischen
|
||
Produkt und Referenz bleibt zu dokumentieren, nicht als identisch ausgeben.
|
||
|
||
- Fortschritt: Erfolgreiche Qwen-Referenzbelege, Runner/Canary sowie aktueller
|
||
Kern-Quellstand und vorhandenes Release-Binary archiviert. Hashes und Einschränkungen
|
||
stehen im [Snapshot-Manifest](/Users/gb/Projects/DS4Server/local-eval-results/20260905-before-p13/manifest.md).
|
||
Der SHA256 des Binary wurde auch aus dem Archiv erneut verifiziert. Quellstand
|
||
und altes Binary sind ausdrücklich nicht als passender Build ausgegeben.
|
||
Originaldateien unverändert; lokale Ergebnisarchive sind von Git ausgeschlossen.
|
||
|
||
- Vorhandene gültige JSONL-Receipts, Runner und Eingaben dauerhaft unter einem
|
||
lokalen Ergebnisverzeichnis sichern; ungültige Läufe eindeutig ausschließen.
|
||
- Binary-/Kernel-/Source-Diff- und Artefaktidentitäten, Hardware/GPU-Cores,
|
||
Modellparameter, effektive Flags, MTP-Vertragsdaten, Fan-/Thermalzustand festhalten.
|
||
Keine erneuten Modell-Downloads oder unnötigen vollständigen Artefakt-Reads während
|
||
einer Kaltstartmessung.
|
||
- Abnahme: Ein zweiter Lauf kann aus dem Manifest dieselben effektiven Bedingungen
|
||
herstellen. Background-Warmup ist beendet oder ausdrücklich Teil der Kaltmessung.
|
||
Keine Leistungsbehauptung anhand wechselnder ungehashter Arbeitsstände.
|
||
|
||
### P02 — Identische Texte, Tokens und toolfreier Produktpfad
|
||
|
||
Priorität P0; nach P01; teilweise korrigiert.
|
||
|
||
**Plain-Chat-Konfiguration umgesetzt (2026-09-05):** `Config::plain_chat` gilt im
|
||
gemeinsamen UI-/Headless-Systempromptbuilder. Sie entfernt Tool-/Skill-/A2UI-Anteile
|
||
und den eingebauten Coding-Agent-Standardprompt, erhält aber einen benutzerdefinierten
|
||
Systemprompt unverändert. In der UI unterbindet sie außerdem Workspace-/Datums-
|
||
Injektionen, Hooks, Tool-Ausführung, automatische Antwortkorrekturen und Ersttitel.
|
||
Der UI-Default bleibt `false`; die Harness weist ihren Default `--plain-chat on`
|
||
im Start-Receipt aus. Vergleich nur mit einer frischen UI-Session unter
|
||
`plain_chat: true`. Bestehende Chats werden nicht bereinigt. `--plain-chat off`
|
||
ist weiterhin nur ein Prompt-/Inferenzdiagnosepfad, kein Headless-Agent-Executor.
|
||
|
||
Der gemeinsame Prompt-Test über alle Modelloptionen, CLI-Overrides und YAML-
|
||
Roundtrip bestehen. `tools/qwen-chat-reference.py` verwendet den tatsächlichen
|
||
MTPLX-Runtime-Tokenizer-Loader und Server-Encoder `_encode_messages_uncached`, nicht
|
||
einen nachgebauten Jinja-Aufruf. Drei vorbereitete Low-Turns (README-Summary,
|
||
Story, Python; mit fest vorgegebenen Assistant- und Reasoning-Inhalten) stimmen in
|
||
gerenderten Bytes und Token-IDs überein: **2489 / 2541 / 2609 Tokens**.
|
||
Beleg: `local-eval-results/20260905-qmm-loader/plain-chat-reference.json` und
|
||
`plain-chat-tokens-after.log` (einschließlich History-plus-Checkpoint-Append);
|
||
der erste Direktversuch ohne den MTPLX-Tokenizer-
|
||
Wrapper scheiterte und ist kein Referenzbeleg. Es wurde kein Modell generiert.
|
||
Das ist kein Beweis für alle live erzeugten Historien oder für DS/GLM. P02 bleibt
|
||
bis zur entsprechenden Frontend-/Referenzabnahme offen; alte Agent-Prompt-
|
||
Performanceläufe dürfen nicht mit neuen Plain-Chat-Läufen vermischt werden.
|
||
|
||
**Echte erzeugte Historien nachgeprüft (2026-09-05):** Der Fixture-Exporter
|
||
akzeptiert nun `--source-run`. Für die abgeschlossenen Plain-Chat-AR- und
|
||
MTP-Rust-Läufe stimmen Rust-Vollrendering und der tatsächliche MTPLX-Server-Encoder
|
||
in Bytes/Token-IDs sowie re-encodierter History-plus-Continuation überein.
|
||
AR: 2617/3056/4242; MTP: 2617/3042/4030 Tokens; beide Release-Tests bestanden.
|
||
Die live fortgesetzten Rust-Checkpoints meldeten dagegen 2617/3054/4238 und
|
||
2617/3041/4028. Das ist noch kein Beleg für identische live Tokenfolgen: erhaltene
|
||
Generationstokens versus erneut gerenderte/encodierte History müssen an der
|
||
konkreten Grenze verglichen werden; nicht ungeprüft als BPE-Effekt abtun.
|
||
Beleg: `local-eval-results/20260905-plain-reference/manifest.md`.
|
||
|
||
**Live-Request-Anbindung und reproduzierter Turn-Abschlussfehler (10.09.):**
|
||
Der kanonische Drei-Turn-Test ruft nun `LiveSession::generate` mit tatsächlichen
|
||
`ChatTurn`-Nachrichten und `TurnSettings` auf. Eingefrorene Prompt-IDs sind nur
|
||
noch Assertions, nicht die Eingabe an den Executor. Der Owner hält abgeschlossene
|
||
und Prefill-Snapshots getrennt; Abbruch vor/nach Streaming, Observer-Fehler und
|
||
Text-Stopp laufen durch diesen Owner. Ein CPU-Check prüft AR-/MTP-Übernahme von
|
||
Sampler, Seed und Kontext-/Ausgabelimit bei unveränderter Backend-Policy.
|
||
|
||
Der erste überwachte AR-Lauf scheiterte nach einer exakt referenzgleichen Summary
|
||
an Turn 2: Produktprompt 3410 statt 3411 Tokens, erste Differenz an Position 3383.
|
||
Der gespeicherte EOS-Token 248046 war vorhanden, der Template-Zeilenumbruch 198
|
||
vor dem nächsten User fehlte. Vorherige History-Append-Tests starteten mit erneut
|
||
gerenderter History, die diesen Zeilenumbruch bereits enthält. Sie deckten die
|
||
echte Decode-Grenze nicht ab. Der Fehlbeleg bleibt erhalten unter
|
||
`local-eval-results/live-session-20260910.9RSmzd/ar.{stdout,stderr}.log`.
|
||
|
||
`engine::render_text_prompt` vervollständigt nun ausschließlich bei einer
|
||
authentifizierten Qwen-Assistant-History den fehlenden Abschluss: unveränderte
|
||
vollständige Template-Grenze, Newline nach MTPLX-EOS oder EOS+Newline nach dem
|
||
skalaren Pre-EOS-Frontier. Generierte Tokens werden nicht neu gerendert und der
|
||
KV-Prefix bleibt erhalten. DS/GLM sind von dieser Verzweigung nicht betroffen.
|
||
Der Metadaten-Regressionstest prüft diese drei Frontiers und den Vollrender-Fallback
|
||
bei ungültigem Tag. Produktiver Controller-/Power-/Checkpoint-Anschluss und die
|
||
vollständige sechsstellige Performance-Abnahme bleiben offen; dies ist noch keine
|
||
Freigabe eines UI-Bundles.
|
||
|
||
**Verifikation dieser Anbindung:** Test-/Produktions-Clippy mit `-D warnings`,
|
||
Release-Testbuild, Format und Diffcheck bestanden. Finale Testbinary-SHA256:
|
||
`d7705551bebd41c5568fef0f11d593d93fd76accda727f347b075079d3b89e70`.
|
||
Logs: `/tmp/ds4-live-session-{clippy,production-clippy,build}.log`.
|
||
Die zwei Request-Checks und der erweiterte Metadaten-/Frontier-Test bestanden
|
||
unter Supervisor `2048 15 15`. Vollmodell AR/MTP unter `81920 30 45`, sequenziell,
|
||
SSD-Ngram, unveränderten Referenz-Flags, Chunk 2048, ohne Power-Drosselung,
|
||
Thinking Low und Seed 0; durchgängiger 100-ms-Canary mit 2-s-Abbruchgrenze.
|
||
Referenzen bleiben `session-chat-20260910.jT3hf5/reference-{ar,mtp}-boundary.stdout.log`.
|
||
Es wurden keine Referenztokens oder Assertions abgeschwächt.
|
||
|
||
Beide vollständigen Chats inklusive Owner-Abbruchprüfungen bestanden, ebenso
|
||
Prompt-/Output-Tokens, Reasoning/Text, Logits-/Hidden-Hashes, Boundary-Snapshots,
|
||
Cache-Fortsetzungen und MTP-Zyklen. AR Prompt/Cached/Output:
|
||
2748/0/635, 3411/3383/1347, 4791/4758/266; MTP:
|
||
2748/0/466, 3242/3214/1394, 4669/4636/326. Die tatsächlichen `TurnSettings`
|
||
(einschließlich f32-Samplerwerte) ändern diese Referenzergebnisse nicht.
|
||
AR: 583 Canary-Proben, keine Fehler/Stalls, Prefill-max 2,532 ms,
|
||
Decode-max 1,022 ms, Peak Physical 82.615.580.104 Bytes; Supervisor 62,241 s.
|
||
MTP: 562 Proben, keine Fehler/Stalls, Prefill-max 4,254 ms,
|
||
Decode-max 1,145 ms, Peak Physical 83.185.055.752 Bytes; Supervisor 58,907 s.
|
||
Rohdaten: `local-eval-results/live-session-20260910.9RSmzd/`,
|
||
`{metadata,request-fixed,ar-fixed,mtp-fixed}.{stdout,stderr}.log`.
|
||
Das sind Canary-beobachtete Funktionsregressionen, keine neue gepaarte Performance-
|
||
Abnahme und kein UI-Eventloop-Nachweis. Der Controller ist weiterhin `cfg(test)`.
|
||
Nichtnull-`min_p` wird vom neuen Request-Adapter ausdrücklich abgelehnt, da der
|
||
MTPLX-Sampler diesen Filter nicht unterstützt; diese Produktoption ist damit
|
||
noch nicht integriert. EngineSettings-/Power-/Persistierungsanbindung bleibt offen.
|
||
|
||
- Qwen-Continuation-Fix bereits vorhanden: initialer Systemprompt nur bei
|
||
Vollrendering, nicht nochmals bei Checkpoint-Append. Regressionstest
|
||
`engine::tokenizer::tests::qwen_checkpoint_continuation_matches_full_conversation`
|
||
ist nach vorherigem Fehler bestanden. Noch kein frischer End-to-end-Nachweis.
|
||
- Test-Konfiguration ohne Skill-/Tool-/A2UI-Anteile über denselben gemeinsamen
|
||
Produkt-Promptbuilder herstellen, keine nur in der Harness geltende Nachbearbeitung.
|
||
Effektive UI-Testkonfiguration und Harness-Konfiguration müssen übereinstimmen.
|
||
- Abnahme: Bytegleicher gerenderter Prompt und gleiche Token-IDs in UI-Headless und
|
||
Referenz pro Turn, einschließlich Assistant-Reasoning, EOS und Template-Marker;
|
||
keine Tools/Skills ausgeführt oder angeboten. Low bleibt modellgerecht.
|
||
- Kleinster vorhandener Check: mit installiertem `DS4SERVER_QWEN38_SOURCE`
|
||
`cargo test --release engine::tokenizer::tests::qwen_checkpoint_continuation_matches_full_conversation -- --ignored --exact`.
|
||
|
||
### P03 — Cache-Arbeit und Chat-Fortsetzung aufklären
|
||
|
||
Priorität P0; nach P02; Ursache der AR-Referenz-Cache-Lücke reproduziert,
|
||
vollständige Cache-/Zeitabnahme weiterhin offen.
|
||
|
||
**Scope-Klarstellung des Nutzers (2026-09-10, maßgeblich für die Integration):**
|
||
MTPLX ist für Qwens Modellausführung in Prefill/Decode, Kernel und Responsivität
|
||
die Referenz. Seine SSD-SessionBank samt CAS-Blobs, SQLite-Manifest, Writer-Queue
|
||
und Eviction muss nicht nachgebaut werden. Für die Persistierung ist auch das
|
||
bewährte DS4-Verfahren Referenz; die vorhandene Rust-KV-Verwaltung wird wiederverwendet.
|
||
Der in diesem Arbeitsschritt begonnene separate `session_store.rs` wurde vollständig
|
||
entfernt, bevor er ausgeführt oder produktiv angebunden wurde. Keine Benutzercaches
|
||
wurden verändert oder gelöscht.
|
||
|
||
Konkrete Integrationsgrenze im aktuellen Code:
|
||
|
||
- `src/engine/kvstore.rs` verwaltet unabhängig vom Modellzustandslayout die
|
||
Checkpoint-Dateien, Prefix-Schlüssel, Budget, Zugriffe und Eviction. Keine zweite
|
||
Datenbank oder zweite Cache-Verwaltung für Qwen einführen.
|
||
- `src/engine/metal/qwen.rs::save_checkpoint/load_checkpoint` implementiert bereits
|
||
den dateibasierten Persistierungspfad mit begrenzten IO-Chunks und Veröffentlichung
|
||
nach `sync_all`/Rename. Das alte FP32-Scratch-Layout ist jedoch kein gültiger
|
||
Ersatz für die BF16-/Recurrent-/QSA-/MTP-Zustände des neuen Executors.
|
||
- `qwen_mtplx/session_cache.rs::SessionSnapshot` und der vorhandene Tensorcodec
|
||
bleiben für die korrekte Zustandsübergabe nutzbar; sie erfordern keine MTPLX-
|
||
Speicherverwaltung. Ein Restore muss dieselben Folgetokens und Zustandsfrontiers
|
||
liefern, ohne zusätzliche Voll-Prefills oder Präzisionskonvertierung im Decode.
|
||
- Priorität hat die produktive Anbindung von `Execution::generate_text` als
|
||
vollständigem Turn an den gemeinsamen UI-/Harness-Pfad. Eine bytekompatible
|
||
MTPLX-SSD-Datenbank ist dafür ausdrücklich keine Voraussetzung mehr.
|
||
|
||
**AR-Auswahlfehler belegt (2026-09-05):** Ein erneuter vollständiger MTPLX-Lauf
|
||
mit `MTPLX_DEBUG_PREFIX_DIVERGENCE=1` reproduziert 5120 gecachte Tokens in allen
|
||
drei Antworten. Inhalt, Reasoning, Finish-Reason und Usage stimmen vollständig
|
||
mit dem alten AR-Lauf überein. Alle Antworten enden mit `stop`, Supervisor exit 0,
|
||
Peak-Footprint 83.78 GB unter der 116.82-GB-Grenze; kein zweiter Inferenzprozess.
|
||
|
||
Die konkrete Kette ist jetzt belegt:
|
||
|
||
1. `generate_ar` sucht unter `mtp_history_policy="cycle"`; der Server speichert
|
||
den finalen Generation-Snapshot unter `"committed"`.
|
||
2. `SessionBank.restore` wählt zuerst den längsten exakten Prefix (bei Story
|
||
7836 Tokens), lehnt dessen Policy ab und versucht keinen kürzeren passenden
|
||
exakten Eintrag (vorheriger Prefill: 7460 Tokens).
|
||
3. Der Near-Prefix-Fallback lehnt **beide** exakten Einträge ab, weil
|
||
`matched >= entry.prefix_len` gilt (`matched_out_of_range`).
|
||
4. Erst der teilweise passende Warmup-Eintrag wird an Recurrent-Grenze 5120
|
||
restauriert. Dasselbe tritt beim Python-Turn mit 8643/7896 Tokens auf.
|
||
|
||
Die Debug-Ausgabe bestätigt `clean prefix` und die Präsenz der größeren
|
||
Kandidaten. Fehlende Session-IDs, fehlgeschlagene Speicherung, Token-Drift oder
|
||
Eviction dieser Kandidaten erklären diesen Befund nicht.
|
||
`tools/mtplx-cache-reference.py` reproduziert die Auswahl mit echten MTPLX-
|
||
Funktionen und leeren Cache-Payloads. Kontrollfall: Nur den inkompatiblen längsten
|
||
Eintrag entfernen; der unveränderte Exact-Restore nutzt dann den gültigen
|
||
7460-Token-Prefix. Kein Modell- oder State-Paritätsbeweis durch diesen Kontrolltest.
|
||
|
||
Belege und Identitäten: [Cache-Diagnosemanifest](/Users/gb/Projects/DS4Server/local-eval-results/20260905-cache-parity/manifest.md).
|
||
Der Golden Master bleibt unverändert. Diese zusätzliche Referenzarbeit wird nicht
|
||
zur künstlichen Verlangsamung in Rust nachgebaut. Die alten Agent-Prompt-Läufe
|
||
sind keine Matched-Work-/2%-Abnahme und dürfen nicht mit der neuen Plain-Chat-
|
||
Baseline vermischt werden. Rest: Save/Restore/Commit-Zeiten und tatsächlich neue
|
||
Tokens in der neuen laufenden Chat-Matrix, einschließlich MTP, erfassen.
|
||
|
||
- MTPLX `generate_ar`/`generate_mtpk`, `restore_or_prefill` und Server-SessionBank
|
||
gegen `Engine`-Checkpoint-Tag, Save/Restore und Pending-Token-Finalisierung verfolgen.
|
||
Die oben belegte AR-Referenz-Auswahlgrenze in Messungen ausdrücklich ausweisen.
|
||
- Produktlauf bleibt ein ongoing Chat. Cache-Strategie nicht heimlich verändern,
|
||
um gleiche Zeiten zu erzeugen. Zusätzlicher Matched-Work-Test mit identischem
|
||
Prefix/Suffix darf die Engine-Kosten isolieren, ersetzt aber nicht den Produktlauf.
|
||
- Abnahme: Für alle drei Turns vollständige Tokens/Reasoning/Cache-Frontiers,
|
||
tatsächlich neu berechnete Tokens sowie Save/Restore-Zeiten; kein unerklärtes
|
||
Re-Prefill, kein vorzeitiges Ende. Warmup gehört nicht zur Chat-History.
|
||
|
||
### P04 — Messvertrag für Responsiveness und Zeitanteile vereinheitlichen
|
||
|
||
Priorität P0; nach P01; Lade-/Canary-Phasenzuordnung korrigiert und im
|
||
Produkt-Runtime-Kontrolllauf geprüft; Gesamt-Messvertrag weiter offen.
|
||
|
||
- Native Canary-Scheduling/Completion, Host-Timer-Verzögerung und echte
|
||
UI-Eventloop-Verzögerung getrennt ausweisen. Die Engine läuft bereits auf einem
|
||
eigenen Thread (`src/runtime.rs:108`); ein weiterer Thread beweist keine GPU-Fairness.
|
||
- Harness-Thread und UI-`Task::perform` benutzen zwar dieselbe native Probe, aber
|
||
unterschiedliche Scheduling-Umgebungen. Blocking Probe nicht als kooperatives
|
||
async-Warten interpretieren. Headless misst ohne GUI keinen tatsächlichen Beachball.
|
||
- Ganze Lebensdauer: Start, Laden, Warmup, Restore, Prefill, erster Token,
|
||
Decode, Save, Abschluss. Phase bei Probe-Start und -Ende erfassen; p50/p95/p99/max,
|
||
Samplezahl, In-flight-Alter und Fehler. Fortschritt nur durch echte Modellarbeit.
|
||
- `run_warmup` startet vor `service.generate` und umfasst damit auch das erstmalige
|
||
Modellladen. `warmup_result.elapsed_ms` und separat gemeldete Ladezeit dürfen
|
||
**nicht addiert** werden. Der Loading-Event wird jetzt ausgewertet; der gemeinsame
|
||
Runtime-Event `Loaded` meldet dieselbe Ladedauer wie die UI-Metriken. Das neue
|
||
`timing` trennt Ladezeit und restliche Request-Zeit, ohne letztere als reine
|
||
Rechenzeit auszugeben. Nicht verfügbare Ladedauer bleibt `null`.
|
||
- Prefill-tok/s = neue Tokens / entsprechende Prefill-Zeit. TTFT und Gesamtzeit
|
||
separat. Draft, Verify, Acceptance, Commit und Repair dürfen sich im additiven
|
||
Zeitbudget nicht überlappen (`note_mtp_verification` umfasst momentan auch Repair).
|
||
- Abnahme: Identischer kleiner Kontrolllauf in UI/Headless mit gleichen nativen
|
||
Messgrößen; künstlicher Host-Stall und GPU-Stall werden unterscheidbar erkannt.
|
||
Canary an/aus A/B quantifiziert Messkosten; optional bleibt sie in der UI.
|
||
|
||
**Teilnachweis Phasenzuordnung (2026-09-05):** Release-CLI neu gebaut, zehn
|
||
`model_eval::tests` bestanden. Ein überwachter Qwen-Plain-Chat-Kontrolllauf bei
|
||
100%, Chunk 2048, Low, MTP aus und Canary an endet natürlich mit `pong` (mit
|
||
führenden Leerzeilen), Supervisor exit 0. Warmup gesamt 12785 ms, davon 8258 ms
|
||
Modellladen und 4526 ms übrige Request-Zeit (separate Abrundung auf Millisekunden).
|
||
140 erfolgreiche Canary-Proben, davon 80 während Loading; eine Probe überschreitet
|
||
eine Phasengrenze und behält beide Phasen. Zeitstempelreihenfolge, Phasenzahlen,
|
||
Zeitzerlegung, Ausgabe, Stop und Speichergrenze wurden per Assertions geprüft.
|
||
Maximale Canary-Completion 3,604 ms; kein erkannter Stall in diesem kurzen Lauf.
|
||
Startphase bleibt die explizite Zuordnung für Per-Phase-Statistiken; Abschluss-
|
||
und Beobachtungszeit werden nicht mehr verwechselt.
|
||
|
||
Beleg: `local-eval-results/20260905-phase-attribution/manifest.md`. Frischer
|
||
Inferenzprozess, **keine** Behauptung eines kalten OS-Dateicaches. Der gemessene
|
||
`pong`-Turn folgt dem separaten Warmup: keine Reproduktion des kalten UI-Pings,
|
||
kein GUI-Eventloop-Nachweis und keine Referenz-/2%-Abnahme. Release-Bundle nicht
|
||
neu gebaut. Restore/Save-Granularität, überlappende MTP-Zeitanteile und die
|
||
übrigen oben genannten P04-Abnahmekriterien bleiben offen.
|
||
|
||
Der Kontrolllauf belegte auch eine weitere Zeitgrenzen-Lücke: letzter
|
||
Decode-Progress bei 1294 ms, Request-Ende bei 1603 ms. `timing.decode_ms=670`
|
||
umfasst diese nachlaufenden 309 ms, während die UI-/Runtime-Rate 49,807 tok/s
|
||
aus dem letzten Token-Progress stammt (`src/engine.rs`, `generation_started`).
|
||
`write_result` beendete die Decode-Zeit erst am `Finished`-Event, das nach
|
||
Checkpoint-Arbeit gesendet wird. Die 309 ms sind **nicht** vollständig als
|
||
Save-Zeit belegt; EOS/Finalisierung/Checkpoint/Host-Zustellung müssen durch echte
|
||
Runtime-Grenzen getrennt werden, nicht aus dem letzten Token geschätzt werden.
|
||
|
||
**Decode-Grenze korrigiert (2026-09-05):** Ein lokaler Timer im gemeinsamen
|
||
`Generator::generate_inner` umfasst den Decode-Loop einschließlich Sampling,
|
||
Token-/Stop-Verarbeitung und Output-Callbacks. Er endet bei jedem Rückkehrpfad,
|
||
auch Fehler/Cancel/Stop innerhalb eines spekulativen Zyklus, vor nachgelagerter
|
||
Pending-Token-Finalisierung und Checkpoint-Arbeit. Keine Kernel-/Sampling-Änderung.
|
||
`MetricsSnapshot.decode_duration_ns` ist dieselbe Quelle für die neue Stats-Zeile
|
||
und Harness-`timing.decode_ms`. Die bisherige Host-Zeitspanne bleibt ausdrücklich
|
||
als `decode_to_request_end_ms` erhalten; historische `decode_ms`-Werte hatten
|
||
noch diese alte Semantik. `decode_loop_tokens_per_second` verwendet die ganze
|
||
Loop-Dauer, `decode_tokens_per_second` weiterhin den letzten UI-Progress-Wert.
|
||
`checkpoint_io` gibt vorhandene gemeinsame Zähler und letzte I/O-Dauern aus;
|
||
letzte Dauer wird nicht als Summe mehrerer Operationen ausgegeben.
|
||
|
||
Vier Metrics-Tests und zehn Harness-Tests bestanden; der neue Regressionstest
|
||
prüft Fehler-Rückkehr, Ausschluss nachfolgender I/O und Reset zwischen Requests.
|
||
Die zeitliche Canary-Zuordnung der nachgelagerten Finalisierung ist dadurch
|
||
noch nicht korrigiert: ein Loop-Zeitwert ersetzt kein Live-Phasenereignis.
|
||
|
||
**Vollständiger Qwen-Kontrollchat AR/MTP:** Summary des eingefrorenen README,
|
||
Story, Python nacheinander als ein Chat, jeweils separater Warmup; 100%, Chunk
|
||
2048, Low, Canary an. Alle sechs Antworten natürlich abgeschlossen, 1/3/5
|
||
History-Nachrichten bestätigt, beide Python-Ausgaben bestehen neun Funktionsfälle.
|
||
Checkpoint-Schreiben pro Turn 341/377/376 ms (AR), 379/474/464 ms (MTP).
|
||
Gemeinsame Loop-Rate und letzte UI-Progress-Rate weichen pro Turn um weniger
|
||
als 0,05% voneinander ab; kein MTPLX-Paritätsnachweis durch diese interne Prüfung.
|
||
Loop-tok/s: AR 48,916/48,367/48,495; MTP 53,976/38,874/61,596.
|
||
Die Story bleibt mit MTP langsamer; Draft-Akzeptanz dort 479/1308 gegenüber
|
||
79/98 bei Python. Unterschiedliche gesampelte Texte/History und aktive Canary:
|
||
keine saubere Performance-A/B-Abnahme, aber die Timing-Korrektur beseitigt diesen
|
||
beobachteten MTP-Rückstand nicht. Canary max AR 102,483 ms / MTP 84,761 ms,
|
||
keine Fehler; kein GUI-Eventloop-Nachweis. Beide Supervisor exit 0, keine
|
||
verbleibenden Modellprozesse. Rohdaten, Hashes, Zeitzerlegung und Grenzen:
|
||
`local-eval-results/20260905-decode-boundary/manifest.md`.
|
||
|
||
Zusatzbefund 2026-09-05: Der vorhandene `DS4SERVER_QWEN38_PREFILL_PROFILE=1`
|
||
beendet/wartet jeden Layer separat und ist **kein transparenter Profiler**.
|
||
Vollständiger AR-Chat mit 100% / 2048 / Low und identischen Prompts: Summary-Prefill
|
||
21,500 s statt 5,291 s im normalen Lauf; ein anschließender normaler Kontrolllauf
|
||
wieder 5,257 s. Alle drei Antworten inklusive Reasoning und Tokenzahlen sind in
|
||
allen drei Läufen exakt gleich. Profiling-Gesamtprozess 91,115 s statt 60,579 s;
|
||
alle Turns trotzdem regulär beendet. Die Layerzeiten dürfen daher nicht als
|
||
Kostenverteilung des normalen Produktpfads ausgegeben werden. Einzelne Diagnose-
|
||
Layer dauern >1 s, obwohl das größte GPU-Command-Buffer-Intervall im Summary nur
|
||
263,579 ms beträgt: GPU-Zeit und zusätzliche Host-/Submission-Kosten trennen.
|
||
Die genaue zusätzliche Kostenursache ist noch offen; keine unbewiesene Zuschreibung
|
||
an Kernel, Cache-Eviction oder thermische Drosselung.
|
||
|
||
Apples installiertes `xctrace` bietet **Metal System Trace**. Eine gezielte
|
||
Aufzeichnung mit dem normalen Qwen-Worker als Attach-Ziel (nicht `--all-processes`)
|
||
wurde gestartet und beim Prozessende automatisch gestoppt. Der Export bestätigt
|
||
allerdings nur **18,114 s am Laufende**: der große Summary-Prefill fehlt. Im
|
||
PID-gefilterten Ausschnitt liegen 871 GPU-Compute-Intervalle der Ebene 0 vor,
|
||
zusammen 12,959 s und maximal 35,604 ms. Das sind Ausführungsintervalle, **keine
|
||
einzelnen Kernelzeiten**; Shader Timeline ist im Standardtemplate deaktiviert.
|
||
Somit noch kein Prefill-Ursachenbeweis. Native Traces müssen früher starten.
|
||
Instruments erfasst trotz Attach auch System-/Prozessmetadaten; Rohtrace und
|
||
Umgebungsdaten bleiben lokal und werden nicht veröffentlicht. Das Tool benötigt für
|
||
seinen Instruments-Cache Rechte außerhalb der Workspace-Sandbox; der erfolgreiche
|
||
Start nach Freigabe ist kein Produktfehler. Diagnosebelege unter
|
||
`local-eval-results/20260905-gdn-delta/qwen-layer-profile.*` und `qwen-metal-trace.*`.
|
||
|
||
Die anschließende **frühe** Aufzeichnung `qwen-metal-early.trace` erfasst 56,838 s
|
||
inklusive des großen Summary-Prefills. Produktparameter unverändert, keine Layer-
|
||
Profiling-Flags. Der vollständige Chat endet mit denselben Antworten und Tokenzahlen
|
||
wie zuvor. Summary-Prefill 5,289 s, Prozess 63,728 s; Canary-Prefill-Maximum 119,609 ms.
|
||
`tools/metal-trace-summary.py` wertet die exportierten XML-Daten inkrementell und
|
||
PID-gefiltert aus; referenzierte Werte, fremde PIDs, verschachtelte Intervalle und
|
||
überlappende Intervalle sind im integrierten Self-Test geprüft.
|
||
|
||
Der große Summary-Buffer `29116535429` spannt im Trace 3848,372 ms auf, davon
|
||
**3831,767 ms überschneidungsbereinigte GPU-Ausführung** (234 Intervalle, längstes
|
||
85,788 ms). Das deckt sich mit dem nativen Harness-Maximum von 3848,390 ms.
|
||
Der nachfolgende Prefill-Buffer enthält weitere 1273,938 ms GPU-Ausführung. Somit
|
||
ist dieser Prefill-Rückstand hauptsächlich GPU-Arbeit, kein gleich langer
|
||
CPU-Eventloop-Stall. Das identifiziert noch keinen einzelnen langsamen Shader.
|
||
Gesamtes Trace-Maximum der GPU-Compute-Intervalle: 117,702 ms; kein Shader-Timeline-
|
||
Profil und keine pauschale UI-Freigabe.
|
||
|
||
Die rohe Instruments-Aufzeichnung belegt ca. 2,7 GiB; die Nachverarbeitung brauchte
|
||
mehrere Minuten und zwischenzeitlich ca. 16 GiB RSS. Deshalb ausschließlich
|
||
optionale Einzel-Diagnose, nicht Teil jedes Harness-Laufs. Rohtrace/TOC bleiben
|
||
wegen enthaltenen System-/Prozessmetadaten lokal. Zusammenfassung:
|
||
[metal-early-summary.json](/Users/gb/Projects/DS4Server/local-eval-results/20260905-gdn-delta/metal-early-summary.json).
|
||
|
||
### P05 — Qwen-Submission-Grenzen am aktiven MTPLX-Pfad ausrichten
|
||
|
||
Priorität P0; nach P02, P04; Produktionsintegration und Abnahme weiter offen.
|
||
Der kanonische Test-Port enthält Encoder-/Taskgrenzen, Streams, Events/Fences
|
||
und jetzt den gemeinsamen Eval-/Async-Eval-Kontrollfluss einschließlich
|
||
Abschluss und Fehler-Cleanup, leere materialisierte Daten/Null-Bindings und
|
||
gemeinsame Array-Ownership anstelle einer externen Materialisierungsliste sowie
|
||
typisierte Shapes vor der Auswertung sowie geteilte Slice-/Broadcast-/Transpose-
|
||
Views mit Byte-Offsets bis zur Metal-/Fast-Fence-Bindung sowie Reshape mit
|
||
geteiltem Backing oder Original-General-Copy sowie AsType-/Dtype-View-Backends
|
||
mit referenzierten Donation-/Layout-Regeln. Lazy-Array-Konstruktoren und
|
||
graph-eigene Payloads einschließlich normalisierter Slice-/Contiguous-Knoten
|
||
führen diese Operationen ohne externe Fixture-Zuordnung
|
||
aus; RMSNorm und der installierte BF16-Affine-Linear-Pfad sind jetzt mit normalen
|
||
Input-/Gewicht-Graphkanten angeschlossen. Dessen Layout-/Offset-Pfade verwenden
|
||
denselben originalen QMV/QMM/Split-K-Dispatcher wie die Modul-Fixtures.
|
||
Die Unary-Payloads Negative/Square/Exp/Sigmoid/Tanh/Sqrt/Rsqrt übernehmen
|
||
ebenfalls die originalen Layout-/Donation-/Dispatch-Regeln.
|
||
Binäre Add/Subtract/Multiply/Divide/Maximum/Minimum/LogAddExp-Payloads samt
|
||
Broadcasting und gemeinsamer vollständiger Dtype-Promotion sind angeschlossen.
|
||
Shared-Expert-MLP ist als zusammenhängender Graph mit echter Split-
|
||
Geschwisteroperation, erfasster compiled SiLU und Down-Projektion verbunden.
|
||
Vollständige QSA-/Modelloperationen fehlen weiter. Prüfstände stehen in den jeweiligen
|
||
Abschnitten; frühere Messungen sind dort nicht ersetzt.
|
||
Weitere Array-Operationen/Promotion, Modellprimitive und
|
||
vollständige Modellanbindung fehlen noch; P05 ist deshalb nicht abgeschlossen.
|
||
P06 verändert auch Encoder-Grenzen; Canary-Messungen allein sind kein isolierter
|
||
Scheduling-Beweis. Details im Abschnitt zum gemeinsamen Eval-/Async-Eval-Ablauf.
|
||
|
||
**Encoder-Zählerdiagnose (2026-09-06):** Optionaler nativer Timestamp-Profiler an
|
||
bestehenden Encoder-Grenzen, ohne neue CBs/Flushes/Waits. Der vollständige Qwen-MTP-
|
||
Chat bleibt text-/token-/acceptance-identisch. 588 Vierzeilen-CBs mit 22.932
|
||
vollständigen Encoder-Spans decken 99,708% ihrer GPU-Zeit ab. Gemischte Layer-Spans
|
||
(37/83 Qwen-Dispatches) tragen etwa 88% der instrumentierten Zeit; das isoliert
|
||
keinen einzelnen Kernel. **Die Zähler verändern die Performance erheblich:**
|
||
Decode 28,684/14,887/21,614 statt zuvor 57,166/37,921/52,799 tok/s. Daher keine
|
||
normalen Kernelkosten oder Referenzparität aus diesem Lauf ableiten. Canary-Max
|
||
141,889 ms, kein echter GUI-Eventloop-Nachweis. Messkosten und verbleibende
|
||
Submission-/Kernel-Ursachen bleiben offen. Vollständige Belege und Prüfkommandos:
|
||
`local-eval-results/20260905-verifier-stage-counters/manifest.md`.
|
||
|
||
- MTPLXs gepinnte Runtime: [device.cpp](https://github.com/ml-explore/mlx/blob/v0.32.2/mlx/backend/metal/device.cpp)
|
||
`needs_commit`/`commit` und
|
||
[eval.cpp](https://github.com/ml-explore/mlx/blob/v0.32.2/mlx/backend/metal/eval.cpp)
|
||
gegen `Commands`, generischen Qwen-Dispatcher, Copy-/Flash-/MTP-Pfade vergleichen.
|
||
Max-Defaults `ops > 50` / `(data_size >> 20) > 50` sind Batching-Grenzen,
|
||
keine Millisekundengarantie. `data_size` zählt Elemente, nicht Bytes.
|
||
- Asynchrone Submissions, Waits, tatsächliche Ressourcen-/Operationszählung,
|
||
In-flight-Ressourcenlebensdauer und Scratch-Wiederverwendung gemeinsam behandeln.
|
||
Weder blind pro Layer blockierend warten noch vorhandene Kapazitätsbytes als
|
||
referenzierte Array-Elemente zählen. Einzelne lange Kernel bleiben P06–P09.
|
||
- Abnahme: Chunk 2048, Power 100, keine künstlichen Sleeps; identische Ergebnisse,
|
||
native Completion-Verteilung im wiederholten Referenzbereich ohne Mehrsekunden-
|
||
Ausreißer. Durchsatz darf nicht zur Bezahlung geringerer Latenz verschlechtert werden.
|
||
Profiling an/aus darf Submission-Politik für die Vergleichsmessung nicht wechseln.
|
||
|
||
### P06 — GDN-Prefill und Verifier vollständig abgleichen
|
||
|
||
Priorität P0; nach P02, P04; Conv/Norm-Boundary korrigiert und gemessen, Gesamt-Task offen.
|
||
|
||
Graphstand 2026-09-07: Der gemeinsame GDN-Forward verbindet Fused-Step,
|
||
Fused-Conv/Verify, Conv1d-Fallback, Output-Fusion und Cache-Fortschreibung
|
||
mit den unveränderten MTPLX-Kerneln; alle 264 Forward-, 130 Staged- und
|
||
24 zusätzlichen Lifecycle-Receipts werden geprüft (siehe „Gemeinsamer
|
||
GDN-Forward, Output-Fusion und Cache-Fortschreibung“). Äußerer Modellablauf,
|
||
Maskenerzeugung, Cache-Batchoperationen, Capture-Commit/Repair und
|
||
Produktintegration bleiben offen. Die
|
||
historischen Detailbefunde unten beziehen sich auf den bisherigen Produktpfad;
|
||
der neue Graph ist weiterhin `cfg(test)` und P06 ist nicht abgeschlossen.
|
||
|
||
- MTPLX `models/qwen4_exp.py:388–664` und installiertes
|
||
`mlx_lm/models/gated_delta.py` gegen `gdn_rows` und die Metal-Kernel
|
||
`kernel_qwen_gdn_conv_norm_rows` / `kernel_qwen_gdn_delta_rows` vergleichen.
|
||
- Ausgangsbefund: Rust Conv/Norm lief mit lediglich zehn 1024-Threadgruppen serial über alle
|
||
Prefill-Zeilen; MTPLX nutzt diese Fusion nur für kleine Breiten, große Prefills
|
||
nutzen Conv1d/Silu/L2 mit anderen Rundungsgrenzen. Die Delta-Rekurrenz selbst
|
||
iteriert in **beiden** Implementierungen über Tokens; das allein ist kein Fehler.
|
||
- Delta: Rust 64 Threads/TG, 32 State-Werte pro Lane versus MLX 128 Threads/TG,
|
||
vier State-Werte pro Lane. Registerdruck, Occupancy und Reduktionsreihenfolge messen.
|
||
- Abnahme: gleiche Eingaben/States für S=1,2,3,4,5,6,7,32,2048 einschließlich
|
||
Chunk-Grenze; Conv-, q/k/v-, Delta- und Output-States gegen aktive Referenz.
|
||
Einzelkernelzeit und komplette Layerzeit mit identischem Warmzustand vergleichen.
|
||
Keine allgemeine Toleranzaufweitung, um abweichende Prefill-Rundung zu kaschieren.
|
||
|
||
#### P06-Teilnachweis: Conv/Norm, 2026-09-05
|
||
|
||
- `tools/qwen-gdn-reference.py` erzeugt ohne Modellladen mit der installierten
|
||
MTPLX/MLX-Umgebung gleiche BF16-Eingaben, Gewichte und Conv-States. Kleine S
|
||
verwenden den tatsächlichen MTPLX-Fused-Kernel; große S bilden die aktive
|
||
Conv1d/SiLU/L2-Operatorfolge ab. Dies ist ein Boundary-Test, kein kompletter
|
||
Modell- oder Delta-Referenzlauf.
|
||
- Vorher: S=1..6 exakt; bei S=2048 **2.383.531 q-, 2.381.323 k- und 6.185.718
|
||
v-Werte verschieden**, maximale absolute Fehler 0,00024414063 / 0,00390625 /
|
||
0,0009765625. Auch S=7 und S=32 schlagen fehl. Conv-States schon vorher exakt.
|
||
- Korrektur: ab S>6 unabhängige Zeilen parallel dispatchen und die BF16-Grenzen
|
||
nach Conv, SiLU, L2 und q-Skalierung erhalten. S<=6 bleibt unverändert.
|
||
Wiederverwendung des vorhandenen GDN-Scratch-Tails für den neuen Conv-State;
|
||
anschließender bestehender GPU-Copy verhindert In-place-Lese-/Schreibraces.
|
||
Keine kleinere Chunk-Größe, Leistungsbegrenzung oder künstliche Pause.
|
||
- Nachher: `qwen_gdn_conv_norm_rows_matches_mtplx` für S=1,2,3,4,5,6,7,32,2048
|
||
mit **null Abweichungen** bei q/k/v und Conv-State, einschließlich In-place-
|
||
State-Übernahme; unveränderte exakte Assertions. Wiederholung nach beiden Chats
|
||
ebenfalls erfolgreich. Das ist keine Aussage über alle möglichen Eingangswerte.
|
||
- Isolierte S=2048-Wall-Mediane, zehn Wiederholungen nach einem Warmup: vorher
|
||
1,935 ms, nachher zunächst 0,757 ms, MTPLX 1,513 ms. Eine spätere Rust-Wiederholung
|
||
nach den Modellläufen liegt bei **1,543 ms**. Host-/Graph-Overhead ist enthalten;
|
||
erhebliche Streuung und nicht kontrollierter thermischer Zustand erlauben daraus
|
||
**keine** belastbare 2%-Abnahme oder garantierten Beschleunigungsfaktor.
|
||
- Wichtig für P05: `Buffer::copy_from` → `ds4_gpu_tensor_copy` beendet den aktiven
|
||
Compute-Encoder und erzeugt einen Blit-Encoder im selben Command Buffer. Damit
|
||
ändert die notwendige sichere State-Übernahme auch Scheduling-Grenzen. Die
|
||
Canary-Verbesserung unten darf nicht allein dem schnelleren Conv-Kernel
|
||
zugerechnet werden. Es wurde kein zusätzlicher Command-Buffer-Flush eingeführt.
|
||
- Belege: [Messmanifest](/Users/gb/Projects/DS4Server/local-eval-results/20260905-gdn-reference/manifest.md),
|
||
[numerischer Wiederholungstest](/Users/gb/Projects/DS4Server/local-eval-results/20260905-gdn-reference/rust-gdn-check.log).
|
||
Offen bleiben vollständige Layer-Outputs, gemeinsame Conv-/Delta-Chunk-States,
|
||
Verifier-/Commit-State-Abgleich und die isolierte Scheduling-Ursache.
|
||
|
||
#### P06-Teilnachweis: Delta-Rekurrenz, 2026-09-05
|
||
|
||
Die andere Thread-Aufteilung ist **kein belegter numerischer Fehler**: der neue
|
||
modellfreie Test `qwen_gdn_delta_rows_matches_mtplx` vergleicht normalisierte,
|
||
deterministisch zufällige BF16-q/k-Eingaben, BF16-v/beta, FP32-g und einen
|
||
nichtleeren FP32-Startzustand mit dem tatsächlich verwendeten
|
||
`mlx_lm.models.gated_delta.gated_delta_kernel`. Der optionale MTPLX-Blocked-Prefill-
|
||
Patch ist im festgehaltenen Referenzlauf nicht aktiviert und wird nicht als
|
||
Golden Master untergeschoben.
|
||
|
||
- S=1,2,3,4,5,6,7,32,2048: Ausgaben und FP32-Endzustände bereits **vor einer
|
||
Kerneländerung exakt identisch**. Die spätere Prüfung umfasst zusätzlich je
|
||
zwei Teilchunks mit In-place-Zustandsfortsetzung (S=2048 → 1024+1024), ebenfalls
|
||
exakt. Ganze und geteilte Ausführung werden jeweils gesondert geprüft.
|
||
- Produktionsdispatch für Prefill/Verify und Capture-Commit lediglich in den
|
||
gemeinsamen Helper `encode_gdn_delta_rows` extrahiert, damit der Test dieselben
|
||
Parameter verwendet. Kernel, Geometrie und Mathematik bleiben unverändert.
|
||
- Isolierter S=2048-Wall-Median: Rust 2,403 ms, Wiederholung 2,366 ms; MLX
|
||
3,382 ms. Das ist inklusive Host-Aufrufkosten, mit sichtbaren Startausreißern,
|
||
und keine ganze Modell-Abnahme. Bei kleinen S liegen Aufrufkosten im Bereich
|
||
von Zehntelmillisekunden; keine pauschale Aussage, jede Größe sei schneller.
|
||
- Die gemessene Rekurrenz liefert damit keinen Beleg für den mehrsekündigen
|
||
Prefill-Rückstand. Kein Umbau auf die Referenzgeometrie allein wegen ihres
|
||
anderen Layouts. Nächster Kostenabgleich: ganze Layer, insbesondere MoE sowie
|
||
Submission-Grenzen (P05/P07), statt spekulativer Rekurrenz-Optimierung.
|
||
- Reproduktion: `tools/qwen-gdn-reference.py <Ausgabepfad> --delta`; Rust-Test
|
||
mit `DS4SERVER_GDN_REFERENCE=<Ausgabepfad>` und `--release --ignored --exact`.
|
||
[Rohbelege](/Users/gb/Projects/DS4Server/local-eval-results/20260905-gdn-delta/delta-reference.json),
|
||
[abschließender Test](/Users/gb/Projects/DS4Server/local-eval-results/20260905-gdn-delta/rust-final-check.log).
|
||
Noch kein vollständiger GDN-Layer-, Controls-, Fused-S1- oder MTP-Commit-Beweis.
|
||
|
||
#### Vollständige Qwen-Produktläufe nach der Korrektur
|
||
|
||
Je ein separater Warmup und anschließend Summary → Story → Python in einem Chat;
|
||
100%, Chunk 2048, Low, Kontext 131072, T=1, p=0,95, k=20, Seed 12345, Canary an.
|
||
Systemprompt und drei rohe Prompts stimmen mit dem archivierten AR-Kontrolllauf
|
||
überein. Die inzwischen korrigierte Tokenisierung reduziert den ersten Prompt von
|
||
7490 auf **7460 Tokens** (wie MTPLX). Cache-Unterschiede bleiben offen (P03).
|
||
|
||
| Modus / Turn | Neue / cached Tokens | Output-Tokens | Prefill s / tok/s | Decode tok/s¹ | Nach-Prefill tok/s² | Gesamter Turn s | Draft-Akzeptanz |
|
||
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||
| AR Summary | 2294 / 5166 | 464 | 5,291 / 433,6 | 47,46 | 45,62 | 15,604 | — |
|
||
| AR Story | 59 / 7924 | 861 | 0,812 / 72,7 | 47,04 | 45,93 | 19,557 | — |
|
||
| AR Python | 72 / 8844 | 91 | 0,858 / 83,9 | 47,50 | 37,89 | 3,260 | — |
|
||
| MTP Summary | 2294 / 5166 | 488 | 5,487 / 418,1 | 53,59 | 51,25 | 15,162 | 307/495 = 62,0% |
|
||
| MTP Story | 59 / 7949 | 640 | 0,832 / 70,9 | 40,20 | 38,92 | 17,280 | 350/869 = 40,3% |
|
||
| MTP Python | 72 / 8649 | 77 | 0,895 / 80,4 | 70,73 | 48,37 | 2,488 | 57/60 = 95,0% |
|
||
|
||
¹ Letzter Engine-Fortschrittswert; schließt nicht alle EOS-/Checkpoint-/Abschlusskosten ein.
|
||
² Completion-Tokens geteilt durch Harness-`decode_ms` bis zum Turn-Abschluss;
|
||
keine reine Kernel-/Steady-Decode-Zeit. P04 muss diese Grenzen explizit zerlegen.
|
||
Alle Output-Tokenzahlen umfassen auch Reasoning/Steuertokens.
|
||
|
||
| Vollständiger Lauf | AR | MTP |
|
||
| --- | --- | --- |
|
||
| Prozess inkl. Load und Warmup | 60,579 s | 59,592 s |
|
||
| Laden / Warmup-Lifecycle inkl. Laden (nicht additiv) | 8,914 / 21,333 s | 9,406 / 24,020 s |
|
||
| Peak Physical Footprint | 84.360.337.288 B | 86.666.337.288 B |
|
||
| Canary Prefill p95 / max | 110,614 / 117,076 ms | 112,441 / 115,618 ms |
|
||
| Canary Decode p95 / max | 3,578 / 15,983 ms | 0,513 / 1,114 ms |
|
||
| Canary Maximum gesamte Laufzeit | 162,362 ms (Warmup) | 145,001 ms (Warmup) |
|
||
| Canary Samples / Fehler | 574 / 0 | 567 / 0 |
|
||
| Supervisor-Maximalverzögerung | 45 ms | 48 ms |
|
||
|
||
Beide Prozesse Exit 0; alle drei Turns `finish_reason=stop`. Keine Rückfragen,
|
||
beide Stories vollständig und kohärent. Summaries decken wesentliche README-Inhalte
|
||
ab; die MTP-Summary enthält allerdings einen falschen DS4-Link (`github.com/ds4`),
|
||
also keine pauschale Behauptung fehlerfreier Inhalte. Beide zuvor gelesenen Python-
|
||
Antworten bestehen elf kleine funktionale Fälle inklusive strikter Schwelle,
|
||
Duplikaten, leeren Listen und unveränderter Eingabeliste; ohne Tools/Netzwerkrechte.
|
||
|
||
Kein beobachteter >2-s-Canary-Stall in diesen beiden Läufen. Die maximale Prefill-
|
||
Canary bleibt dennoch weit über der bereits gemessenen MTPLX-Referenz (AR 2,974 ms,
|
||
MTP 0,550 ms). Mehrsekündige Command Buffer bestehen weiterhin (Summary AR 3,861 s,
|
||
MTP 3,848 s); deren gesamte GPU-Laufzeit ist nicht gleich Canary-Blockierzeit.
|
||
Kein Beleg für die Behebung aller UI-Beachballs und keine Sechs-Zellen-/2%-Abnahme.
|
||
P02 (Skill-Metadaten im Systemprompt), P03/P04 und weitere GDN-/MTP-Pfade bleiben offen.
|
||
|
||
### P07 — Router, sortierte MoE und Shared Expert
|
||
|
||
Priorität P1; offen wegen vollständiger Modellanbindung und Produktmigration. Die bisherigen
|
||
verbundenen SparseMoeBlock-Belege betreffen die ältere Buffer-Ausführung mit
|
||
fusionierten, getrennten und gemischten Expert-/Shared-Modulen sowie aktivierten
|
||
Decode-/Verify-Flags, nicht den vollständigen kanonischen Arraygraph. Dessen
|
||
GatherQMM und jetzt auch SwitchGLU, Routing, die zwei fused-MoE-CustomKernel-
|
||
Knoten sowie der ganze SparseMoeBlock sind an den kanonischen Arraygraph
|
||
angeschlossen (2026-09-09, siehe folgenden Nachweis). Decoder und äußerer
|
||
Modellgraph und MTP-Head sind inzwischen verbunden; vollständige Compile-Fusion,
|
||
Gewichts-/Serving-Anbindung und Produktionsmigration bleiben offen.
|
||
Keine Produktabnahme.
|
||
|
||
**Decoder-Verbindung 2026-09-09:** `qwen_mtplx/decoder.rs` setzt
|
||
`qwen4_exp.py:3741` (`DecoderLayer`) mit den bestehenden Arraygraph-Modulen um:
|
||
optional PLE plus Residual, Attention-Hyper-Connection, GDN beziehungsweise QSA,
|
||
BF16-Multiply/Reshape/Add, MLP-Hyper-Connection, SparseMoeBlock und erneutes
|
||
Multiply/Reshape/Add. GDN-, QSA- und PLE-Caches werden an ihre bestehenden
|
||
Implementierungen durchgereicht. Keine zusätzlichen Eval-/Wait-Grenzen,
|
||
keine neuen Kernel, keine Änderung von Power oder Prefill-Chunks.
|
||
|
||
Zwei gezielte Tests bestanden unter `test-supervisor 2048 15 15`:
|
||
|
||
- CPU-Graphprüfung: Residual behält BF16, getrennte Multiply-/Add-Knoten,
|
||
Broadcast-Geometrie und ursprünglichen Hidden-Input; keine Auswertung.
|
||
- Verbundener GPU-Smoke: beide Attention-Typen jeweils ohne/mit PLE,
|
||
pro Cache fortlaufend 17 Prefill-, 4 Verify- und 1 Decode-Zeile. Analytisch
|
||
bekannte, von null verschiedene PLE-/QSA-Residualbeiträge werden bitgenau
|
||
geprüft; GDN-State-, PLE-Conv-/History-Layouts und QSA-Frontier ebenfalls.
|
||
Die künstlichen Gewichte verwenden zwei Experten und keinen QSA-Indexer.
|
||
Dies ersetzt weder die vorhandenen nichttrivialen Komponenten-Referenzbelege
|
||
noch einen vollständigen Decoder-/Modellvergleich gegen MTPLX.
|
||
|
||
Rohdaten: `local-eval-results/decoder-graph-20260909.pL6JX4/ple.*.log`.
|
||
Dieser ursprüngliche Decoder-Smoke allein deckt den äußeren Modellaufruf nicht ab.
|
||
|
||
**Äußerer Modellgraph und Capture-Commit, 2026-09-09:**
|
||
`qwen_mtplx/model.rs` verbindet nun die aufgerufenen Bausteine gemäß
|
||
`qwen4_exp.py:3778–4134`: dichte/quantisierte Embeddings, optionale übergebene
|
||
Embedding-Zeilen, SSM-Maske aus Padding/Lengths, erstes PLE-Staging vor der
|
||
Layerschleife, originales Tile, Decoder-Kette und finaler Mixer. Das letzte
|
||
Widened-Array bleibt für MTP erreichbar. `emit_logits=false` baut keinen Head;
|
||
`logits_keep` schneidet vor der Head-Projektion. Tied und untied Head verwenden
|
||
die vorhandenen Linear-Operationen.
|
||
|
||
Zusammenhängende GDN-Runs schließen PLE/QSA aus. Ein explizit falscher Wert
|
||
eines der beiden ursprünglichen Compile-Env-Aliase schlägt die AR-Lane-Freigabe.
|
||
S=1–4, keine SSM-Maske und vorhandener Cache sind die Eintrittsbedingungen;
|
||
fehlende Conv-/Delta-Zustände lassen den jeweiligen Run eager ausführen.
|
||
Der vorhandene Replay hält getrennte Traces nach Run, Capture und
|
||
Shape-/Dtype-Signatur; Zustandspaare und sechs Capture-Zeilen pro GDN werden
|
||
in Referenzreihenfolge zurückgeschrieben. Bereits ausgewertete Parameter
|
||
haben nach dem gemeinsamen Evaluator keine Primitive mehr und werden wie in
|
||
`compile_replace` als Konstanten gehalten, nicht als neue Projektionen gebaut.
|
||
|
||
**Compile-Stand 2026-09-09:** Die drei `compile_simplify`-Durchläufe und die
|
||
anschließende `compile_fuse`-Absenkung sind jetzt im Modell-Run-Pfad über
|
||
`trace_compiled` angeschlossen. Acht synthetische GDN-Run-Graphvarianten sind
|
||
inzwischen gegen tatsächliche MTPLX-Traces geprüft (siehe unten); der vollständige
|
||
Vergleich mit echten Gewichten und Dispatch-Sequenzen bleibt offen.
|
||
Der Pfad bleibt `cfg(test)`; weder Serving-Integration noch
|
||
Performance-Parität sind damit behauptet.
|
||
|
||
**Compile-Simplify 2026-09-09:** `qwen_mtplx/compile_graph.rs` bildet den
|
||
DFS-/Parents-Graph und die drei CSE-Durchläufe aus dem gepinnten
|
||
`mlx/compile.cpp:590–800` in Rust ab. Verfügbare Rang-0-Skalare werden über
|
||
Bits plus Dtype zusammengeführt. Äquivalente Primitive verlangen identische
|
||
geordnete Inputs und ursprüngliche Primitive-Parameter; identische Primitive-
|
||
Pointer werden wie in der Referenz ausdrücklich nicht zusammengelegt.
|
||
Frühere Tape-Position gewinnt, spätere globale Ausgaben bleiben geschützt,
|
||
Split-Siblings werden in kanonischer Reihenfolge zusammengeführt und die
|
||
High-Fanout-Gruppierung ab mehr als 100 Parent-Einträgen bleibt erhalten.
|
||
Neue Deskriptoren werden aufgebaut, ohne den eingefangenen Modellgraph oder
|
||
seine Gewichte zu mutieren. Der Modell-Run verwendet inzwischen `trace_compiled`;
|
||
bereits explizit abgesenkte QSA-Graphen verwenden weiterhin `trace`.
|
||
|
||
Slice und SliceUpdate behalten dafür zusätzlich ihre ursprünglichen Stop-
|
||
Parameter im Primitive. Die GPU-Ausführung benötigt diese nicht, aber die
|
||
Referenz-CSE vergleicht sie ausdrücklich: beispielsweise Stop=3 und Stop=4
|
||
bei Stride=2 sind trotz gleicher Werte keine äquivalenten Slice-Primitive.
|
||
CustomKernel erbt in der Referenz die standardmäßig falsche Äquivalenz;
|
||
gleiche Shadertexte allein lösen deshalb keine Zusammenlegung aus.
|
||
|
||
CPU-Graphprüfung bestanden: mehrstufige Zusammenlegung, geschützte Ausgaben,
|
||
Slice-Parameter, Split-Siblings, identische Primitive-Pointer und 110-facher
|
||
Fanout. Der angeschlossene Decoder-/Modell-/MTP-Smoke besteht weiterhin
|
||
beide Tests (`local-eval-results/compile-graph-20260909.WCXIbS/model.*.log`,
|
||
0,28 s, gesampelter Peak 313.705.264 Bytes), einzeln unter
|
||
`test-supervisor 2048 15 15`. Keine Modellgewichte geladen. Diese Prüfungen
|
||
ersetzen nicht den noch offenen vollständigen Compile-/Dispatch-Tracevergleich
|
||
gegen MTPLX und sind keine Durchsatzmessung.
|
||
|
||
Zusätzliche Skalarkonstanten-/Identitätsprüfung bestanden (`simplify.*.log`):
|
||
gleiche NaN-Bitmuster werden zusammengeführt, +0/-0, verschiedene Dtypes und
|
||
Rang-1-Einzelwerte nicht. CustomKernel-Äquivalenz bleibt falsch; ursprüngliche
|
||
Deskriptoren bleiben unverändert. Der abschließende verbundene Lauf am finalen
|
||
Build besteht erneut beide Tests (`final-model.*.log`, 0,27 s, gesampelter
|
||
Peak 313.492.296 Bytes). Release-Testbuild, warnings-denied Clippy, originale
|
||
Shader-Quellprüfung sowie Format-/Diffprüfung bestanden. Kein Bundle erstellt.
|
||
|
||
**Compile-Fuse und dynamische Library-Verwaltung, 2026-09-09:**
|
||
`compile_graph.rs` bildet die Fusionsgrenzen aus `mlx/compile.cpp:805–1028`
|
||
ab: Tiefe 11, Kandidatenlimit 24, Stream-Gleichheit, Schutz globaler Ausgaben
|
||
anderer Form, Mehrfachverbraucher und Broadcast-Splitting. Eine zweite DFS
|
||
ordnet Inputs, Zwischenwerte und mehrere Ausgaben. `fused.rs` erzeugt die
|
||
originalen Metal-Ausdrücke mit dem unveränderten gemeinsamen Funktor-Header.
|
||
Die Shadernamen werden umbenannt; die vollständigen 19 SiLU-Kernelkörper
|
||
stimmen nach ausschließlicher Symbolnormalisierung bytegenau mit dem gepinnten
|
||
Export überein. Der gemeinsame Compiled-Evaluator unterstützt eingebettete
|
||
Konstanten, Rang-0-Inputs und mehrere Ausgaben samt Referenz-Donation.
|
||
|
||
Verschachteltes SiLU, SwiGLU und `compute_g` legen bei Tracer-Eingaben ihren
|
||
Operationsgraph offen, statt bereits abgesenkte Compiled-Primitive einzusetzen
|
||
(`mlx/compile.cpp:1136`). Damit kann der äußere GDN-Run über diese Grenzen
|
||
hinweg nach den Referenzregeln fusionieren.
|
||
|
||
Der erste GPU-Test identifizierte eine Lücke der gemeinsamen Metal-Brücke:
|
||
eine dynamische Library hielt nur ihre zuerst erzeugte Pipeline erreichbar.
|
||
Beim Wechsel von contiguous zu strided fehlte die weitere Funktion.
|
||
`ds4_gpu_mtplx_compile` hält jetzt die Library mit allen ihren Funktionen;
|
||
`ds4_gpu_mtplx_pipeline` erzeugt die jeweils angefragte Pipeline verzögert.
|
||
Die anfängliche, eventuell ungenutzte Pipeline wird nicht vorab erzeugt.
|
||
Die Libraries werden mit dem Metal-Kontext freigegeben.
|
||
|
||
Eine weitere fehlgeschlagene Testassertion betraf **die Test-Erwartung**, nicht
|
||
die Engine: Die Referenz wählt den Compiled-Kernel vor der Ausgabe-Allokation
|
||
anhand von `data_size` (`metal/compiled.cpp:384,419`). Dieser Wert ist bei
|
||
frischen Array-Deskriptoren null. Deshalb muss auch bei 65536 logischen
|
||
Elementen zunächst `_contiguous`, nicht `_contiguous_n`, erwartet werden.
|
||
Der korrigierte Test prüft ausdrücklich den Nullwert, die gewählte Variante,
|
||
die vollständige Gridgröße und sämtliche Ausgabewerte; keine Änderung dieser
|
||
Referenz-Ausführungsreihenfolge.
|
||
|
||
Rohdaten: `local-eval-results/compile-fusion-20260909.K2FLi8/`.
|
||
Alle GPU-Läufe einzeln unter `test-supervisor 2048 15 15`, ohne Modellladen:
|
||
|
||
- `source.stdout.log`: Konstantenschreibweise und alle 19 SiLU-Quellkörper
|
||
bestanden; die beiden GPU-Tests bei diesem CPU-Aufruf ausdrücklich ignoriert.
|
||
- `graph.*.log`: drei Tests für Simplify, Konstantenidentität und Fusion
|
||
bestanden; Mehrfachausgaben, Broadcast-Splitting, äußere Verbraucher,
|
||
verschiedene Streams und Tiefengrenze geprüft.
|
||
- `final-fusion.*.log`: sechs SiLU-Layouts (Rang 1/4/8, positive/negative
|
||
Strides), drei nichttriviale `compute_g`-Fälle (1/4/17 Zeilen) und vier
|
||
Mehrfachausgabe-/Skalarfälle (8/65536 Elemente, eingebettet/nicht eingebettet)
|
||
bestanden. Je Fall eine fusionierte Dispatch; SiLU/GDN bitgleich mit den
|
||
erfassten Originalkerneln, Mehrfachausgaben exakt zum arithmetischen Soll.
|
||
- `silu.*.log`: vorhandener Split-/SiLU-Layout-/Donationstest bestanden.
|
||
- `qsa.*.log`: alle 396 vorhandenen QSA-Compile-Referenzfälle bestanden.
|
||
- `model.*.log`: beide verbundenen Decoder-/Modell-/MTP-Tests bestanden,
|
||
einschließlich Cache-Fortsetzung und Capture-Commit; 314.835.760 Bytes
|
||
gesampelter Peak. Das bleibt ein synthetischer Modelltest.
|
||
|
||
Noch zu prüfen sind vollständige äußere GDN-Run-Traces mit echten Gewichten,
|
||
die Referenz-Cacheäquivalenz der generierten Shader sowie verschachtelte
|
||
Compile-Aufrufe mit ausschließlich partiell getraceten Eingaben. Die kurzen
|
||
Funktionsprüfungen sind keine Messung der UI-Responsiveness oder des
|
||
Modelldurchsatzes. Serving-/Generator-Verbindung und P16 bleiben offen.
|
||
|
||
Release-Testbuild, `cargo clippy --offline --all-targets --all-features -j 1
|
||
-- -D warnings`, originale Shader-Quellprüfung und Format-/Diffprüfung bestanden.
|
||
Cargo meldet weiterhin die bestehende Future-Incompatibility von `block 0.1.6`.
|
||
Keine Downloads, kein Bundle und kein Commit in diesem Arbeitsschritt.
|
||
|
||
**Vollständige synthetische GDN-Run-Graphen und Ausgaben, 2026-09-09:**
|
||
`tools/mtplx-gdn-run-reference.py` ruft die unveränderte ursprüngliche
|
||
`Qwen4ExpTextModel._get_run_fn((0,), capture)` auf. Reale GDN-/HC-Dimensionen,
|
||
zwei kleine MoE-Experten, synthetische Nullgewichte und Hidden=0,125; keine
|
||
Modellgewichte geladen. Acht Kombinationen: S=1/4, Capture aus/an und
|
||
HC-Fusion aus/an. Referenzmodell ausdrücklich `eval()`, Zustände zwischen
|
||
HC-Profilen zurückgesetzt und Compile-Cache beim Flagwechsel geleert.
|
||
|
||
Der vorhandene externe Wächter unterstützt dafür zusätzlich
|
||
`test-supervisor MEMORY_MIB START_SECONDS IDLE_SECONDS --command EXECUTABLE ARGS...`.
|
||
Er startet den Referenz-Pythonprozess direkt, nicht Cargo oder eine Shell.
|
||
Direkte Worker-Argumente werden unverändert übergeben; im Rust-Testmodus bleiben
|
||
die bisherigen Testargumente erhalten. Die zwei CPU-Selbsttests prüfen beide
|
||
Aufrufarten sowie Speicher-/Start-/Fortsetzungsabbruch und Fehlerbehandlung.
|
||
Speichertelemetrie gilt weiterhin nur für den direkten Worker, nicht einen
|
||
beliebigen Prozessbaum. Alle nachstehenden GPU-Läufe einzeln mit 2048 MiB und
|
||
15 Sekunden Start-/Fortsetzungsgrenze, ohne Gesamtzeitlimit.
|
||
|
||
Rohdaten: `local-eval-results/gdn-run-20260909.xTGA2h/`.
|
||
`reference.jsonl` ist **kein gültiger Inferenzbeleg**: beim ersten Export fehlte
|
||
`model.eval()`, wodurch der Training-Rekurrenzpfad gewählt wurde.
|
||
`hyper-profiles.jsonl` enthält die acht gültigen Original-Inferenzbelege;
|
||
`tests/fixtures/mtplx-gdn-runs.jsonl` hält deren Formen, Ausgabe-Hashes und
|
||
Graphverträge ohne die umfangreichen DOT-Texte.
|
||
|
||
Der Vergleich identifizierte zusammenhängend folgende Abweichungen:
|
||
|
||
- GDN-Q-Skalierung und HC-Inject: Python `scalar * array` läuft durch
|
||
`array.cpp:631::__rmul__` und erzeugt `multiply(array, scalar)`. Rust hatte
|
||
Scalar zuerst. Gleiche Arithmetik, aber andere Broadcast-/Fusionsreihenfolge.
|
||
Beide Aufrufstellen sind korrigiert; andere Scalar-first-Operationen wie
|
||
C++-`isclose`, Reverse-Power und Reverse-Divide bleiben referenzgerecht.
|
||
- Nichtfusioniertes HC: die Matmul-Factory erzeugte `Reshape` statt der
|
||
ursprünglichen Primitive `Flatten` und `Unflatten` (`ops.cpp:3515,3533`).
|
||
Beide Identitäten samt CSE-Parametern sind jetzt erhalten. Wie im Original
|
||
benutzen beide denselben Reshape-View-/Copy-Evaluator, keine neuen Kernel.
|
||
- Der Graphvertrag unterscheidet nun auch `Broadcast` und `AsType` innerhalb
|
||
von Compiled-Namen. Die Emitterschreibweise bleibt unverändert; eine
|
||
Normalisierung, die diese Unterschiede verstecken würde, findet nicht statt.
|
||
|
||
Ergebnisse am korrigierten Build:
|
||
|
||
- `final.*.log`: beide verbundenen Decoder-/Modelltests bestanden; alle acht
|
||
ursprünglichen GDN-Graphvarianten stimmen überein. HC-fusioniert 60–70,
|
||
unfusioniert 97–107 Primitive, je 3 oder 9 Ausgaben.
|
||
- `numeric.*.log`: derselbe Test zusätzlich mit **allen** Hidden-/Conv-/Delta-
|
||
und sechs Capture-Ausgaben pro Capture-Fall. Formen und Float32-SHA256
|
||
bytegenau zur Referenz, beide Tests bestanden (0,35 s Testzeit,
|
||
315.458.424 Bytes gemessener Peak-Footprint). Der zusätzliche wiederholte
|
||
Ein-Zeilen-Aufruf prüft auch Fortsetzung nach Capture.
|
||
- `dense.*.log`: 114 Matmul-Fixtures in jeweils beiden Prepare-Modi bestanden,
|
||
Peak 203.277.080 Bytes.
|
||
- `compiled.*.log`: vier Tests bestanden, darunter alle 396 QSA-Compile-Fälle,
|
||
nichttriviale GDN-/SiLU-Fusion und 19 ursprüngliche SiLU-Quellkörper;
|
||
Peak 282.493.816 Bytes. Warnings-denied Clippy und originale Shaderprüfung
|
||
ebenfalls bestanden.
|
||
|
||
Grenze des Graphvertrags: er vergleicht Primitive-Namen, geordnete Abhängigkeiten
|
||
und Ausgabe-/Siblingpositionen; konstante Blätter gehen nicht mit ihren Bytes
|
||
ein. Die zusätzlichen Ausgabe-Hashes schließen diese konkrete numerische
|
||
Fixture, nicht beliebige Gewichte oder alle Shaderparameter ab. Die Nullgewichte
|
||
ersetzen keine Modellinferenz und diese Zeiten sind keine Durchsatzbelege.
|
||
Vollständige echte Gewichtsbindung, Generator-/Serving-Anschluss, verbleibende
|
||
Compile-Cache-/Partial-Tracer-Abweichungen und die sechs P16-Messzellen bleiben
|
||
offen. Kein Bundle und kein Commit, keine 2%-Paritätsfreigabe.
|
||
|
||
**Gewichtsbindung: Shard-Loader und alle drei Vorab-Fusionen, 2026-09-09:**
|
||
`qwen_mtplx/weights.rs` lädt wie der ursprüngliche `load_model` die
|
||
`model*.safetensors` als verzögerte CPU-Load-Deskriptoren über den bereits
|
||
vorhandenen Safetensors-Loader. Danach bildet derselbe Vorbereitungspfad
|
||
`_fuse_gate_up_sanitize`, `_fuse_gdn_in_proj_sanitize` und
|
||
`_fuse_qsa_qkv_sanitize` in ihrer Referenzreihenfolge ab. Kein neuer Loader,
|
||
keine zusätzliche Runtime-Bibliothek und keine Gewichts-Materialisierung in
|
||
diesem Schritt.
|
||
|
||
Die Fusionsmetadaten enthalten Bits, Gruppengröße und Split-Positionen für die
|
||
spätere Konstruktion der ursprünglichen Ersatzmodule. Gate/Up wird bei Experten
|
||
entlang Achse 1 und beim Shared Expert entlang Achse 0 verbunden; GDN behält die
|
||
Reihenfolge QKV/Z/B/A. QSA prüft Bias und tatsächliche Packgeometrie, lässt bei
|
||
abweichender Indexer-Packung nur diesen separat und verzichtet ohne Indexer
|
||
auf die gesamte QKV-Fusion. Fehlende Parameter oder nicht unterstützte GDN-
|
||
Bitbreiten behalten den ursprünglichen Pfad. Layer-Indizes außerhalb des
|
||
Modells werden mit Fehler beendet, nicht durch indizierenden Panic.
|
||
|
||
Originalreferenz: MTPLX `e652d55e2652137a4abcf1312357abbf3eb9d692`,
|
||
Unterbau `1f8e74e3f12f31365464a6867c6579f0e9b29d85` / Version 0.32.2.
|
||
`tools/mtplx-weight-fusion-reference.py` ruft die drei unveränderten
|
||
Sanitize-Funktionen auf. Die Modellattrappen stellen ausschließlich die
|
||
gelesenen/ersetzten Modulattribute bereit; sie ersetzen keine Fusionslogik.
|
||
Rohdaten: `local-eval-results/weight-fusion-20260909.pqMBBu/`.
|
||
|
||
- `reference.jsonl` / `rust.*.log`: 18 Varianten bestanden, alle acht
|
||
Schalterkombinationen plus zehn Bias-/Missing-/Mixed-Pack-/Indexer-Fälle.
|
||
Rust lädt echte kleine temporäre Safetensors-Dateien, prüft vollständige
|
||
Namen, Formen, Fusionsmetadaten und sämtliche Float32-Ausgabe-Hashes.
|
||
Schwache Referenzen auf die ursprünglichen Load-Blätter belegen vor Eval,
|
||
dass die Fusion die Quellen erreichbar hält, aber noch nicht materialisiert.
|
||
Testzeit 0,18 s, Peak-Footprint 154.288.872 Bytes.
|
||
- `installed-reference.json` / `installed-rust.*.log`: Header des **aktuell
|
||
vorhandenen vollständigen Checkpoints**, 2.466 ursprüngliche Parameter,
|
||
1.782 vorbereitete Parameter und 144 Fusionen (96 Gate/Up, 36 GDN, 12 QSA).
|
||
Namen/Formen/Dtypes als geordneter Metadaten-Hash und sämtliche Rezepte/Splits
|
||
stimmen mit MTPLX überein. Alle ursprünglichen Blätter und vorbereiteten
|
||
Ausgaben bleiben ohne Daten; aktiver kanonischer Allocator = 0 Bytes.
|
||
Kein Eval des Modellpayloads. Rust-Testzeit 0,07 s, Peak-Footprint
|
||
10.699.424 Bytes; Referenz-Peak 59.720.256 Bytes.
|
||
|
||
Installierter Pfad:
|
||
`/Users/gb/Library/Application Support/de.rfc1437.ds4server/models/qwen3.8-flash-next`.
|
||
Konfigurations-SHA256:
|
||
`826302af9ff3293cfc9975c9a5a96546fa0aa9f0808505adfc30a62fef806965`;
|
||
Index-SHA256:
|
||
`81e77f5b25bb29e25e239ae2f9f324c9cada379ee600441d6c229f1d95a13443`.
|
||
Vorbereiteter Metadaten-SHA256:
|
||
`fb7106c8a24a6dc1073cbc386d57c9e60a9f30858ecf294bd9bba215b1bfa8b8`.
|
||
Dies sind **keine vollständigen Gewichts-Hashes**.
|
||
|
||
Wichtige Artefakt-Präzisierung gegenüber älteren Notizen: In diesen vorhandenen
|
||
Shards sind Q/K/V 4 Bit, der Indexer ist 8 Bit (je Gruppe 64). Deshalb enthalten
|
||
alle zwölf QSA-Fusionen **nur drei Projektionen**; Splits `[12288,12800]`.
|
||
Der ältere Produktpfad prüft diese Packkompatibilität ebenfalls bereits
|
||
(`qwen.rs::attention_input`); der Befund belegt hier keinen neuen Produktfehler.
|
||
Eine frühere Aussage über vier gleichartig gepackte Projektionen darf nicht
|
||
als Eigenschaft dieses aktuellen Artefakts in Messverträge übernommen werden.
|
||
|
||
Alle Prozesse einzeln unter `test-supervisor 2048 15 15`, ohne Modell-Download.
|
||
Abschließender gemeinsamer Lauf am finalen Build (`final.*.log`): beide Tests
|
||
bestanden, 0,20 s Testzeit, Peak-Footprint 154.223.336 Bytes. Zusätzlich geprüft:
|
||
ungültiger Modell-Layerumfang wird vor der ersten Fusion ohne Parameterverlust
|
||
abgewiesen. Release-Testbuild, warnings-denied Clippy sowie Format-/Diffprüfung
|
||
bestanden; kein Bundle und kein Commit.
|
||
Die neuen APIs sind noch Teil des testinternen kanonischen Ports. **Offen:**
|
||
restliches Sanitize/Norm- und Quantisierungsbinding, echte persistente
|
||
Decoder-/MTP-Modulkonstruktion aus diesen Parametern, PLE-Sidecar-Anschluss,
|
||
Generator/Serving und anschließend vollständige Modellmessungen. Die geprüfte
|
||
Ladevorbereitung ist kein Ersatz für diese Integration und keine
|
||
Performance-Paritätsabnahme.
|
||
|
||
**Vollständige installierte Modulbindung und Sidecar-Lebenszyklus, 2026-09-09:**
|
||
`qwen_mtplx/binding.rs` bindet jetzt alle 48 Decoder (36 GDN / 12 QSA),
|
||
beide Hyper-Connections pro Decoder, MoE, PLE auf Layer 1, Embedding,
|
||
Ausgabemixer/-kopf sowie optional den eigenen MTP-Decoder aus dem installierten
|
||
Checkpoint. Bits/Gruppen werden aus der tatsächlichen Modulkonfiguration bzw.
|
||
der ursprünglichen MTP-Packgeometrie bestimmt. Nur die zwei MTP-Pre-FC-Normen
|
||
erhalten den ursprünglichen Float32-`+1`-Schritt mit Rückkonvertierung;
|
||
Trunk-Normen werden nicht erneut verschoben. Fehlende oder ungebundene
|
||
Checkpoint-Parameter führen zu Fehlern. Raw-HF-Sanitize ist ausdrücklich noch
|
||
nicht implementiert und wird nicht stillschweigend als konvertiertes Format geladen.
|
||
|
||
`BoundModel` hält die Gewichtsbank und ihre entlehnten Module dauerhaft zusammen,
|
||
einschließlich veränderlichem Compile-/Staging-Zustand. Dazu wird die bereits
|
||
transitiv vorhandene, unveränderte `self_cell` 1.3.0 direkt verwendet. Kein
|
||
lokaler unsicherer Selbstreferenz-Code und keine Kopie der Gewichtspayloads.
|
||
Der Test prüft unveränderte Moduladresse und erhaltenen Zustand beim Verschieben
|
||
sowie Rückgewinnung der Gewichtsbank nach Freigabe der Module.
|
||
|
||
`TextModel::post_weight_load` verbindet die bestehenden Tabellenfunktionen wie
|
||
MTPLX: Sidecar je PLE-Layer, optional Resident-Anschluss, bestehender SSD-Fallback
|
||
bei gescheitertem Resident-Bind. Die originale Policy verwendet
|
||
`MTPLX_NGRAM_RESIDENT` bzw. ab 160 GiB physischen RAM den residenten Modus.
|
||
Die neue Integrationsprüfung pinnt ausdrücklich SSD-Modus; sie lädt keine
|
||
vollständige Tabelle und behauptet keine neu geprüfte residente Modellinferenz.
|
||
|
||
Referenz: dieselben oben gepinnten MTPLX-/Runtime-Versionen.
|
||
`tools/mtplx-binding-reference.py` konstruiert **die echten unveränderten
|
||
MTPLX-Module** über `load_model(lazy=True, strict=True)` und `attach_mtp`.
|
||
Die Variante `--post-weight-load` ruft zusätzlich die originale Anschlussfunktion
|
||
und den echten Tabellen-Gather auf. Keine Modellattrappen oder ersetzte
|
||
Referenzfunktionen. Fixtures: `tests/fixtures/mtplx-binding{,-sidecar}.jsonl`;
|
||
Rohdaten: `local-eval-results/binding-20260909.ikUh5D/`.
|
||
|
||
- Vier Varianten, alle drei Fusionen gemeinsam aus/an × MTP aus/an:
|
||
2.466 / 1.782 / 2.524 / 1.840 Parameter und 626 / 398 / 639 / 411
|
||
quantisierte Module. Sämtliche Namen/Formen/Dtypes und Packrezepte exakt;
|
||
beide MTP-Normausgaben als Float32-SHA256 exakt.
|
||
- Sidecar in allen vier Varianten auf Layer 1, nicht resident, Prefetch an,
|
||
ursprüngliche abgerundete Hot-Cache-Kapazität 1023 MiB. Vier echte Lookup-Zeilen
|
||
`[0,1,255,1]`, Form `[4,160]`, vollständiger Float32-SHA256 exakt.
|
||
AR-Pipeline-Freigabe bleibt wie im Original ohne residente Tabelle `false`.
|
||
- Finaler Rust-Test (`final.*.log`) bestanden, 0,12 s Testzeit. Alle übrigen
|
||
Modellparameter bleiben ausdrücklich ohne materialisierte Daten.
|
||
Benachbarte Fusionsprüfungen: zwei Tests bestanden, 0,17 s;
|
||
Tabellen-Routingprüfung bestanden, 0,06 s. Release-Testbuild, gezieltes
|
||
warnings-denied Clippy für Tests und Format-/Diffprüfung bestanden.
|
||
- Referenz und Rust ausschließlich einzeln unter externem
|
||
`test-supervisor 2048 15 15`. Bei diesen sehr kurzen Prozessen sind die
|
||
100-ms-Ressourcenstichproben kein lückenloser Peak-Nachweis. Keine neuen
|
||
Downloads, kein Bundle und kein Commit.
|
||
|
||
**Verbleibender kritischer Integrationspfad:** originale Trunk-Materialisierung
|
||
einschließlich Parameterbaum-/Eval-Reihenfolge; dauerhafter Engine-/Session-Besitz
|
||
mit dem neuen BoundModel; Generator/Sampler mit AR- und spekulativen Pfaden;
|
||
Anschluss an den gemeinsamen UI-/Headless-Runtimepfad. Der kanonische Port ist
|
||
weiterhin `cfg(test)`; das produktive `QwenExecutor` verwendet weiterhin den
|
||
alten FP32-Scratch-Pfad. Deshalb wird dieser Abschnitt **nicht** als behobenes
|
||
UI-Performanceproblem oder Abschluss von P16 gewertet. Die sechs vergleichbaren
|
||
End-to-End-Messzellen und die 2%-Abnahme aller drei Modelle bleiben offen.
|
||
|
||
**Parameterbaum-/Eval-Reihenfolge, 2026-09-10:**
|
||
Die echte MTPLX-`Module.parameters()`-Traversal wurde jetzt zusätzlich erfasst
|
||
(`tools/mtplx-binding-reference.py --parameter-order`). Sie verwendet die
|
||
Einfügereihenfolge der Module; auch der Python/C++-`tree_visit` vor `mx.eval`
|
||
sortiert Dictionary-Schlüssel nicht. Die Rust-Bindung zeichnet deshalb die
|
||
ursprüngliche Modul-Konstruktionsreihenfolge auf, statt die alphabetische
|
||
`BTreeMap`-Reihenfolge als Auswertereihenfolge zu verwenden:
|
||
|
||
- GDN: Conv, unverknüpfte Eingangsprojektionen, dt_bias, A_log, Norm, Ausgang;
|
||
der Sanitize-Ersatz `in_proj_fused` wird wie im Original hinten angefügt.
|
||
- QSA: Q/K/V einschließlich jeweiligem Bias, Ausgang, Q/K-Normen, Indexer;
|
||
`qkv_fused` ebenfalls nach den verbleibenden ursprünglichen Kindern.
|
||
- MoE: Router, SwitchGLU, Shared Expert, Shared Gate. Das nicht fusionierte
|
||
Shared-MLP konstruiert Gate/Down/Up, SwitchGLU dagegen Gate/Up/Down.
|
||
- MTP: Embedding-Norm, Hidden-Norm, Embedding-FC, Hidden-FC, Decoder, Mixer.
|
||
|
||
`TextModel.parameter_order` hält diese Reihenfolge über die Lebensdauer der
|
||
Modulbindung. `Bank::materialize` reicht die benannten Wurzeln gemeinsam an
|
||
den vorhandenen synchronen Graph-Auswerter weiter; keine Einzel-Evals pro
|
||
Gewicht, zusätzliche Gruppierung oder neue Datei-Ladelogik. Fehlende Namen
|
||
werden vor dem Eval abgewiesen. Der vorhandene Bindungstest prüft jetzt die
|
||
vollständigen geordneten Namen gegen die vier originalen SHA256-Belege in
|
||
`tests/fixtures/mtplx-binding-order.jsonl`. Er übt den Materialisierungspfad
|
||
an den zwei echten MTP-Normen aus, nicht am gesamten 72.640.204.792-Byte-Trunk.
|
||
|
||
Belege im bestehenden Rohdatenverzeichnis `binding-20260909.ikUh5D`:
|
||
`reference-order.jsonl` enthält die vollständigen Namen, `order.*.log` den
|
||
bestandenen Rust-Lauf (vier Varianten, 0,16 s Testzeit). Die zwei verbundenen
|
||
Decoder-/Cache-Regressionstests bestanden ebenfalls (`order-decoder.*.log`,
|
||
0,47 s). Die Prozesse liefen
|
||
einzeln unter `test-supervisor 2048 15 15`; keine vollständige Gewichts- oder
|
||
N-Gram-Tabellenmaterialisierung. Release-Testbuild, warnings-denied Clippy für
|
||
Tests sowie Format-/Diffprüfung bestanden. Kein Bundle, kein Commit.
|
||
Die zuvor offene Reihenfolge ist damit belegt und der gemeinsame Auswertepfad
|
||
implementiert. **Noch nicht belegt:** vollständige Trunk-Materialisierung,
|
||
produktiver Executor-/Generator-Anschluss und die sechs End-to-End-Messzellen.
|
||
Dieser Befund ist kein Durchsatz- oder UI-Responsiveness-Nachweis.
|
||
|
||
**Vollständiger Trunk und fortlaufender Ping, 2026-09-10:**
|
||
`qwen_mtplx::execution::Execution` hält jetzt BoundModel, Streams und den
|
||
modellweiten Cache dauerhaft. Der nicht-lazy Lader materialisiert den gesamten
|
||
Trunk in der originalen Parameterreihenfolge und schließt den SSD-Sidecar an.
|
||
`forward` baut denselben Modellgraphen auf; `logits_f32` verwendet den vorhandenen
|
||
Auswerter. Dieser Ausführungspfad bleibt bis zum Generator-/Produktanschluss
|
||
`cfg(test)`, nicht der produktive QwenExecutor.
|
||
|
||
Der erste echte Forward deckte eine fehlende Spezialisierung auf:
|
||
`QuantizedEmbedding` indiziert gepackte U32-Gewichte mit I32-Token-IDs. Der
|
||
Rust-Gather wies diese Kombination bislang ab. Der Export enthält nun auch
|
||
U32/I32 und F16/I32 für Front-Gather und den allgemeinen Gather-Wrapper;
|
||
die gepinnten Kernelkörper sind unverändert. Der bestehende Layouttest prüft
|
||
beide Kombinationen mit negativen Indizes und zusammenhängenden/strided
|
||
Quellen. Bestanden unter `test-supervisor 2048 15 15`; Export-Identität ebenfalls
|
||
bestanden. Keine Cast-Umgehung im Embedding, keine kleinere Testform.
|
||
|
||
Rohdaten: `local-eval-results/execution-20260910.Ngpzu7/`.
|
||
`tools/mtplx-execution-reference.py` verwendet den tatsächlichen Server-Encoder
|
||
für Ping/Thinking-low, `load_model(lazy=False, strict=True)`, den originalen
|
||
Modellaufruf und persistenten Cache. `--decode` folgt für diesen numerischen
|
||
Oracle greedy bis zum natürlichen EOS; es ersetzt nicht den Serving-Sampler.
|
||
`--server-defaults` übernimmt die zwölf Einstellungen unmittelbar aus
|
||
`_server_runtime_env_overrides` (Qwen-Familiendefaults, nicht zusätzlich ein
|
||
generisches Serverprofil). Die Rust-Paarläufe verwendeten dieselben Werte.
|
||
|
||
| Numerischer Vollmodell-Lauf | Exakt geprüfte Logit-Reihen | Canary max MTPLX / Rust | Ergebnis |
|
||
| --- | --- | --- | --- |
|
||
| Direkte Modell-Defaults (`reference-decode` / `canonical-decode`) | 41 Prefill + 56 Decode, je 248.320 Float32-Werte | 4,053 / 4,853 ms | alle SHA256 und Argmax gleich, natürliches EOS; Antwort „Pong! …“ |
|
||
| Qwen-Server-Familiendefaults (`reference-server` / `canonical-server`) | 41 Prefill + 46 Decode, je 248.320 Float32-Werte | 3,650 / 3,962 ms | alle SHA256 und Argmax gleich, natürliches EOS; Antwort „pong“ |
|
||
|
||
Alle Vollmodellprozesse liefen **nacheinander** unter `test-supervisor 81920 30 45`:
|
||
80-GiB-Abbruchbudget, Start-/Fortsetzungsgrenzen statt Gesamtlaufzeitlimit.
|
||
Zusätzlich durchgehende native UI-GPU-Probe (4-KiB-Blit/100 ms), Testabbruch bei
|
||
2-s-Probenstall oder Probe-Fehler. Python verwendet den aus der vorhandenen
|
||
ObjC-Brücke gelinkten Canary; Rust den vorhandenen model-eval-Monitor.
|
||
Keine Canary-Fehler oder unvollständigen Proben. Höchster Lifetime-Peak im
|
||
Familienpaar: Referenz 76.258.077.296 Bytes, Rust 75.878.557.624 Bytes.
|
||
Keine neue Modellinstallation. Der anfängliche Referenz-Importfehler wurde durch
|
||
Wiederverwenden der bereits lokalen Python-3.12-Pydantic-Core-Erweiterung
|
||
derselben Version 2.46.4 behoben; Modell- und Runtime-Revision unverändert.
|
||
|
||
Die instrumentierten Kaltzeiten sind **keine Performance-Abnahme**: etwa
|
||
7,734/7,527 s Load, 5,860/5,424 s Prefill und 2,083/2,014 s summierte 46
|
||
Decode-Forwards für MTPLX/Rust im Familienpaar. Reihenfolge nicht alterniert,
|
||
keine sauberen Warmup-Paare, Hash-/Readback-Diagnostik aktiv, kein produktiver
|
||
Sampler/Generator. Die Tests schließen die zuvor offene reale
|
||
Trunk-Materialisierung und diese beiden numerischen Cache-Fortsetzungen;
|
||
nicht UI-Eventloop, spekulativen Generator, laufenden Drei-Prompt-Chat oder P16.
|
||
Release-Testbuild, gezieltes warnings-denied Clippy sowie Format-/Diffprüfung
|
||
bestanden; kein Bundle, Commit oder Push.
|
||
|
||
**Sampler-Anschluss: originaler LogSumExp-Pfad, 2026-09-10:**
|
||
|
||
Der tatsächliche serielle Generator ruft `fast_sampling.py` auf, nicht nur die
|
||
NumPy-Hilfen in `sampling.py`. `_device_serial_support_arrays` normalisiert die
|
||
Top-p-Masse mittels GPU-Float32-`logsumexp` über das gesamte Vokabular und liest
|
||
Kandidaten erst an der gemeinsamen Eval-Grenze zurück. Ein vollständiges
|
||
Host-Readback als Ersatz würde diese Ausführung nicht abbilden.
|
||
|
||
`qwen_mtplx/normalization.rs` ergänzt daher den bislang fehlenden kanonischen
|
||
Last-axis-LogSumExp-Knoten. Rust übernimmt den unveränderten Auswahl-/Layoutpfad
|
||
aus `mlx/ops.cpp` und `mlx/backend/metal/logsumexp.cpp` der gepinnten
|
||
MTPLX-Runtime: Original-`block_logsumexp_*` bis einschließlich 4096 Elemente,
|
||
darüber Original-`looped_logsumexp_*`, originale Threadgroup-Geometrie,
|
||
erforderliche Kontiguitätskopie, physische Zeilenreihenfolge, Ausgabe-Strides,
|
||
kein Input-Donation und keine zusätzliche Synchronisation. Die Kernel kommen
|
||
aus der bereits gepinnten Metallib, nicht aus einer Ersatzimplementierung.
|
||
Die Graph-Vereinfachung übernimmt auch `LogSumExp::is_equivalent`.
|
||
|
||
Rohdaten: `local-eval-results/sampler-primitives-20260910.lnnnAf/`.
|
||
Der vorhandene Original-Fixturegenerator enthält `logsumexp_graph_fixtures`:
|
||
150 Fälle aus drei Datentypen (BF16/FP16/FP32), fünf Achsengrößen
|
||
(1/17/4096/4097/248320), fünf Speicherlayouts und beiden Keepdims-Werten.
|
||
`tests/fixtures/mtplx-logsumexp-graph.jsonl` enthält die direkt gewonnenen
|
||
Float32-Ausgabe-SHA256. Fixture-SHA256:
|
||
`c2e4a855f6f84a355b69e21f1be6fac96a82ac6e0cdeabbddd89260c03c05018`.
|
||
|
||
- Original- und Rust-Läufe jeweils seriell unter `test-supervisor 2048 15 15`,
|
||
keine Gewichte geladen, keine Downloads. Original-Lifetime-Peak
|
||
322.339.608 Bytes; Rust-Lifetime-Peak 213.041.896 Bytes.
|
||
- `mtplx_logsumexp_graph_matches_reference`: alle 150 Hashes exakt,
|
||
Ausgabeformen und Nicht-Donation geprüft, leere Eingaben und skalare Eingaben
|
||
mit Last-axis-Reduktion abgewiesen. Rust-Test 0,73 s; dies ist keine
|
||
Durchsatzmessung. Der erste Rust-Versuch scheiterte kontrolliert an einem
|
||
lokalen RefCell-Borrow bei Ausgabe-Allokation; korrigiert, kein GPU-Hang.
|
||
- `mtplx_compile_simplify_preserves_reference_parent_rules`: bestanden,
|
||
einschließlich Zusammenlegung äquivalenter LogSumExp-Knoten. Der anfängliche
|
||
Aufruf mit unqualifiziertem `--exact` führte null Tests aus und zählt nicht;
|
||
der vollqualifizierte Wiederholungsaufruf führte den Test tatsächlich aus.
|
||
- Release-Testbuild, gezieltes Clippy mit `-D warnings`, Format- und Diffprüfung
|
||
bestanden. Kein Bundle, Commit oder Push; kein Testprozess bleibt aktiv.
|
||
|
||
Dies schließt eine benötigte Sampler-Primitive, **nicht P11 oder P16**.
|
||
Die Kandidaten-GatherAxis-Typkombination und Cutoff-Tie-Selektion sind im
|
||
folgenden Nachweis ergänzt. Offen bleiben originale Host-Normalisierung und
|
||
RNG-Ziehungsfolge, Penalties/Fallback sowie der
|
||
vollständige AR-/MTP-Generator-Anschluss an UI/Harness. Das bereits vorhandene
|
||
NumPy-kompatible PCG64 wird wiederverwendet. Die vollständigen fortlaufenden
|
||
Chat-A/B-Läufe aller drei Modelle mit/ohne Spekulation bleiben ausstehend.
|
||
|
||
**Sampler-Anschluss: deterministische Kandidatenauswahl, 2026-09-10:**
|
||
|
||
`qwen_mtplx/sampling.rs::deterministic_top_k` bildet den vollständigen Graphen
|
||
von MTPLX `fast_sampling._deterministic_mlx_top_k_support` ab: erster
|
||
ArgPartition, Gather der provisorischen Werte, Min-Cutoff, Greater/Equal,
|
||
I32-Summe der strikt höheren Werte, I32-Cumsum der Gleichstände, Auswahl
|
||
kleinerer Vokabular-IDs bis zur Restquote, Where(-inf), zweiter ArgPartition
|
||
und finaler Gather. Alle Operationen bleiben lazy; kein Host-Readback und
|
||
keine zusätzliche GPU-Synchronisation innerhalb des Graphen.
|
||
|
||
Die vorhandenen Reduktions-/Scan-Auswerter werden wiederverwendet:
|
||
Min und I32-Sum nutzen die originalen Reduce-Kernel, Scan übernimmt für
|
||
vier Byte die originalen N_READS=4-Threadgroup-Regeln, für den bisherigen
|
||
I64-NGram-Pfad unverändert N_READS=2. GatherAxis ergänzt BF16/F16/F32/U32 mit
|
||
I32-/U32-Indizes durch Instanziierungen des unveränderten Original-Templates.
|
||
Die Originalquellprüfung bestätigt weiterhin 17 Custom-Körper und
|
||
22 Runtime-Einheiten; kein Kernelkörper wurde für diesen Schritt verändert.
|
||
|
||
Rohdaten: `local-eval-results/sampler-selection-20260910.s0lvxY/`.
|
||
Der vorhandene Original-Fixturegenerator ruft den tatsächlichen MTPLX-Helper
|
||
auf und erzeugt `tests/fixtures/mtplx-sampler-selection.jsonl` mit 48 Fällen:
|
||
Vokabular 17/4097/248320, eine/vier Reihen, Top-k 1/min(20,Vokabular), normales
|
||
Muster, große Gleichstandsgruppen, vollständig gleiche und nichtendliche Werte.
|
||
|
||
- Zusammenhängender Rust-Selektor: **96 Ausgabe-Hashes exakt**, Token-IDs und
|
||
Werte für alle 48 Fälle. Zusätzlich tatsächlich dispatchte Min-/I32-Sum-/
|
||
I32-Scan-Kernel geprüft. Zehn I32-Scan-Fälle decken alle Threadsize-Bereiche
|
||
(17/4096/4097/8192/8193) sowie zeilen-/spaltenkontiguierliche Layouts ab.
|
||
- Bestehende Gather-Regression einschließlich neuer Float-/U32-Kombinationen,
|
||
232 ursprüngliche Summenfälle und ursprünglicher NGram-GPU-Test mit
|
||
120 Referenzfällen plus I64-Scan-/Donation-/Layout-Zweigen: bestanden.
|
||
- Original und Rust ausschließlich nacheinander unter `test-supervisor 2048
|
||
15 15`, modellfrei, ohne Downloads. Original-Selektor Lifetime-Peak
|
||
248.890.040 Bytes; Rust-Selektor 262.374.144 Bytes. Selektortest 1,30 s,
|
||
kein Durchsatzvergleich. Ein anfänglicher Buildfehler in der temporären
|
||
Test-Shape-Bindung wurde vor GPU-Ausführung korrigiert.
|
||
- Release-Testbuild, gezieltes Clippy mit `-D warnings`, Originalquellprüfung,
|
||
Format- und Diffprüfung bestanden; kein Bundle, Commit oder Push.
|
||
|
||
**Keine Umstellung des heißen seriellen Pfads auf diese teurere Auswahl:**
|
||
MTPLX verwendet dort zunächst die M=4k-Kandidatenmenge mit nur einem
|
||
ArgPartition und Host-Sortierung. Der oben portierte Graph wird bei
|
||
Cutoff-Tie-Spill beziehungsweise vom entsprechenden gebundenen Batch-Pfad
|
||
benötigt. Die M=4k-Route und Sparse-Normalisierung/RNG sind im folgenden
|
||
Nachweis verbunden. Die vollständige Generator-Anbindung bleibt ausstehend.
|
||
P11/P16 und die sechs Modell-/Spekulations-A/B-Abnahmen bleiben
|
||
offen; diese isolierten Tests belegen keine UI- oder Gesamtperformance-Parität.
|
||
|
||
**Sampler-Anschluss: serielle M=4k-Route und Sparse-Stochastik, 2026-09-10:**
|
||
|
||
`serial_support` bildet `_device_serial_support_arrays` ab: F32-Cast und
|
||
Temperaturreziprok, ein ArgPartition über M=min(4k,Vokabular), Gather und
|
||
bei aktivem Top-p LogSumExp/Exp, anschließend **eine gemeinsame Auswertung**.
|
||
Das Host-Readback kopiert nur die M ausgewählten Spalten je Reihe, auch wenn
|
||
die Slice einen vollständigen Vokabular-Stride besitzt; kein zusätzlicher
|
||
GPU-Pack oder Full-Vocab-Readback. Host-Lexsort, Top-p-Präfixmasse und
|
||
Cutoff-Spill bleiben unverändert. Nur bei mindestens einem Spill folgt eine
|
||
zweite Auswertung des deterministischen Selektors für alle Reihen; ersetzt
|
||
werden anschließend ausschließlich die Spill-Reihen.
|
||
|
||
Der Sparse-Verteilungspfad übernimmt `_serial_row_distribution`, die zweite
|
||
Normalisierung im `SparseDistribution`-Konstruktor, erste Treffer bei
|
||
Token-Lookups, Vereinigung/Residual und die bedingte Korrekturziehung.
|
||
Kein neuer RNG: vorhandenes `Rng::new_qwen`/PCG64 wird verwendet.
|
||
NumPys [paarweise Summierung](https://raw.githubusercontent.com/numpy/numpy/v2.4.4/numpy/_core/src/umath/loops_utils.h.src)
|
||
und [CDF/Choice-Reihenfolge](https://raw.githubusercontent.com/numpy/numpy/v2.4.4/numpy/random/_generator.pyx)
|
||
wurden gegen Version 2.4.4 geprüft: kumulative Summe, Division durch den
|
||
letzten CDF-Wert, Searchsorted rechts. Eine Punktmasse verbraucht weiterhin
|
||
eine Ziehung; Verify zieht zuerst für Akzeptanz und nur bei Rejection erneut.
|
||
Die BSD-3-Clause-Mitteilung zum Summierungsport steht im Rust-Quelltext; bei
|
||
späterer Produktintegration ist sie auch in die ausgelieferten Lizenzhinweise
|
||
aufzunehmen. Der kanonische Pfad ist weiterhin nur im Testbuild enthalten.
|
||
|
||
Rohdaten: `local-eval-results/sampler-serial-20260910.h4pidl/`.
|
||
|
||
- 108 tatsächliche Original-Helper-Aufrufe: Vokabular 17/4097/248320,
|
||
eine/vier Reihen, Top-p 0,1/0,95/1,0, Temperatur 0,6, k=20 (am Vokabular
|
||
begrenzt), eindeutige Werte, Gleichstandsgruppen, uniforme/scharfe,
|
||
nichtendliche und gemischte Spill-/Nicht-Spill-Reihen.
|
||
- Token-IDs und alle endlichen Float64-Werte bitgenau; NaNs werden in beiden
|
||
Receipts kanonisiert, ihre ungültige Verteilungsmasse bleibt erhalten.
|
||
Die Originalzahl expliziter `mx.eval`-Aufrufe stimmt mit den expliziten
|
||
kanonischen GPU-Commits überein (automatische Primitive-Commits getrennt).
|
||
Der tatsächlich dispatchte Tie-Scan stimmt mit der Original-Fallbackzahl
|
||
überein, nicht nur mit einer vorhergesagten Verzweigung.
|
||
- 252 daraus erzeugte Sparse-Verteilungen: normalisierte Float64-Werte und
|
||
8.064 gewöhnliche Tokenziehungen exakt. Dazu 8.064 Verify-Entscheidungen,
|
||
davon **7.559 Akzeptanzen und 505 Korrekturen**, einschließlich exakter
|
||
Akzeptanzmassen und Residual-Verteilungen. Je Sequenz ist der nächste
|
||
PCG64-Wert ebenfalls exakt; keine versteckten zusätzlichen RNG-Ziehungen.
|
||
- Alle drei `mtplx_sampler_`-Tests gemeinsam bestanden, 0,44 s Testdauer,
|
||
Lifetime-Peak 258.835.224 Bytes. Original-Support-Peak 355.943.216 Bytes,
|
||
ursprüngliche CPU-Verteilungsprüfung 87.933.600 Bytes. Alle Läufe seriell
|
||
unter `test-supervisor 2048 15 15`, keine Modelle/Downloads.
|
||
- Release-Testbuild, gezieltes Clippy mit `-D warnings`, Format-/Diffprüfung
|
||
bestanden; kein Bundle, Commit oder Push. Reine Diagnostikzeiten, keine
|
||
Aussage zu Modell-Token/s oder UI-Latenz.
|
||
|
||
**Sampler-Anschluss: Dense-Verteilung und Bad-mass-Fallback, 2026-09-10:**
|
||
|
||
`dense_probabilities` übernimmt den Host-Float64-Pfad `softmax` und
|
||
`apply_top_p_top_k`, einschließlich deterministischer Top-k-Gleichstände,
|
||
Top-p-Präfixmasse und erneuter Normalisierung auch ohne aktive Filter.
|
||
Die abschließende paarweise Summierung behält die Nullpositionen des vollen
|
||
Vokabulars bei. Der plurale GPU-Einstieg `sparse_distributions` übernimmt die
|
||
serielle Route und liest volle Host-Logits erst bei der ersten ungültigen
|
||
Reihe; weitere ungültige Reihen verwenden diesen Readback wieder.
|
||
Der originale Sparse-Fallback liefert bei ungültiger Host-Masse Token 0;
|
||
der gewöhnliche Dense-Pfad meldet dagegen einen Fehler. Greedy oder
|
||
deaktiviertes Top-k liefern am pluralen Einstieg unverändert `None`.
|
||
|
||
Rohdaten: `local-eval-results/sampler-fallback-20260910.Csse1Y/`.
|
||
150 Originalfälle (30 GPU-Batches mit je vier Reihen und 120 Dense-Fälle)
|
||
stimmen überein: Sparse-IDs und Float64-Bits vollständig, Dense-Werte über
|
||
den vollständigen Float64-SHA256 beziehungsweise denselben Fehlerzweig.
|
||
Vokabular 17/4097/248320, uniforme/scharfe/eindeutige/nichtendliche/gemischte
|
||
Reihen, Top-p 0,95/1, Top-k 0/20, Temperatur 0/0,6.
|
||
Alle vier bisherigen Sampling-Tests gemeinsam bestanden (0,68 s);
|
||
Lifetime-Peak Rust 276.022.040 Bytes, Original 356.614.984 Bytes.
|
||
Beide seriell unter `test-supervisor 2048 15 15`, ohne Modell oder Download.
|
||
Release-Testbuild und gezieltes warnings-denied Clippy bestanden.
|
||
Keine Kernelkörper geändert. Das ist noch kein vollständiger
|
||
`_sample_from_logits`-Einstieg: Dense-Tokenziehung, Penalties und die
|
||
eigentliche Generator-Verbindung sind davon getrennt.
|
||
|
||
**Sampler-Anschluss: originaler GPU-Argmax, 2026-09-10:**
|
||
|
||
Der vorhandene Reduktionsbaustein enthält jetzt `ops.cpp::argmax(axis)` und
|
||
`metal/primitives.cpp::ArgReduce::eval_gpu`. Der Aufruf verwendet unverändert
|
||
`argmax_bfloat16`/`argmax_float16`/`argmax_float32` aus der gepinnten Metallib,
|
||
keinen nachgebauten Kernel. Achsen-/Input-/Output-Strides, Scalar-Platzhalter,
|
||
uint32-Ausgabe und Dispatch entsprechen dem Original (vier Elemente je
|
||
Thread, Rundung auf 32, Begrenzung durch die tatsächliche Pipeline).
|
||
Singleton-Achsen liefern den originalen Zeros-Pfad; andere Eingaben werden
|
||
weder für die Reduktion kopiert noch als Output-Allokation gespendet.
|
||
Die CSE-Äquivalenz enthält die Reduktionsachse wie im Original.
|
||
|
||
Rohdaten: `local-eval-results/sampler-argmax-20260910.nHvwG6/`.
|
||
480 Originalvergleiche mit BF16/F16/F32, Achsenlängen
|
||
1/17/4096/4097/248320, keepdims an/aus, nichtendlichen Werten und
|
||
Gleichständen. Acht Layouts: gewöhnlich, transponiert, strided, Offset,
|
||
Broadcast, Vektor, Mittelachse und negative Strides. Alle uint32-Outputhashes
|
||
und Formen exakt; für jede nichttriviale Reduktion genau ein Originaldispatch
|
||
mit passender Grid-/Threadgroup-Geometrie, ohne zusätzliche Copy oder Sort.
|
||
Alle fünf damaligen Sampling-Tests gemeinsam bestanden (1,90 s),
|
||
Rust-Lifetime-Peak 283.820.776 Bytes, Original 322.323.200 Bytes.
|
||
Serielle modellfreie Läufe unter dem externen 2-GiB-/15-s-Wächter;
|
||
Release-Testbuild und gezieltes Clippy bestanden, keine Kerneländerung.
|
||
Der Primitive-Nachweis ersetzt noch nicht den vollständigen Greedy-Einstieg
|
||
mit Penalties und dessen vorgeschalteter Auswertung im Generator.
|
||
|
||
**Sampler-Anschluss: Dense-/Sparse-Tokenziehung und Verify, 2026-09-10:**
|
||
|
||
`Distribution` bildet die zwei originalen Verteilungsarten ab. Dense-Sampling
|
||
behält seine zusätzliche Float64-Normalisierung vor NumPy-Choice; Sparse
|
||
verwendet weiter die Konstruktorverteilung. Beide verwenden dieselbe
|
||
CDF-Reihenfolge und den bereits vorhandenen PCG64. Ungültige Dense-Masse
|
||
liefert einen Fehler vor der Ziehung, keine Token-0-Ersatzantwort.
|
||
Dense-/gemischte Residual-Verteilungen behalten die vollständigen
|
||
Vokabularpositionen, Sanitization und erneute Normalisierung. Beide
|
||
Sparse-Verteilungen verwenden weiter ihren vorhandenen Union-/Lookup-Pfad.
|
||
Bei leerem Sparse-Residual wird der Target wie im Original unverändert
|
||
weitergereicht; die bisherige zusätzliche `clone()`-Kopie entfällt (`Cow`).
|
||
|
||
Rohdaten: `local-eval-results/sampler-mixed-20260910.y18CqV/`.
|
||
Der erste Originaldatensatz belegte jede Sparse-Position des Vokabulars und
|
||
wurde bei 248320 Tokens vom Wächter nach 16,330 s ohne Fortschritt beendet
|
||
(`reference.*`, 83 vollständige Receipts). Dies erzwingt im originalen
|
||
Sparse-Residual quadratisch viele lineare Token-Lookups und bildet die
|
||
Top-k=20-Testkonfiguration nicht ab. Der korrigierte Datensatz
|
||
(`reference-topk.*`) enthält weiterhin das **volle Dense-Vokabular**, aber
|
||
maximal 20 über das Vokabular verteilte Sparse-IDs. Weder Runtime noch
|
||
Wächtergrenzen wurden dafür verändert. Der Fehlversuch bleibt dokumentiert.
|
||
|
||
- 100 Originalfälle: Vokabular 1/17/129/4097/248320, Dense/Dense,
|
||
Dense/Sparse, Sparse/Dense und Sparse/Sparse; umgekehrte, identische,
|
||
disjunkte, nichtendliche und Nullmassen.
|
||
- 2.560 Tokenziehungen exakt; 20 Sample-Fehlerfälle ohne abweichenden
|
||
RNG-Verbrauch. 3.200 Verify-Ergebnisse exakt: 1.659 Akzeptanzen,
|
||
1.227 Korrekturen, 314 Fehler. Akzeptanzbits und jeweils der nächste
|
||
PCG64-Wert stimmen ebenfalls überein.
|
||
- Residual-Art, vollständige Float64-Hashes, Sparse-ID-Hashes und
|
||
Wiederverwendung des Targets exakt; 20 Residual-Fehlerfälle stimmen.
|
||
- Alle **sechs** Sampling-Tests gemeinsam bestanden (2,36 s Testdauer),
|
||
Rust-Lifetime-Peak 298.763.008 Bytes. Korrigierte Originalprüfung:
|
||
1,197 s inklusive Wächter, Peak 101.057.184 Bytes. Dies sind
|
||
Korrektheitsprüfungen und keine Modell- oder Performance-Benchmarks.
|
||
- Unveränderte serielle Überwachung mit 2048 MiB und 15 s
|
||
Start-/Fortsetzungsgrenzen, keine Modellladung oder Downloads.
|
||
Release-Testbuild und gezieltes warnings-denied Clippy bestanden.
|
||
Bestehende Sparse-Prüfungen bestehen nach gemeinsamer CDF-Nutzung weiter.
|
||
|
||
**Sampler-Anschluss: Raw-Logit-Penalties und Overlay, 2026-09-10:**
|
||
|
||
`apply_penalties_host` und `apply_penalties_gpu` übernehmen die beiden
|
||
Originalfunktionen aus `sampling.py` und `fast_sampling.py`. Presence und
|
||
Frequency werden auf [-2,2] begrenzt; das nachgeschaltete sparse Overlay wird
|
||
nicht begrenzt. Counts beziehen sich weiterhin auf Completion-Tokens, nicht
|
||
auf Prompt-Tokens. Ohne aktive Counts/Overlay bleibt die Originalidentität
|
||
erhalten, auch wenn die unbenutzten Penalty-Parameter ungleich null sind.
|
||
|
||
Die GPU bildet die Float64-Deltas auf dem Host, rundet diese zu Float32 und
|
||
führt für Counts und Overlay je einen unabhängigen `Scatter(Sum, axes=[0])`
|
||
aus. Der allgemeine Scatter castet Updates **vor** der Addition in den
|
||
ursprünglichen Logit-Datentyp; BF16/FP16-Logits werden nicht zu FP32 befördert.
|
||
Der CPU-Pfad bleibt Float64 und verwendet die originale Read-all/Write-all-
|
||
Reihenfolge der indizierten Subtraktion je Stufe. Deaktivierte Penalties sind
|
||
keine Kopie und kein neuer Dispatch.
|
||
|
||
Der vorhandene Indexing-Baustein und Copy-/Donation-Pfad werden wiederverwendet.
|
||
Der neue eindimensionale additive Scatter verwendet die unveränderten
|
||
Originalkörper `scatter_impl`, Atomic-/Sum-Helfer sowie zwölf spezialisierte
|
||
Original-JIT-Wrapper (BF16/F16/F32, Updates contiguous/strided, 32/64-Bit
|
||
Offsets). Für rank-one Indizes wählt auch der Originalplan immer nwork=1.
|
||
Die Host-Exportnamen des namespaced Wrappers sind explizit gesetzt; der erste
|
||
Lauf ohne diese Alias-Angabe scheiterte vor dem ersten Scatter-Dispatch
|
||
(`rust.*`). Die Korrektur betrifft nur den Einstieg, keine Berechnung.
|
||
|
||
Rohdaten: `local-eval-results/sampler-penalties-20260910.kW51NO/`.
|
||
|
||
- 360 direkte Originalfälle: Vokabular 17/4097/248320, BF16/F16/F32,
|
||
gewöhnliche/strided/Offset/reverse/Broadcast-Logits. Acht Profile:
|
||
deaktiviert, keine Counts, Counts, Overlay, beide, begrenzte Penalties,
|
||
Null-Overlay und ein einzelner Count-Eintrag.
|
||
- Alle vollständigen GPU-Float32- und CPU-Float64-Hashes exakt. Identität
|
||
bei No-op, kein Dispatch bei No-op, Anzahl separater Scatter-Stufen und
|
||
Erhalt der vom Aufrufer gehaltenen Eingabelogits zusätzlich geprüft.
|
||
- Korrigierter Einzeltest bestanden (`rust-export.*`, 1,30 s),
|
||
Rust-Lifetime-Peak 172.671.720 Bytes; Original 232.211.176 Bytes.
|
||
Alle sieben Sampling-Tests gemeinsam bestanden (`samplers.*`, 2,70 s),
|
||
Lifetime-Peak 313.541.472 Bytes. Auch der bestehende QSA-ScatterAxis-Test
|
||
mit den gemeinsam verwendeten Originaldefinitionen besteht weiter.
|
||
- Sämtliche Läufe seriell unter `test-supervisor 2048 15 15`, keine Modelle
|
||
geladen/heruntergeladen. Release-Testbuild, gezieltes warnings-denied
|
||
Clippy und Originalquellprüfung bestanden. Die Quellprüfung ermittelt die
|
||
Runtime-Einheiten nun aus dem Export statt einer veralteten Konstanten:
|
||
26 Runtime-Einheiten, 17 Custom-Körper/41 Custom-Einstiege plus dynamische
|
||
QSA-Quellen unverändert zur gepinnten Referenz beziehungsweise ihrem Export.
|
||
|
||
**Sampler-Anschluss: gewöhnlicher Generator-Einstieg, 2026-09-10:**
|
||
|
||
`SamplerConfig`, `distribution_from_logits` und `sample_from_logits` verbinden
|
||
die geprüften Bausteine entsprechend `generation._distribution_from_mlx_logits`
|
||
und `generation._sample_from_logits`. Greedy verwendet unverändert den
|
||
Raw-Dtype-Penalty-Pfad, wertet dessen Logits **vor** der Argmax-Erzeugung aus
|
||
und verbraucht keinen PCG64-Wert. Der einzelne Sparse-Einstieg flacht die
|
||
Logits ab, wendet GPU-Penalties an, castet danach zu Float32 und verwendet
|
||
die serielle Unterstützung mit ihrem originalen Bad-mass-Fallback. Dense
|
||
castet die unbestraften Logits zu Float32, liest logisch zu Float64 und
|
||
wendet erst dort die Host-Penalties und Distribution/Choice-Normalisierung an.
|
||
Ein GPU-Penalty-Ergebnis wird nicht als Dense-Fallback wiederverwendet.
|
||
|
||
Beim Verbinden wurde die Einschränkung des bisherigen Full-Logit-Readbacks
|
||
auf zusammenhängende Zeilen entfernt. Der bereits vorhandene Integer-Reader
|
||
teilt nun seine evaluierte, span-validierte CPU-Ansicht mit Float32→Float64:
|
||
auch negative/mehrdimensionale/Broadcast-Strides werden ohne GPU-Pack oder
|
||
GPU-Flatten gelesen. Der heiße 4k-Support-Readback bleibt unverändert und
|
||
kopiert weiterhin nur die ausgewählten Kandidaten. Der plurale Bad-mass-
|
||
Fallback verwendet denselben vollständigen strided Reader einmal für alle
|
||
ungültigen Reihen.
|
||
|
||
Rohdaten: `local-eval-results/sampler-entry-20260910.WyVtqa/`.
|
||
|
||
- 1.080 tatsächliche Aufrufeinstellungen des originalen MTPLX-
|
||
`generation._sample_from_logits`: BF16/F16/F32, Vokabular
|
||
17/4097/248320, gewöhnliche/Rank-3/strided/reverse/Broadcast-Logits,
|
||
periodische/uniforme/nichtendliche Eingaben; Greedy, Sparse Top-k,
|
||
Dense Top-p und Dense ohne Filter, jeweils Penalties/Overlay an/aus.
|
||
- Pro Konfiguration drei aufeinanderfolgende Ziehungen mit einem PCG64
|
||
und fortgeschriebenen Completion-Counts. Alle 3.240 Ergebnisse stimmen:
|
||
810 Greedy-, 810 Sparse-, 1.080 Dense-Ergebnisse und 540 erwartete Fehler.
|
||
Token, Verteilungstyp, vollständige Float64-/Sparse-ID-Hashes, Count-
|
||
Reihenfolge und nachfolgender RNG-Wert exakt.
|
||
- Die Referenz-Python-Aufrufe von eval/argmax werden aufgezeichnet. Der
|
||
Rust-Test prüft tatsächliche GPU-Commitgrenzen: Greedy hat zwei getrennte
|
||
Auswertungen; ein bereits ausgewerteter Bad-mass-Host-Readback erzeugt
|
||
keinen zusätzlichen GPU-Commit. Argmax bleibt dem Greedy-Pfad vorbehalten,
|
||
Dense-Penalties dispatchen keinen GPU-Scatter.
|
||
- Alle acht Sampling-Tests gemeinsam bestanden, 6,99 s Testdauer,
|
||
Rust-Lifetime-Peak 320.389.936 Bytes. Originalsequenzen: 4,114 s inklusive
|
||
Wächter, Peak 286.769.968 Bytes. Unterschiedliche gesamte Testumfänge;
|
||
diese Zeiten sind ausdrücklich kein Performance-A/B-Vergleich.
|
||
- Beide bestehenden N-Gram-Stage-Tests bestehen nach Wiederverwendung des
|
||
Integer-Readers weiter. Alle Läufe seriell unter dem externen
|
||
`2048 MiB / 15 s Start / 15 s Fortschritt`-Budget, ohne Modelle/Downloads.
|
||
Release-Testbuild, gezieltes warnings-denied Clippy, Format- und
|
||
Diffprüfung bestanden. Keine Änderung an Metal-Kernelkörpern.
|
||
|
||
Dieser Einstieg ist weiterhin Teil des kanonischen Testbuilds. Die Python-
|
||
Owner-Progress-/Watchdog-Anbindung ist zusammen mit dem vollständigen
|
||
Generator und den UI-/Harness-Metriken zu verbinden; der Methodenvergleich
|
||
allein weist weder Produktintegration noch UI-Responsivität nach.
|
||
|
||
**Residenter Keyed-GPU-Sampler, 2026-09-10:**
|
||
`sampling::lazy_sample` bildet `generation._mx_lazy_sample` vollständig als
|
||
verzögerten Graphen ab. ArgPartition arbeitet auf den unveränderten
|
||
Modell-Dtypes; erst die k gewählten Logits werden F32. Top-p verwendet den
|
||
originalen inklusiven Scan, Bool-Sum, Maximum und Select. Die gepinnte
|
||
`categorical(sv[None], key)`-Route ist inverse CDF, nicht Gumbel-max:
|
||
Max/Inf-Behandlung, exklusiver Scan, Uniform und SearchSorted-right.
|
||
`random.rs` übernimmt U32-Key-Erzeugung, Split und F32-Uniform aus dem
|
||
gepinnten `random.cpp`; `rbits`/`rbitsc`, Scan, SearchSorted und Reduktionen
|
||
kommen unverändert aus der originalen Metallib. Der Host-PCG64 bleibt davon
|
||
getrennt. Keine Auswertung, Rücklesung oder Synchronisation im Graphaufbau.
|
||
|
||
Für Bool-Sum verwendet der gemeinsame Reduktionsplan die originale
|
||
`remap_reduce_types`-Zuordnung Bool -> Int8-Eingabe / Int32-Ausgabe, ohne
|
||
Cast-Dispatch. Die vorhandenen Gather-Exporte umfassen nun auch F16/F32 mit
|
||
U32-Indizes, einschließlich F16-GatherFront mit beiden Arbeitsbreiten.
|
||
Nur Original-Template-Instanziierungen wurden ergänzt, keine Kernelkörper
|
||
verändert. CSE berücksichtigt RandomBits-Outputshape und Scan-/Suchrichtung.
|
||
|
||
Belege: `local-eval-results/sampler-resident-20260910.7576Ll/`;
|
||
Fixture `tests/fixtures/mtplx-sampler-resident.jsonl`, SHA256
|
||
`497e1175cf18e2d76d2b18f7547bc27c9138b9f3ea82f2b3bead0cf0f72ac7a3`.
|
||
|
||
- 63 Original-RNG-Fälle: drei vollständige U64-Seeds, zusammenhängende,
|
||
geslicte und rückwärts gerichtete Keys, leere/gerade/ungerade sowie
|
||
mehrdimensionale Ausgaben (Uniform bis 4097, Split bis 8194 Elemente).
|
||
Vollständige U32-Bits- und
|
||
F32-Uniform-Hashes, vier aufeinanderfolgende Split-Keys und der nächste
|
||
Key stimmen bitgenau überein.
|
||
- 324 Sequenzen des echten MTPLX-Samplers mit jeweils vier aufeinanderfolgenden
|
||
GPU-Key-Ziehungen: Vokabular 17/4097/248320, BF16/F16/F32, vier Layouts,
|
||
normale/gleiche/nichtendliche Logits, drei Temperature/Top-p/Top-k-Profile.
|
||
Alle 1296 Tokens und Fortsetzungs-Keys stimmen exakt überein. Rust prüft
|
||
zusätzlich skalare unevaluierte Ergebnisse, keine Dispatches/Commits beim
|
||
Aufbau sowie acht RandomBits- und vier SearchSorted-Aufrufe pro Sequenz.
|
||
- `samplers-export.*`: alle neun Samplertests bestanden, 7,86 s Testzeit,
|
||
Lifetime-Peak 337.036.080 Bytes. Original-Oracle `reference-fixed.*`:
|
||
1,289 s einschließlich Wächter, Peak 282.280.704 Bytes. Verschiedene
|
||
Testumfänge; ausdrücklich keine Performance-A/B-Messung.
|
||
- Frühere Versuche im selben Verzeichnis sind nicht als Erfolg gewertet:
|
||
Python exportiert `bits` nicht öffentlich (Oracle nutzt danach den echten
|
||
`random.split`-Einstieg); Rust fehlten zunächst Bool-Sum-Kernelzuordnung
|
||
und F16-GatherFront-Instanziierungen. Die Referenzwerte wurden nicht an
|
||
Rust angepasst. Alle GPU-Läufe seriell unter dem externen
|
||
2048-MiB-/15-s-Start-/15-s-Fortschritts-Wächter, ohne Modell/Download.
|
||
- Release-Testbuild, gezieltes warnings-denied Clippy, Format-, Diff- und
|
||
Originalquellprüfung bestanden. P11/P16 bleiben offen: der Sampler allein
|
||
ist weder ein integrierter Generator noch ein UI-/Performance-Nachweis.
|
||
- Der bestehende gemeinsame Sum-Graph-Test mit 232 Referenzfällen besteht
|
||
ebenfalls (`sum.*`, 2,41 s, Lifetime-Peak 396.804.960 Bytes).
|
||
|
||
**Gebundene und seriale Batch-Verteilungen, 2026-09-10:**
|
||
`BatchedDistributions` und `BoundBatchedDistributions` übernehmen die zwei
|
||
verschiedenen Wege aus MTPLX `fast_sampling.py`. Der normale Batch-Einstieg
|
||
verwendet die vorhandene Serial-Support-Auswertung und `_from_execution_arrays`:
|
||
Zeilensumme vor Vokabularsortierung, dann einmalige Matrix-Normalisierung.
|
||
Eine einzige ungültige Zeile schaltet **alle** Zeilen auf Host-Sampling um;
|
||
`-1`-Padding und Nullwahrscheinlichkeiten bleiben erhalten. Das ist nicht der
|
||
bereits vorhandene Sparse-Listenpfad mit einzelnen Zeilen-Fallbacks.
|
||
|
||
Der vorgebundene Weg friert Temperature/Top-p/gekappte Top-k/Vokabular vor dem
|
||
Decode-Loop ein, bestimmt den Support auf den rohen F32-Logits und wertet
|
||
Rows/Indices gemeinsam aus. Anschließend laufen Full-Vocab-Softmax und Top-p
|
||
in Host-F64 wie im Original. Ungültige Masse bleibt hier ein Fehler, ohne
|
||
automatische One-hot-Ersetzung. Vorhandene Auswahlgraphen, Readback, PCG64,
|
||
CDF-Ziehung und Sparse-Konvertierung werden wiederverwendet; kein neuer Kernel.
|
||
|
||
Die Batch-Methoden behalten ihre getrennten Regeln: `probability` nimmt den
|
||
ersten passenden Eintrag, `sample` filtert positive Einträge ohne zusätzliche
|
||
Normalisierung, `to_distribution` normalisiert über den originalen
|
||
Sparse-Konstruktor erneut. Der gemeinsame Choice-Validator wird auch vom
|
||
bisherigen dichten Sampler benutzt. Ungültige Ziehungen verbrauchen keinen RNG.
|
||
|
||
Der erste Vergleich deckte bei Broadcast-Rows eine Ein-Bit-Abweichung auf.
|
||
`np.asarray(rows).astype(float64)` verwendet `order='K'`: aus Strides `(0,4)`
|
||
wird eine Fortran-Anordnung `(8,32)`; die Zeilensummen entstehen dann
|
||
sequenziell statt paarweise. Das separate Originalexperiment `layout.*`
|
||
belegt die unterschiedlichen Normalisierer. Rust wählt jetzt anhand der
|
||
evaluierten 2D-Inputstrides die entsprechende Summationsreihenfolge, ohne
|
||
Referenzwerte oder Toleranzen zu verändern. Referenzimplementierung:
|
||
[NumPy 2.4.4 Keep-order allocation](https://github.com/numpy/numpy/blob/v2.4.4/numpy/_core/src/multiarray/ctors.c#L1033),
|
||
[absolute-stride ordering](https://github.com/numpy/numpy/blob/v2.4.4/numpy/_core/src/multiarray/shape.c#L765).
|
||
|
||
Belege: `local-eval-results/sampler-batched-20260910.5QvwOq/`;
|
||
Fixture `tests/fixtures/mtplx-sampler-batched.jsonl`, SHA256
|
||
`60e35333cc2f11ca950fdef1c3c1bcbc56da76331ce33867ad50a8d9f8719b6c`.
|
||
|
||
- 324 Originalfälle je Route plus fünf Konstruktorfälle: Vokabular
|
||
17/4097/248320, BF16/F16/F32, zusammenhängende/strided/reverse/broadcast
|
||
Vier-Zeilen-Batches, normale/gleiche/gemischt ungültige Logits und drei
|
||
Temperature/Top-p/Top-k-Profile. 108 globale Fallbacks und 111 erwartete
|
||
Konstruktor-/Auswertungsfehler. Die vollständigen IDs-/F64-Matrix-Hashes,
|
||
Einzelkonvertierungen, Probability-Lookups einschließlich negativer und
|
||
ungültiger Zeilenindizes sowie 17.344 Sample-Versuche mit anschließenden
|
||
RNG-Werten stimmen exakt. Ablehnungen sind Teil des Vergleichs.
|
||
- Tatsächliche explizite Commit-Grenzen passen zu den Originalauswertungen;
|
||
der bereits erledigte Readback bei Host-Fallback erzeugt keinen neuen
|
||
GPU-Commit. Binden und abgelehnte Greedy-/Top-k-Anfragen lösen keine
|
||
Inferenz aus. `samplers-layout.*`: alle zehn Samplertests bestanden,
|
||
11,96 s, Lifetime-Peak 797.639.856 Bytes. Der fehlschlagende frühere
|
||
`samplers.*`-Lauf bleibt als Diagnosebeleg erhalten.
|
||
- Original-Oracle: 2,286 s einschließlich Wächter, Peak 393.233.200 Bytes.
|
||
Die Testumfänge unterscheiden sich; daraus wird keine Performance-Parität
|
||
abgeleitet. Alle GPU-Läufe seriell unter 2048 MiB / 15 s Start / 15 s
|
||
Fortschritt, ohne Modelle/Downloads. Release-Testbuild, gezieltes
|
||
warnings-denied Clippy sowie Format-/Diffprüfung bestanden.
|
||
|
||
**Device-side Target-prefix-Sampler, 2026-09-10:**
|
||
`sampling::sample_token_ids` bildet jetzt die unveränderte
|
||
`fast_sampling.sample_token_ids_from_mlx_logits`-Operationsfolge ab: Float32-
|
||
Division durch Temperatur, deterministischer Support, begrenzte paarweise
|
||
Rangordnung (Wert absteigend/Token-ID aufsteigend), Full-vocabulary-LSE und
|
||
Top-p-Maske beziehungsweise Token-ID-Sortierung vor der Ziehung. Der positive
|
||
Top-p-Pfad lehnt k > 32 nach Begrenzung auf die Vokabulargröße ab; k <= 0
|
||
mit aktivem Top-p bleibt nicht unterstützt. Beide Pfade verbrauchen keinen
|
||
RNG-Schritt. Greedy verwendet den originalen Logit-Datentyp ohne RNG.
|
||
|
||
`random::categorical_last` übernimmt die tatsächlich unterschiedlichen
|
||
Referenzpfade: ein einzelner Verteilungsvektor ohne Prefix nutzt Gumbel-Max,
|
||
ein Singleton-Prefix inverse CDF, mehrere Reihen Gumbel-Max. Die Log-Operation
|
||
verwendet das originale Runtime-Metallib; die vorhandenen Reduce-, Scan-,
|
||
Gather- und Threefry-Graphen werden wiederverwendet. Keine neuen Metal-Körper,
|
||
keine CPU-Ziehung und keine vorgezogene GPU-Auswertung beim Graphaufbau.
|
||
`KeySequence` bildet Seed, Split und fortgesetzten Zustand ab. Dies ist noch
|
||
**kein** angeschlossener produktiver threadlokaler Default-RNG: Owner-
|
||
Lebenszyklus, gemeinsame unkeyed Aufrufe, zeitbasierter Initialseed und Wechsel
|
||
des Default-Streams müssen im Generator integriert werden. Der aktuelle
|
||
Sequenzhelfer hält den beim Anlegen übergebenen Stream fest; diese Tests
|
||
belegen den unveränderten Default-GPU-Stream, keine Streamwechsel-Parität.
|
||
|
||
Nachweis: `tools/mtplx-kernel-fixtures.py::prefix_sampler_fixtures` ruft den
|
||
originalen MTPLX-Einstieg auf. 162 Fälle mit Vokabular 17/4097/248320,
|
||
BF16/F16/F32, Vektor/Singleton/2x2-Prefix sowie strided/reverse/broadcast,
|
||
Muster/Gleichständen/NaN und Unendlichkeiten. Je elf aufeinanderfolgende
|
||
Aufrufe mit Greedy, nicht unterstützter und abgelehnter Konfiguration zwischen
|
||
Zufallsziehungen; expliziter Reseed innerhalb derselben Folge. Rust prüft
|
||
Token-IDs, Rückgabeform, Fehlermeldung und den vollständigen RNG-Zustand nach
|
||
jedem Aufruf exakt. Zusätzlich keine Dispatches oder Commits beim Graphaufbau.
|
||
|
||
- Fixture `tests/fixtures/mtplx-sampler-prefix.jsonl`, SHA-256
|
||
`e74e239d30749f66d74d92eb9124f47de460fbf3f01b338b3adc65fef7bdbd07`.
|
||
- Rohdaten: `local-eval-results/sampler-prefix-20260910.SIdwjQ/`.
|
||
Original-Oracle regulär beendet, 1,616 s inklusive Wächter,
|
||
gemessener Lifetime-Peak 447.480.696 Bytes.
|
||
- Alle elf `mtplx_sampler`-Tests bestanden, 13,34 s Testzeit / 14,042 s
|
||
inklusive Wächter, gemessener Lifetime-Peak 815.416.520 Bytes. Original und
|
||
Rust jeweils einzeln unter 2048 MiB / 15 s Start / 15 s Fortschritt,
|
||
ohne Modellgewichte oder Downloads. Die Umfänge unterscheiden sich;
|
||
dies sind keine vergleichbaren Gesamtmodell-Geschwindigkeitsmessungen.
|
||
- Release-Testbuild, gezieltes warnings-denied Clippy, Originalquellprüfung
|
||
(17 Körper/41 Custom-Einstiege/26 Runtime-Einheiten plus dynamische QSA),
|
||
Format- und Diffprüfung bestanden. Keine Bundle-/Commit-/Push-Aktion.
|
||
|
||
**AR-Decode-Verbindung, 2026-09-10:** `ar.rs` und
|
||
`Execution::decode_ar` verbinden den bereits vorhandenen Modell-/Cache-Graphen
|
||
mit dem normalen Text-Decode-Zweig von `generation.generate_ar`:
|
||
|
||
- Klassischer synchroner und asynchroner AR-Pfad, Host-PCG64, Penalties nur
|
||
über bereits generierte Tokens, Stop-Token intern behalten und nicht an den
|
||
Text-Callback ausgeben. Keine zusätzliche CPU-Konvertierung residenter IDs
|
||
vor dem Modell-Forward.
|
||
- Pipeline-Admissibilität, eigener `seed & 0x7fffffff`-Key und originale
|
||
Reihenfolge: erster Token aus Host-Sampler; aktuellen Schritt async auswerten,
|
||
Folgeschritt bauen/async auswerten, erst dann aktuellen Token materialisieren.
|
||
Vorangehende Logit-Zeile bis zum nächsten Schritt behalten.
|
||
- Die Pipeline hat den finalen Token schon konsumiert; die klassische
|
||
Schleife hat ihn nur ausgegeben. Finale Cache-Erfassung verwendet daher die
|
||
vorhandene Pipeline-Zeile oder genau einen klassischen Tail-Forward. Der
|
||
Modell-Owner schaltet den Pipeline-Modus vor dieser Erfassung zurück; auch
|
||
Result-Fehler des Decode-/Callback-Pfades stellen den Modus zurück.
|
||
Antwortzeit wird vor dieser Session-Nacharbeit beendet; Capture-Fehler
|
||
bleiben separat und vernichten die fertige Antwort nicht.
|
||
|
||
Dieser Einstieg beginnt **nach** Prompt-Restore/Prefill und implementiert den
|
||
normalen Textzweig. Er ist noch kein Ersatz für den vollständigen Request-
|
||
Owner: Grammar/Constraint, Repetition-/Loop-/Thinking-Guards samt Übergang von
|
||
Pipeline zu klassischer Steuerung und die Owner-Progress-Hooks fehlen noch.
|
||
Die Pipeline-Admissibilität darf daher nicht allein zur Auswahl für solche
|
||
Requests benutzt werden. `qwen_mtplx` bleibt `cfg(test)`; UI und `model-eval`
|
||
wurden nicht auf einen unvollständigen Generator umgeschaltet.
|
||
|
||
**Orchestrierungsnachweis:** `ar_driver_fixtures` ruft das unveränderte
|
||
MTPLX-`generate_ar` mit einer kleinen GPU-Transitionstabelle statt Modellgewichten
|
||
auf. Prefill, Sampling, Pipeline und finale Erfassung sind die originalen
|
||
Generatoroperationen, keine nachgebaute Python-Decode-Schleife. 480 Fälle,
|
||
1384 interne Tokens, 32 tatsächlich aktivierte Pipeline-Fälle und
|
||
192 finale Cache-Erfassungen. 96 Fälle stoppen durch EOS; die zusätzlichen
|
||
Stop-Sets erzwingen insbesondere den ersten und zweiten Pipeline-Token,
|
||
also sofortiges EOS und EOS mit bereits laufendem Folgeschritt. Rust stimmt
|
||
für Tokenfolgen, Callback-Ausgaben,
|
||
Forward-Eingaben/Reihenfolge/Hidden-Anforderung, Pipeline-Admissibilität,
|
||
Verify-Zähler und finale Logit-Bytes exakt überein. Dies testet den Decode-
|
||
Ablauf, **nicht** Qwen-Modellrechnung, den gesamten Session-Owner oder Speed.
|
||
|
||
- Fixture `tests/fixtures/mtplx-ar-driver.jsonl`, SHA-256
|
||
`9916c29df3d937c36df1f12a477bcd1160683806b6941faa7ff108f8533307a5`.
|
||
- Rohdaten `local-eval-results/ar-driver-20260910.Ph2gDy/`.
|
||
`reference.jsonl`/`driver.*` dokumentieren den ersten fehlgeschlagenen
|
||
Vergleich von JSON-Float64-Dezimalwerten. Finale Float32-Zeilen werden im
|
||
`reference-bits.jsonl` unverändert als Byte-Hash erfasst;
|
||
`driver-bits.*` besteht ohne Toleranzänderung. Der erweiterte maßgebliche
|
||
Satz `reference-eos.jsonl` / `driver-eos.*` umfasst auch die erzwungenen
|
||
frühen EOS-Fälle: 0,64 s Testzeit, 1,297 s einschließlich Wächter,
|
||
gemessener Lifetime-Peak 173.589.272 Bytes.
|
||
Original-Oracle 1,636 s einschließlich Wächter, Peak 231.129.880 Bytes;
|
||
unterschiedliche Umfänge, keine Performance-A/B-Abnahme.
|
||
- Alle elf vorhandenen Sampler-Referenztests (`samplers.*`) danach bestanden.
|
||
Modellfreie GPU-Läufe ausschließlich seriell unter 2048 MiB / 15 s Start /
|
||
15 s Fortschritt. Keine neuen Modellartefakte oder Downloads.
|
||
|
||
**Angeschlossener Vollmodell-Decode:** Der vorhandene installierte Ping-Test
|
||
behält seine 41 Prefill-Zeilen und 46 vollständigen Decode-Logit-Vergleiche.
|
||
Zusätzlich setzt er den Cache zurück, evaluiert denselben 41-Token-Prompt und
|
||
ruft `Execution::decode_ar` auf. Greedy mit `max_tokens=usize::MAX`, also kein
|
||
geschätztes Antwortlimit: alle 46 Antworttokens und das natürliche EOS stimmen
|
||
mit `execution-20260910.Ngpzu7/reference-server.stdout.log` überein. Der Callback
|
||
prüft jeden Token gegen diese Referenz und meldet tatsächlichen Fortschritt.
|
||
Das ist eine Verbindung zum echten Qwen-Trunk, nicht nur ein Tabellenmodell.
|
||
|
||
Maßgeblicher Lauf `installed-phase.*`: 9,05 s Testzeit / 9,758 s einschließlich
|
||
Wächter, Lifetime-Peak 75.893.991.712 Bytes, 86 Canary-Proben ohne Fehler/Stall.
|
||
Maximale GPU-Probenlatenz 3,579 ms beim Laden, 0,620 ms im Prefill und
|
||
0,505 ms im Decode. Beide Prefills sind ausdrücklich als Prefill markiert;
|
||
der erste Lauf `installed.*` hatte den zweiten Prefill noch im Decode-Abschnitt
|
||
und ist deshalb **keine** Grundlage für phasenbezogene Latenzvergleiche.
|
||
Unverändert 81920 MiB / 30 s Start / 45 s Fortschritt, nativer Canary während
|
||
des gesamten Workers mit 2-s-Abbruch, installierter Trunk ohne MTP-Head,
|
||
`MTPLX_NGRAM_RESIDENT=0`, originale AR-Server-Familiendefaults, Power 100 %.
|
||
Kein paralleler GPU-Prozess, kein Download.
|
||
|
||
Dieser diagnostische Test nutzt weiter den vorhandenen gemeinsamen
|
||
41-Token-Numerik-Prefill, **nicht** den noch zu verbindenden originalen
|
||
Restore-/Body-/Tail-Requestablauf. Greedy aktiviert keine residente Pipeline.
|
||
Die 9,758 s enthalten Laden, Referenzprüfungen und zwei Decode-Folgen und sind
|
||
kein vergleichbarer Modell-Durchsatz. Release-Testbuild, gezieltes
|
||
warnings-denied Clippy, Originalquellprüfung und Format-/Diffprüfung bestanden.
|
||
Kein Bundle, Commit oder Push.
|
||
|
||
**Kalter Text-Prefill mit echtem AR verbunden, 2026-09-10:**
|
||
`qwen_mtplx/prefill.rs` führt den originalen `_prefill`-Body-/Tail-Ablauf aus:
|
||
Cache-Erzeugung nach dem ersten Abbruchcheck, Chunk-Views auf demselben
|
||
Promptkörper, bedarfsabhängige Logits-/Cache-Auswertung, Fortschritt nach
|
||
abgeschlossener Auswertung und separates letztes Prompt-Token. Die rohe
|
||
Cache-Wurzelmenge folgt `_tree_mx_arrays` über Objektattribute, nicht der
|
||
abweichenden `cache.state`-Ansicht: inklusive QSA-Kapazität, F32-Mirror,
|
||
GDN-/PLE-Captures und Alias-Deduplizierung. Nicht ausgewertete Head-Logits
|
||
werden im External-Emit-Cachepfad vor der Cache-Auswertung freigegeben.
|
||
|
||
505 originale Referenzfälle decken Wurzelreihenfolge und Prefill-Kontrollfluss
|
||
ab: 0/1/2/9/2050 Tokens, ungeteilter Körper oder Chunks 1/4/2048,
|
||
Final-Logits-/Cache-only-/External-Emit-Pfade, Hidden-Ausgabe und Abbrüche.
|
||
Fixture `tests/fixtures/mtplx-prefill-driver.jsonl`, SHA-256
|
||
`5b5fb0ba51480507e6849020b3137af8af2bc4394d95e4277701f9441bb5041e`.
|
||
Der erste Diagnoseadapter beobachtete fälschlich `rt._count`; originaler
|
||
Prefill schreibt über `generation._runtime_count` direkt in die Zähler.
|
||
Nach Anschluss an diesen tatsächlichen Schreibpfad stimmen auch die
|
||
Chunk-/Fortschrittsereignisse; keine Änderung der Original-Inferenz dafür.
|
||
`unit-counted.*`: bestanden, 0,874 s Supervisor, Peak 161.759.976 Bytes.
|
||
|
||
Rohdaten: `local-eval-results/prefill-driver-20260910.XwGFhY/`.
|
||
`Execution::prefill_prompt` ist mit derselben gebundenen Modellinstanz und
|
||
dem tatsächlichen AR-Decode verbunden. Der installierte Trunk wird ohne
|
||
Downloads, MTP-Head oder residente N-Gram-Tabelle geladen; Power 100 %, Low,
|
||
Sampler Temperatur 0,6 / Top-p 0,95 / Top-k 20 / Seed 0, originale
|
||
AR-Server-Familiendefaults, sustained Prefill 2048. Externer Wächter
|
||
81920 MiB / 30 s Start / 45 s Fortschritt, native GPU-Canary durchgehend
|
||
mit 2-s-Abbruch; ausschließlich sequenzielle GPU-Prozesse.
|
||
|
||
- Ping (`reference-ar.*`, `installed-ar.*`): 41 Eingabetokens, ein Body-Chunk;
|
||
exakte vollständige F32-Prefill-Logits, alle 68 gesampelten Tokens inklusive
|
||
EOS und die vollständigen finalen Logits nach 67 AR-Schritten stimmen.
|
||
Der Rust-Lauf hatte hier noch nur einen Prefill, die Referenz bereits zwei;
|
||
**kein zeitlich symmetrischer Vergleich**. Diese Diagnoseasymmetrie ist
|
||
anschließend im Rust-Test korrigiert worden, nicht im Inferenzkern.
|
||
- README-Summary (`reference-summary.*`, `installed-summary.*`): echter Prompt
|
||
`Give a summary of the following text:` plus README, 2748 Eingabetokens;
|
||
Body-Spans 2048 + 699 und letztes Token separat. Exakte erste Prefill-Logits,
|
||
alle **613 Tokens inklusive EOS**, 612 AR-Schritte und volle finale Logits
|
||
stimmen. Die Antwort ist eine abgeschlossene README-Zusammenfassung.
|
||
README-SHA-256 `80c01ea096843312de6662d3cd8c94c8e14bdf286b58824752981fc4920fd1f8`;
|
||
der Oracle speichert außerdem vollständigen Prompt und dessen Hash.
|
||
Beide Seiten führen jetzt erst den diagnostischen Fingerprint-Prefill und
|
||
danach einen frischen Prefill mit anschließendem AR bis natürlichem EOS aus.
|
||
Dies ist **kein vollständiger Chat-Warmup** und kein ongoing Dreiturn-Chat.
|
||
- Summary: erster Prefill MTPLX 9,159 s / Rust 6,456 s, wiederholter Prefill
|
||
2,256 s / 1,755 s. Rust meldet danach 11,636 s Decode; MTPLX meldet 14,741 s
|
||
Generation **einschließlich** des wiederholten Prefills. Diese unterschiedlich
|
||
geschnittenen Rohzähler nicht als gleichnamige Decode-Metrik vergleichen.
|
||
Supervisor-Gesamtzeit 31,391 s / 26,477 s, Peak-Footprint
|
||
81.212.995.568 / 80.948.295.160 Bytes. Kein 2%-Pass aus diesen Einzelmessungen
|
||
mit Canary, Token-Logging, Fingerprints und nicht balancierter Laufreihenfolge.
|
||
- Summary-Canary: MTPLX 288 / Rust 243 Proben, keine Fehler/Abbrüche;
|
||
Prefill-Maximum 0,726 / 0,720 ms, Decode-Maximum 0,520 / 0,737 ms.
|
||
Diese GPU-Proben messen nicht den produktiven UI-Eventloop. Die Behauptung
|
||
eines vollständig identischen Cache-Inhalts wäre ebenfalls zu weitgehend:
|
||
geprüft sind hier Folge-Tokens und finale Logits, nicht jeder Cache-Puffer.
|
||
|
||
Gezielte Nachprüfung: AR-Driver-Regression (480 Referenzfälle, 0,62 s) und
|
||
alle elf bestehenden Sampling-Tests (13,26 s) unter 2048-MiB-/15-s-Wächter
|
||
bestanden. Release-Testbuild, warnings-denied Clippy für Binary/Tests,
|
||
Originalquellprüfung (17 Körper, 41 Einstiegspunkte, 26 Runtime-Einheiten
|
||
plus dynamisches QSA), rustfmt und Diffprüfung bestanden. Kein Bundle,
|
||
Commit oder Push. Der kanonische Modulpfad bleibt `cfg(test)`; diese
|
||
vollständigen einzelnen AR-Interaktionen sind noch nicht die produktive
|
||
UI-/`model-eval`-Ausführung und kein Nachweis der sechs Endmatrix-Zellen.
|
||
|
||
**Streaming-MTP-Historie am Modell verbunden, 2026-09-10:**
|
||
`prefill::committed` portiert den kalten Textablauf aus
|
||
`_prefill_committed_mtp_history_streaming`; `Execution::prefill_mtp_history`
|
||
bindet dafür die bereits vorhandenen Trunk- und MTP-Cache-Graphen ein.
|
||
Body-Chunks liefern nur dann Hidden States, wenn das History-Fenster sie
|
||
benötigt; die Hidden-/Token-Paare werden um ein Token versetzt, passend
|
||
geschnitten und pro Chunk zwingend ausgewertet. Der letzte Prompt-Token
|
||
bleibt ein separater Trunk-Aufruf. Chunk-Callback-Fehler werden wie im Original
|
||
ignoriert, Abbrüche an den separaten Kontrollpunkten dagegen weitergegeben.
|
||
Target- und History-Zeit sind getrennt. Der explizite History-Positionswert
|
||
wird berechnet; Qwens originale `mtp_update_cache` ignoriert ihn zugunsten
|
||
des QSA-Cache-Offsets, und der Rust-Modelladapter tut dasselbe.
|
||
|
||
Rohdaten: `local-eval-results/mtp-prefill-20260910.7S6cT2/`.
|
||
656 unveränderte Originalsteuerungsfälle mit kleinen Modell-Testtensoren
|
||
prüfen Ergebnisse, Forward-/History-Eingaben, Hidden-Slices, Positionen,
|
||
Zähler-/Heartbeat-/Abbruchreihenfolge und Chunk-Callbacks. Eingaben 0/1/9/2050
|
||
Tokens; ungeteilter Körper bzw. 4/2048-Chunks; vollständige/0/1/3/2049-Historie,
|
||
Cache-/absolute Position, Full-Logits-/Cache-only-/External-Emit-Zweige.
|
||
Null-Länge des angeforderten History-Fensters wird wie im Original auf 1
|
||
geklemmt. Abbruchfälle vergleichen auch die schon ausgeführten Calls.
|
||
Fixture `tests/fixtures/mtplx-mtp-prefill-driver.jsonl`, SHA-256
|
||
`ae00ab6c91b98382c35784309ee35f5d2e641e9f2333e050905d03a4fdae70cf`.
|
||
Erzeugung mit dem endgültigen Adapter nochmals byteidentisch bestätigt;
|
||
Rust-Test bestanden (0,26 s, Supervisor 0,968 s, Peak 157.303.552 Bytes).
|
||
Der erste Fixture-Adapterversuch brach wegen eines fehlenden Runtime-Vertrags
|
||
vorzeitig ab; korrigiert wurde der Adapter, nicht MTPLX oder dessen Algorithmus.
|
||
|
||
Vollmodell-Nachweis (`reference-installed.*`, `installed.*`): installierter
|
||
Trunk plus tatsächlicher MTP-Head, README-Summary mit 2748 Eingabetokens,
|
||
Power 100 %, sustained Prefill 2048, originale MTP-Server-Familienflags und
|
||
SSD-N-Gram-Policy. Keine Downloads, keine parallelen GPU-Läufe. Externer
|
||
81920-MiB-/30-s-Start-/45-s-Fortschrittswächter und durchgehende native
|
||
GPU-Canary mit 2-s-Abbruch unverändert.
|
||
|
||
- Vollständige Historie: 2747 verschobene Token-/Hidden-Paare in zwei Chunks;
|
||
Cache-Offset 2747 vor bzw. 2748 nach erstem Draft. Vollständige F32-Hashes
|
||
für letzte Trunk-Logits, letzte Trunk-Hidden, erste Draft-Logits und
|
||
Draft-Hidden sind exakt identisch zu MTPLX.
|
||
- Letzte drei History-Tokens: erster Body-Chunk ohne Hidden-Ausgabe, aus dem
|
||
zweiten nur die letzten drei Paare für den Head; History-Positionsbasis
|
||
2744, Cache-Offset 3 vor bzw. 4 nach Draft. Dieselben vier Tensorprüfungen
|
||
sind exakt; die Draft-Tensoren unterscheiden sich erwartungsgemäß vom
|
||
Vollhistorie-Fall. Die Fixture prüft auch absolute Positionsmetadaten;
|
||
der Vollmodell-Lauf nutzt Qwens normalen Cache-Positionsmodus.
|
||
- Rohzeiten MTPLX/Rust: vollständiger Target-Prefill 11,202/5,509 s,
|
||
History 0,270/0,291 s; Drei-Token-History-Fall Target 2,221/1,710 s,
|
||
History 0,0133/0,0154 s. Die höheren Rust-History-Einzelwerte sind damit
|
||
ausdrücklich festgehalten. Keine Wiederholungs-/Reihenfolgebalance, kein
|
||
sauberer Speed-Test und kein belegter 2%-Pass oder harter Rücknahmegrund.
|
||
- Supervisor insgesamt 20,833/13,477 s; Peak-Footprint
|
||
81.452.808.584/81.093.507.008 Bytes. Canary 189/126 Proben, kein Abbruch,
|
||
Prefill-Maximum 1,391/0,918 ms. Die kurzen ersten Drafts trafen kein
|
||
100-ms-Probenfenster: **keine gemessene Decode-Latenz** aus diesem Test.
|
||
|
||
Alter AR-Prefill (505 Fälle) weiterhin bestanden. Release-Testbuild,
|
||
warnings-denied Clippy für Binary/Tests, Originalquellprüfung, rustfmt und
|
||
Diffprüfung bestanden. Keine neue Metal-Implementierung, kein künstliches
|
||
Cache-Leeren, keine Power-/Chunk-Absenkung, kein Bundle/Commit/Push.
|
||
Dies ist noch kein vollständiger `generate_mtpk`-Lauf bis EOS und keine
|
||
produktive UI-/Harness-Integration; der kanonische Pfad bleibt `cfg(test)`.
|
||
|
||
**Standard-MTP-Generator bis EOS mit Context-copy verbunden, 2026-09-10:**
|
||
`Execution::decode_mtp` verbindet den echten MTP-Head, die vorhandenen
|
||
Sampler/PCG64-Verteilungen, batched Verify, Family-Capture-Commit,
|
||
Snapshot-Rollback/Reforward, persistente autoritative MTP-Historie,
|
||
Bonus/Pending-Correction und finalen Pending-Commit. Der Original-Oracle ruft
|
||
`generate_mtpk` auf; keine nachgebaute Referenzschleife. Natürlicher EOS,
|
||
Sampler 0,6 / 0,95 / 20, Seed 0, Draft-Tiefe 3, History `committed`, Qwen-Low,
|
||
Power 100 %, Prefill 2048, serverseitige Familienflags und SSD-N-Gram-Policy
|
||
sind innerhalb jedes Paares identisch. Rohdaten:
|
||
`local-eval-results/mtp-generator-20260910.pYRdXK/`.
|
||
|
||
Der erste vollständige Ping (`rust-ping.*`, nochmals `rust-ping-trace.*`)
|
||
scheiterte am 30. ausgegebenen Token: MTPLX 328, Rust 264. Die ersten neun
|
||
Draft-/Acceptance-Zyklen stimmten, im zehnten nahm Rust alle drei Drafts an,
|
||
während MTPLX den zweiten ablehnte. Ursache im neu verbundenen Generator:
|
||
der Family-Commit bekam weiterhin `capture=true`, obwohl MTPLX seinen
|
||
`verify_capture_scope` VOR dem Commit beendet. Beim Ein-Token-Replay der
|
||
PLE-Schicht verhinderte das den originalen Fused-GDN-Step und änderte den
|
||
Folgezustand. Korrektur: Commit mit `GraphOptions::from_env(false, false)`,
|
||
wie im bereits geprüften Modelloperationsadapter. Keine Kerneländerung,
|
||
keine Toleranzlockerung und kein geänderter Seed/Prompt.
|
||
|
||
- Ping nach Korrektur (`rust-ping-capture-fix.*`): alle **52 Tokens inklusive
|
||
EOS**, **19 vollständige Zyklen**, 57 Drafts/33 angenommene Drafts, finale
|
||
Logits und Hidden States als vollständige F32-SHA-256 sowie MTP-Offset 92
|
||
exakt wie MTPLX. Kein vollständiger Trunk-Cache-Hash behauptet.
|
||
- Die ursprüngliche Summary enthielt fünf Runden mit leerer MTP-Draftliste.
|
||
Das ist KEINE adaptive Verkürzung der MTP-Tiefe: MTPLX aktiviert auch in
|
||
der batched Qwen-Lane standardmäßig Context-copy. Dieser Zweig wurde
|
||
portiert und NICHT für den Vergleich deaktiviert: Prompt-only N-Gram-Index,
|
||
rückwärtige Match-Verlängerung/neuester Tie-Break, Blockleiter, Probation,
|
||
EMA/Backoff, Punktmassen-p/q-Akzeptanz, Family-Commit und dessen Original-
|
||
Rückfall (gesamten Block zurückrollen, nur Primary nachfahren, Copy für den
|
||
Request deaktivieren). MTP-History enthält die akzeptierten autoritativen
|
||
Paare, nicht die noch ungeprüfte Korrektur. Auch die optionale RAMP-Fixed-
|
||
und Fuzzy-Match-Auswahl ist im Index vorhanden; Vollmodell-Abnahme hier
|
||
ausschließlich mit den unveränderten Standardwerten, RAMP aus.
|
||
- Summary (`reference-summary-copy.*`, `rust-summary-copy.*`): **2748
|
||
Prompt-Tokens, 401 Tokens bis EOS, 135 Verify-Zyklen**, 390 MTP-Drafts/247
|
||
angenommene MTP-Drafts. Alle fünf Copy-Ereignisse sind exakt: Block/Accept
|
||
8/0, 8/8, 16/4, 8/7, 24/0; auch Extension, Korrektur, Position und übrige
|
||
Zyklen stimmen. Vollständige finale Logits/Hidden-F32-Hashes identisch,
|
||
MTP-History-Offset 3148, finaler Zustand commit-fähig. Die Ausgabe ist
|
||
dieselbe abgeschlossene README-Zusammenfassung wie im Original.
|
||
- Summary-Rohzeiten: Rust Prefill 6,540 s, Decode 5,619 s, davon gemeldete
|
||
Draft-Aufrufe 0,679 s, Verify 4,614 s, History 0,143 s; separate Reforward-
|
||
Repair-Zeit 0. MTPLX meldet 10,330 s Generation inklusive 4,582 s Prefill.
|
||
Diese Zähler haben noch keine vollständig vereinheitlichten Messgrenzen;
|
||
aus Subtraktion allein keinen 2%-Pass ableiten. Supervisor-Gesamtzeiten
|
||
MTPLX/Rust 17,671/18,022 s, Peak-Footprint
|
||
82.048.399.848/81.575.557.248 Bytes. Unterschiedliche kalte Prefill-Zeiten,
|
||
Token-Logging, Canary, Endtensor-Readbacks und fehlende balancierte
|
||
Wiederholungen schließen eine saubere Performance-Abnahme aus.
|
||
- Durchgehende Summary-GPU-Canary: MTPLX/Rust 159/170 Proben, keine
|
||
unvollständige Probe/Fehler/Abbrüche, Prefill-Maximum 0,813/0,746 ms,
|
||
Decode-Maximum 0,516/0,203 ms. Das ist keine Messung des UI-Eventloops.
|
||
Alle Vollmodellprozesse liefen einzeln unter 81920-MiB-/30-s-Start-/45-s-
|
||
Fortschrittswächter und 2-s-Canary-Abbruch. Keine neue Last ohne Wächter.
|
||
|
||
Gezielte Prüfungen: Context-copy-Match/Probation/Backoff/Promptende-Test,
|
||
bestehende AR-Driver-Regression (480 Fälle), Release-Testbuild, warnings-denied
|
||
Clippy für Binary/Tests, rustfmt und Diffprüfung bestanden. Kein Bundle,
|
||
Commit oder Push. Der kanonische Modulpfad bleibt `cfg(test)`; die erfolgreiche
|
||
Standard-MTP-Interaktion ist noch NICHT die produktive UI-/Harness-Ausführung.
|
||
Capture-off-Rückfall, Greedy-Copy und optionale RAMP-Konfigurationen benötigen
|
||
zusätzliche Referenzfälle; sie werden durch die zwei Sampled-Läufe nicht als
|
||
vollständig abgenommen ausgewiesen.
|
||
|
||
**Warmer Text-Suffix auf dem tatsächlichen MTP-Endzustand, 2026-09-10:**
|
||
Die Integrationsprüfung der produktiven `Generator::generate_inner`-/
|
||
`prefill_suffix`-/Checkpoint-Verträge zeigte eine noch fehlende Voraussetzung:
|
||
der neue Modellpfad konnte bisher nur kalt vorfüllen. Ein direktes Umschalten
|
||
der UI hätte deshalb laufende Chats nicht mit MTPLX-Semantik fortgesetzt.
|
||
`Execution::prefill_restored_suffix` ergänzt den Live-/Restored-Cache-Pfad aus
|
||
`generation._prefill_restored_prompt_suffix`, ohne Reset oder Nachfahren des
|
||
bisherigen Kontexts. Es nutzt bestehende Modell-, History-, Slice- und
|
||
Auswerterfunktionen; keine neue Kernel-Implementierung und kein zweites Modell.
|
||
|
||
- Kurze Suffixe bis zum übergebenen Original-Limit (Default 512) werden in
|
||
einem Forward mit final-only Logits verarbeitet. Lange Suffixe verwenden
|
||
einen gemeinsamen Body-Eingabetensor mit Chunk-Views und separatem Tail.
|
||
- Vor dem ersten neuen Token wird der letzte gespeicherte Hidden-Zustand
|
||
dem ersten Suffix-Token zugeordnet. Danach werden die um eins versetzten
|
||
Hidden-/Token-Paare pro Body bzw. Fused-Forward in die bestehende MTP-Historie
|
||
übernommen und zwingend ausgewertet. Kein MTP-Cache wird neu erzeugt.
|
||
- Rückgabe und Fortschrittsereignisse halten Target-/History-Zeit auseinander.
|
||
Der separate Tail meldet Fortschritt, zählt aber wie in MTPLX nicht zu
|
||
`prefill_chunks`; ein Fused-Forward zählt als ein Chunk. Chunk-Callbackfehler
|
||
werden ignoriert, Abbrüche an den separaten Kontrollpunkten weitergegeben.
|
||
|
||
Rohdaten: `local-eval-results/restored-suffix-20260910.OovSi9/`.
|
||
Oracle: `--mtp-generate --restored-suffixes README.md`, echte originale
|
||
`generate_mtpk` bis EOS und danach der originale warme Suffix-Helper. Der
|
||
erste Referenzlauf sichert die Tensoren; `reference-counters.*` ergänzt die
|
||
echten Runtime-Zähler. Rust prüft zuerst erneut sämtliche 52 Ping-Tokens,
|
||
19 MTP-Zyklen und Endtensoren und danach die drei Suffixe auf demselben Cache:
|
||
|
||
| Warme Erweiterung | Tokens / bereits im Cache | Fortschritts-Chunks | Runtime-Chunks | Target MTPLX / Rust | History MTPLX / Rust |
|
||
| --- | --- | --- | --- | --- | --- |
|
||
| Story-Anweisung | 28 / 93 | 28 | 1 | 0,10313 / 0,10226 s | 0,00359 / 0,00343 s |
|
||
| README-Summary-Anweisung | 2720 / 121 | 2048 + 671 + 1 | 2 | 2,61440 / 2,58890 s | 0,04834 / 0,05187 s |
|
||
| Python-Anweisung | 33 / 2841 | 33 | 1 | 0,11914 / 0,11780 s | 0,00439 / 0,00518 s |
|
||
|
||
Alle sechs vollständigen F32-Endtensor-Hashes (Logits und Hidden je Erweiterung),
|
||
die Fortschrittsfelder und MTP-Offsets 120/2840/2873 stimmen exakt. Die höheren
|
||
Rust-History-Rohzeiten bleiben sichtbar. Dies sind einzelne instrumentierte
|
||
Numerikläufe, keine balancierte 2%-Abnahme. Die drei Folge-Anweisungen wurden
|
||
hier **nur vorgefüllt**: keine drei vollständig generierten Antworten und kein
|
||
vollständiger SessionBank-/UI-/Harness-Chat werden daraus behauptet.
|
||
|
||
Canary MTPLX/Rust: 120/111 Proben, keine Fehler/Abbrüche; Maximum der gemeinsamen
|
||
Prefill-Phase (kalter Ping plus warme Suffixe) 0,719/0,589 ms, Ping-Decode
|
||
0,161/0,182 ms. Kein UI-Eventloop gemessen. Supervisor-Gesamtzeit 13,374/12,461 s,
|
||
Peak-Footprint 81.600.772.008/81.307.416.056 Bytes. Alle Modellläufe einzeln,
|
||
81920-MiB-/30-s-Start-/45-s-Fortsetzungsbudget und durchgehende 2-s-GPU-Canary.
|
||
Release-Testbuild, warnings-denied Clippy und Format-/Diffprüfung bestanden.
|
||
|
||
**Schutzkorrektur am Test-Wächter:** Der bisherige Ausgabe-Watchdog konnte durch
|
||
workerinterne Canary-Meldungen einen Stillstand der eigentlichen Inferenz
|
||
übersehen. `test-supervisor` leitet diese Meldungen weiterhin vollständig
|
||
weiter, zählt die bekannten GPU-Canary-/Ressourcen-Messereignisse aber nicht
|
||
mehr als Fortschritt. JSON wird über Pipe-Lesegrenzen zusammengesetzt;
|
||
normale Teilzeilen wie Rust-Testbanner bleiben Fortschritt, Pufferung ist
|
||
begrenzt. CPU-Selbsttests prüfen auch Start-/Fortsetzungsabbruch trotz endloser
|
||
Canary-Ausgabe und erlauben einen tatsächlich fortschreitenden Lauf über
|
||
mehrere Timeoutfenster: drei Tests, 2,39 s, bestanden. Neues Release-Binary
|
||
des Wächters gebaut. Das bleibt ein kooperativer Ausgabe-Wächter, kein Beweis
|
||
für GPU-Fortschritt aus beliebigen Worker-Logs und keine Garantie gegen einen
|
||
nicht unterbrechbaren Treiberfehler. Kein neuer GPU-Lauf war dafür erforderlich.
|
||
|
||
Weiter offen am warmen Pfad: SessionBank-Auswahl, Snapshot-/Checkpoint-Restore,
|
||
Policy-Wechsel AR/MTP, optionale recurrent Boundary-Captures, Vision-Splicing,
|
||
Cleanup/Repaging und zusätzliche Abort-/AR-Referenzfälle. Der kanonische Pfad
|
||
bleibt `cfg(test)`, bis seine produktiven Owner-Verträge verbunden sind.
|
||
Kein Bundle, Commit oder Push.
|
||
|
||
**Trunk-/MTP-Snapshot und Restore, 2026-09-10:**
|
||
`qwen_mtplx/session_cache.rs` verbindet die vorhandenen Cache-/Arraytypen mit
|
||
den originalen `snapshot_cache`, `snapshot_cache_lazy_hybrid` und `restore_cache`
|
||
aus dem gepinnten `mtplx/cache_state.py:4334–4482`. Recurrent/GDN/PLE-Zustände
|
||
werden wie `_clone_tree` durch lazy Add-zero-Ausdrücke kopiert. Trimmable
|
||
QSA-Zustände bleiben beim Lazy-Snapshot gehaltene Views; der Restore erzeugt
|
||
neue mutable Array-Container statt die gespeicherten Container einzusetzen.
|
||
Die vorhandene Donation-Prüfung schützt die gehaltenen Deskriptoren. Offset,
|
||
Raw-/Pool-Frontier und Kapazitäten kommen aus dem originalen QSA-State-Setter;
|
||
abgeleitete Mirrors und Verify-Captures sind keine Snapshot-Blätter.
|
||
Keine erzwungene Auswertung oder zusätzliche Synchronisation im Snapshot/Restore.
|
||
|
||
Der bestehende Vollmodelltest und sein Original-Oracle wurden um drei echte
|
||
Snapshot-/Fresh-container-Restores erweitert: lazy / kopiert / lazy, mit
|
||
28 / 2720 / 33 Suffix-Tokens. Für sämtliche Cache-Blätter (Dtype, Shape,
|
||
vollständige F32-Werte) werden gemeinsame SHA256-Belege geprüft, getrennt für
|
||
Trunk und MTP. Gespeicherte Zustände müssen auch nach der Fortsetzung exakt
|
||
unverändert sein. Alle sechs finalen Logits-/Hidden-Hashes, Chunk-Fortschritte,
|
||
History-Offsets und die vorausgehenden 52 Ping-Tokens/19 MTP-Zyklen stimmen.
|
||
|
||
Rohdaten: `local-eval-results/session-cache-20260910.KesHxk/reference.*.log`
|
||
und `rust.*.log`. Erster Rust-Lauf bestanden in 14,27 s; dabei materialisiert
|
||
die diagnostische Hashprüfung den Snapshot noch vor dem Restore. MTPLX/Rust:
|
||
Supervisor 15,102/14,990 s, Lifetime-Peak 81.965.136.024/81.545.557.784 Bytes,
|
||
Canary 140/139 Proben ohne Fehler. Prefill-Maximum 4,643/6,774 ms,
|
||
Decode-Maximum 0,507/0,137 ms. Diese instrumentierten Einzelläufe sind kein
|
||
sauberer Performancevergleich; insbesondere lief jeweils zusätzlich ein
|
||
CPU-Build beziehungsweise Clippy. Kein UI-Eventloop und keine drei generierten
|
||
Folgeantworten gemessen.
|
||
|
||
Der strengere Regressionstest liest die gespeicherten Rust-Blätter erst
|
||
**nach** der Fortsetzung und vergleicht dann mit den unveränderten
|
||
Original-Belegen vor/nach Mutation. Dieser strengere Lauf
|
||
(`rust-lazy.*.log`) ist ebenfalls vollständig bestanden: 12,00 s Testzeit,
|
||
12,719 s Supervisorzeit, Lifetime-Peak 81.546.377.248 Bytes. Kein paralleler
|
||
Build/Clippy oder anderes Modell; 117 Canary-Proben, null Fehler, Maximum
|
||
3,146 ms. Der rohe OS-Disk-Write-Zähler liegt nahe u64::MAX und ist ungültig;
|
||
er wird nicht als IO-Leistungswert interpretiert. Alle gespeicherten Blätter
|
||
und sechs Fortsetzungstensoren stimmen weiterhin exakt mit MTPLX. Damit ist
|
||
auch Restore ohne diagnostisches Vorab-Materialisieren geprüft, nicht nur
|
||
der erste, bereits ausgewertete Snapshot-Lauf.
|
||
Release-Testbuild, gezieltes warnings-denied Clippy für App/Tests/Wächter,
|
||
`cargo fmt --all -- --check` und `git diff --check` bestanden. Keine Downloads,
|
||
kein Bundle, Commit oder Push; sämtliche Modellprozesse regulär beendet.
|
||
|
||
SessionBank-Auswahl/Metadaten, Disk-Checkpoints, AR/MTP-Policy-Wechsel und die
|
||
produktive Owner-Anbindung sind damit noch nicht implementiert. Der neue
|
||
Executor bleibt testintern; die sechs UI-identischen Paritätsläufe sind offen.
|
||
|
||
**Vollständiger Session-Chat, 2026-09-10:**
|
||
`session_cache::SessionSnapshot` hält nun Tokenpräfix, finale Logits/Hidden,
|
||
Trunk-, MTP- und recurrent Boundary-Zustände. `capture_session` und
|
||
`restore_session` verwenden die echten SessionBank-Payload-Regeln: Lazy-Trunk
|
||
abhängig von der Bankpolicy, MTP immer per vollständigem `snapshot_cache` und
|
||
beim Restore ebenfalls geklont, Logits/Hidden beim Speichern und Wiederherstellen
|
||
jeweils `_clone_tree`. Nicht passende Tokenpräfixe werden vor Mutation abgelehnt.
|
||
Dies ist die Zustandsübergabe im Executor, noch keine vollständige SessionBank
|
||
mit Identitätsauswahl, Eviction, SSD-Cold-Tier und UI-Anbindung.
|
||
|
||
`tools/mtplx-execution-reference.py --chat --readme README.md` nutzt jetzt die
|
||
**originale SessionBank** zusammen mit `generate_ar` beziehungsweise
|
||
`generate_mtpk`: README-Summary → vollständige Story → Python-Primzahlfunktion,
|
||
mit allen vorherigen Ausgabetokens im nächsten Prompt. Alle drei Antworten
|
||
enden natürlich; kein Tokenlimit als Testabschluss, keine Tools/Skills oder
|
||
Downloads. Seed 0, Temperatur 0,6, top-p 0,95, top-k 20, Low-Thinking,
|
||
2048er Prefill, SSD-PLE, MTP-D3/committed/batched, originale Serverdefaults.
|
||
Der bestehende Referenz-Runner wurde erweitert, kein weiterer Modellpfad gebaut.
|
||
|
||
**Erst durch die Session-Reproduktion sichtbar gewordene Abweichung:**
|
||
Der erste Rust-MTP-Chat (`rust-mtp.*.log`) bricht am achten ausgegebenen Token
|
||
des Summary-Turns ab: Soll 3766, Ist 19953. MTPLX aktiviert mit SessionBank
|
||
`_gdn_boundary_capture_enabled` und verfeinert den letzten Prefill-Body-Span
|
||
mit `_prefill_spans_with_tail_grid`: nicht 2048+699, sondern
|
||
**2048+256+256+187**, danach das letzte Token separat. Die bisherigen isolierten
|
||
Generator-/Suffixfixtures hatten keine SessionBank und prüften deshalb diesen
|
||
Requestpfad nicht. Die globale Chunkgröße wird ausdrücklich nicht reduziert.
|
||
|
||
Der gemeinsame Rust-Prefill-Treiber benutzt jetzt dieselbe Spanaufteilung bei
|
||
aktivierter Boundary-Policy. Nach dem History-Update werden nur recurrent
|
||
GDN/PLE-Zustände geklont; vorhandenes Hidden wird über `contiguous` ausgewertet
|
||
und gehalten, wie `detach_array_leaf(..., mode="contiguous_eval")`. Geometrische
|
||
Retention begrenzt die Snapshotzahl. Finale Sessions erben diese Grenzen und
|
||
ersetzen im geprüften geradlinigen Chat ältere Präfixeinträge. Explizite
|
||
Mandatory-Edges werden vom gemeinsamen Spanhelfer unterstützt; die produktive
|
||
Stable-Prefix-/Near-Prefix-Auswahl ist weiterhin offen.
|
||
|
||
**Nach Korrektur beide vollständigen Chats bestanden:** jede ausgesendete
|
||
Token-ID, jedes natürliche EOS, alle finalen vollständigen F32-Logit-/Hidden-
|
||
Hashes, alle MTP-Zyklen (inklusive Context-Copy), MTP-Offsets und geerbten
|
||
Grenzpositionen sind exakt wie MTPLX. Die vier Grenzen bleiben in allen Turns
|
||
2048/2304/2560/2747. Rust hält Prompt-Snapshots während Decode und nutzt echte
|
||
Snapshot-/Restore-Container für die folgenden Turns; kein stiller Cold-Replay.
|
||
|
||
| Modus / Turn | Prompt | davon wiederverwendet | Output einschließlich EOS |
|
||
|---|---:|---:|---:|
|
||
| AR Summary | 2748 | 0 | 635 |
|
||
| AR Story | 3411 | 3383 | 1347 |
|
||
| AR Python | 4791 | 4758 | 266 |
|
||
| MTP Summary | 2748 | 0 | 466 |
|
||
| MTP Story | 3242 | 3214 | 1394 |
|
||
| MTP Python | 4669 | 4636 | 326 |
|
||
|
||
Rohdaten: `local-eval-results/session-chat-20260910.jT3hf5/`.
|
||
Maßgeblich `reference-{ar,mtp}-boundary.*.log` und
|
||
`rust-{ar,mtp}-boundary.*.log`; ursprüngliche Referenzen und der fehlerhafte
|
||
Rustlauf bleiben erhalten. Die ergänzte MTP-Referenz liefert gegenüber ihrem
|
||
ersten Lauf unveränderte Tokens, Zyklen und Endtensor-Hashes in allen drei Turns.
|
||
Ausgaben wurden gelesen: zusammenhängende Summary und vollständige Story ohne
|
||
Rückfrage, Python enthält die erwartete `is_prime`-Funktion mit fünf Assertions.
|
||
Generierter Code wurde dabei nicht ausgeführt; das ist noch keine automatische
|
||
inhaltliche Benchmark-Abnahme.
|
||
|
||
Alle Modellläufe einzeln unter 81920 MiB / 30-s-Start / 45-s-Fortsetzung und
|
||
durchgehender 2-s-GPU-Canary. Keine Canaryfehler. AR MTPLX/Rust: 661/550 Proben,
|
||
Prefill-Maximum 2,342/1,653 ms, Decode-Maximum 0,935/0,786 ms; Lifetime-Peak
|
||
82.686.638.304/82.424.002.208 Bytes. MTP: 566/561 Proben, Prefill-Maximum
|
||
97,546/0,810 ms, Decode-Maximum 0,540/0,715 ms; Lifetime-Peak
|
||
83.454.868.352/82.950.518.912 Bytes. Kein GUI-Eventloop wurde gemessen.
|
||
|
||
**Keine 2%-Freigabe:** instrumentierte numerische Läufe ohne separaten Warmup,
|
||
bei Referenzläufen teilweise paralleler CPU-Testbuild. Original-`elapsed_s`
|
||
enthält andere Phasengrenzen als der innere Rust-Decode-Zähler. Trotzdem bleibt
|
||
ein konkreter Performanceverdacht sichtbar: MTP-Story benötigt in Rust bereits
|
||
31,663 s Decode, gegenüber 29,938 s für den gesamten entsprechenden
|
||
Referenz-Generierungsaufruf. Das wird nicht durch die funktionale Gleichheit
|
||
oder die kurzen Canaryzeiten als erledigt behandelt. Saubere gepaarte
|
||
Performanceabnahme folgt am vollständig integrierten UI/Harness-Pfad.
|
||
|
||
Bestehende modellfreie Prefill-Regressionen unverändert bestanden: 656 MTP-
|
||
und 505 AR-Receipts, zwei Tests in 0,32 s unter 2048-MiB-/15-s-Wächter.
|
||
CPU-Policytest prüft Tail-Grid/Mandatory-Edges und geometrische Retention;
|
||
die tatsächliche gepinnte Pythonfunktion lieferte zusätzlich exakte Cap-8-/64-
|
||
Belege. Die native Ganzzahlrechnung sättigt das Potenzprodukt, um Python-
|
||
Integersemantik auch bei großem Retentionslimit zu erhalten.
|
||
Abschließender Release-Testbuild, Cap-8-/64-Policytest, gezieltes warnings-denied
|
||
Clippy für App/Tests/Wächter sowie Format-/Diffprüfung bestanden. Die abschließende
|
||
Änderung betrifft nur den Überlaufschutz bei großem Retentionslimit; die
|
||
Vollmodellläufe benutzen vier Grenzen unter dem unveränderten Limit acht.
|
||
Alle Modellprozesse sind regulär beendet. Kein Bundle, Commit oder Push.
|
||
|
||
**Gemeinsamer Token-Turn-Einstieg, 2026-09-10:**
|
||
`Execution::session_turn` in `qwen_mtplx/session_cache.rs` übernimmt jetzt
|
||
Cold-/Restore-Prefill, AR-/MTP-Decode, die während Decode gehaltene
|
||
Prompt-Snapshot-Referenz und den sicheren finalen Snapshot. Der vollständige
|
||
Chat-Test ruft diesen Einstieg auf; seine zuvor eigene Prefill-/Decode-Steuerung
|
||
ist entfernt. Vorhandene Treiber bleiben unverändert, keine neuen Kernel oder
|
||
Dependencies. Dies bereitet die gemeinsame Produktanbindung vor, aktiviert sie
|
||
aber noch nicht: `qwen_mtplx` bleibt `cfg(test)`.
|
||
|
||
Finale MTP-Arrays sind nur bei angefordertem Capture und ohne Pending-Token oder
|
||
Capture-Fehler bankfähig. Ein fehlgeschlagener Snapshot wird separat gemeldet,
|
||
nicht als Verlust einer fertig generierten Antwort. Der CPU-Test
|
||
`mtplx_session_final_state_requires_capture_and_safe_cache` prüft fehlendes,
|
||
abgeschaltetes, erfolgreiches und fehlgeschlagenes Capture sowie den Pending-Fall;
|
||
er erzeugt nur unallokierte Array-Deskriptoren, keine GPU-Arbeit. Der unveränderte
|
||
Promptzustand bei null MTP-Ausgabetokens bleibt entsprechend der Referenz erlaubt,
|
||
wenn Capture ausdrücklich angefordert ist (`generation.py:12291`).
|
||
|
||
Beide vollständigen Chats gegen die vorhandenen `reference-{ar,mtp}-boundary`
|
||
Belege erneut bestanden: alle Tokens einschließlich natürlichem EOS, finale
|
||
Logit-/Hidden-Fingerprints, Cache-Präfixe und Boundary-Positionen; zusätzlich alle
|
||
MTP-Zyklen und History-Offsets. Keine Referenz neu erzeugt oder Erwartung geändert.
|
||
Rohdaten: `local-eval-results/session-entry-20260910.F1yAZH/{capture,ar,mtp}.*.log`.
|
||
|
||
| Modus / Turn | Ausgabetokens inkl. EOS | Prefill s | Decode s |
|
||
| --- | ---: | ---: | ---: |
|
||
| AR Summary | 635 | 6,213481 | 12,075834 |
|
||
| AR Story | 1347 | 0,105876 | 25,776388 |
|
||
| AR Python | 266 | 0,124386 | 5,102924 |
|
||
| MTP Summary | 466 | 5,956198 | 6,339998 |
|
||
| MTP Story | 1394 | 0,114543 | 27,345384 |
|
||
| MTP Python | 326 | 0,154080 | 4,225220 |
|
||
|
||
Alle Prozesse einzeln mit `test-supervisor`: CPU-Test 2048/15/15, Modelltests
|
||
81920/30/45, SSD-Ngram, originale Server-Overrides, Chunk2048, ohne Drosselung.
|
||
Der permanente 100-ms-GPU-Canary hatte AR/MTP 516/468 Proben, keine Fehler;
|
||
Prefill-Maxima 0,747/0,727 ms, Decode 0,559/0,540 ms, Laden 3,229/11,644 ms.
|
||
Peak-Footprint 82.422.937.008/82.943.817.736 Bytes; Supervisor 55,407/50,261 s,
|
||
beide regulär beendet. Kein CPU-Build parallel zu den Modellläufen.
|
||
Diese instrumentierten Kalt-/Fortsetzungsprüfungen ohne vorgeschalteten Warmup
|
||
sind weiterhin **keine** saubere 2%-Performanceabnahme und messen keinen GUI-Loop.
|
||
|
||
Release-Testbuild (`cargo test --release --offline --bin ds4-server --no-run -j 1`),
|
||
gezieltes Clippy mit `-D warnings`, Format-/Diffprüfung bestanden. Testbinary SHA256:
|
||
`14e13eaa14e810af12ad149e7b1ebe6bf231cef8129d7c951a5b4da661e74441`.
|
||
Weiter nötig für den Produktanschluss: Session-Auswahl/Identität und Disk-Payload,
|
||
Erhalt von Prefill-Bankeinträgen bei Abbruch, Abbruch-/Text-Stop-Ausgänge im Turn-Adapter,
|
||
Power-Pausen sowie gemeinsame Metriken. Keine Umschaltung auf den neuen Executor,
|
||
bevor diese bestehenden `Generator`-Verträge angeschlossen sind.
|
||
|
||
**Gemeinsame produktive Textausgabe, 2026-09-10:**
|
||
`Generator::generate_inner` verwendet jetzt `GeneratedText` für den bisherigen
|
||
UTF8-/Thinking-/Stop-Zustand. Die vorhandenen Helfer `append_generated_bytes`,
|
||
`emit_safe_text` und `flush_generated` werden unverändert wiederverwendet. Die
|
||
scalar Decode-Schleife enthält keine eigene Kopie dieser Zustandsübergänge mehr.
|
||
EOS, Abbruchprüfung, Completion-Zähler und Cache-Gültigkeit bleiben unverändert
|
||
beim Generator. Keine Änderung an Sampling, Prefill-Größe, GPU-Dispatch oder
|
||
Power-Policy; keine zusätzliche Dependency oder Queue.
|
||
|
||
Der kanonische Vollmodell-Chat verwendet exakt dieselbe Textausgabe im
|
||
Token-Callback, mit dem installierten Produkt-Tokenizer. Zusätzlich zur bisherigen
|
||
Token-/Zyklus-/Cache-Parität prüft er jetzt Thinking- und Antworttext sowie deren
|
||
gestreamte Chunks bytegenau gegen `chat_turn.text` der bestehenden MTPLX-Belege.
|
||
Alle sechs Turns erneut bestanden; Referenzen und Erwartungen unverändert.
|
||
Zwei CPU-Regressionstests (`generated_text_`) prüfen geteilte UTF8-Sequenzen,
|
||
unvollständige Sequenzen beim Drain/Phasenwechsel, Thinking-Ereignisse, einen
|
||
tokenübergreifenden Text-Stop und duplikatfreies abschließendes Flushen.
|
||
|
||
Rohdaten: `local-eval-results/shared-emission-20260910.IrS1L4/`:
|
||
`text-matched.*.log` (2 tatsächliche Tests), `ar.*.log`, `mtp.*.log`.
|
||
Das vorausgehende `text.*.log` traf mit falsch qualifiziertem Filter null Tests
|
||
und ist ausdrücklich kein Testnachweis.
|
||
|
||
| Modus / Turn | Thinking / Antwort Bytes | Prefill s | Decode s |
|
||
| --- | ---: | ---: | ---: |
|
||
| AR Summary | 194 / 2514 | 4,667441 | 12,064467 |
|
||
| AR Story | 226 / 5774 | 0,105925 | 25,786883 |
|
||
| AR Python | 142 / 711 | 0,125289 | 5,135448 |
|
||
| MTP Summary | 174 / 1837 | 5,230820 | 6,341459 |
|
||
| MTP Story | 270 / 5817 | 0,114802 | 27,293845 |
|
||
| MTP Python | 203 / 875 | 0,147034 | 4,231167 |
|
||
|
||
Unveränderte sequentielle Supervisor-Grenzen: CPU 2048/15/15, Vollmodell
|
||
81920/30/45, SSD-Ngram, Server-Overrides, Chunk2048, ungedrosselt, 100-ms-Canary.
|
||
AR/MTP: 504/460 Proben ohne Fehler oder 2-s-Stall; Prefill-Maxima 8,309/0,683 ms,
|
||
Decode 0,620/0,535 ms, Laden 3,334/4,606 ms. Peak-Footprint
|
||
82.497.910.432/83.026.982.920 Bytes; Supervisor 53,920/49,404 s, regulär beendet.
|
||
Keine parallelen Builds während der Modelltests. Release-Testbuild, gezieltes
|
||
Clippy mit `-D warnings`, Format-/Diffprüfung bestanden. Testbinary SHA256:
|
||
`e02b2d809197d224a56423b029f8e8dbc66c4f35a0f3cdbe727de019d8b81fa8`.
|
||
|
||
Dies verbindet die produktive **Ausgabe-Verarbeitung**, noch nicht den
|
||
kanonischen **Inferenz-Executor** mit UI/`model-eval`. Letzterer bleibt `cfg(test)`.
|
||
Session-/Disk-Adapter, Whole-Turn-Abbruch/Stop, Power und Metriken sind weiter
|
||
anzuschließen. Die Messungen sind instrumentierte Funktionsregressionen ohne
|
||
vorgeschalteten Warmup, keine 2%-Abnahme und kein GUI-Eventloop-Nachweis.
|
||
Kein Bundle, Commit, Push oder Download.
|
||
|
||
**Qwen-Checkpoint-Payload nach MTPLX, 2026-09-10:**
|
||
Der neue `qwen_mtplx/session_codec.rs` bildet für die vorhandenen typisierten
|
||
Qwen-Zustände `cache_bank/codec.py` ab: JSON-Baum mit Tuple-/List-/None-Metadaten,
|
||
Trunk, Logits, Hidden, MTP-Head und innere GDN-Grenzen. Die Blob-Namen folgen der
|
||
originalen Besuchsreihenfolge. Axis-2-Tensoren werden ab `2 * block_size` in
|
||
Blöcke zerlegt (Default der Referenz 256, null wird zu eins). Schreiben kann
|
||
über denselben Callback entweder gestaged oder direkt auf Disk erfolgen; die
|
||
fertigen Bytevektoren werden übergeben, nicht für den Speicher-Handler kopiert.
|
||
|
||
`bytes(memoryview(array))` wird nach der Auswertung mit vorhandenen
|
||
Array-/Buffer-Helfern in logischer C-Reihenfolge gelesen, auch für negative,
|
||
transponierte und Broadcast-Strides. Kein zusätzlicher GPU-Cast/Contiguous-
|
||
Dispatch zum Export. BF16 bleibt als rohe 16-Bit-Darstellung erhalten; Restore
|
||
verwendet den ursprünglichen View-/Reshape-/Concatenate-Pfad. Der skalare
|
||
Referenzfall Shape `[]` wird beim Restore wie im Original `[1]`, nicht heimlich
|
||
korrigiert. Abbruch wird vor jedem Tensor und jedem Block geprüft.
|
||
|
||
Vollständiger Payload-Restore und separat aufrufbarer Boundary-Restore bilden
|
||
die zwei originalen Routen ab. Ein exakter Restore kann Boundary-Blobs vollständig
|
||
überspringen; späterer partieller Restore liest ausschließlich diese Blobs.
|
||
Die separat gebatchte Boundary-Auswertung und anschließende Gesamt-Auswertung
|
||
bleiben erhalten. Ältere Payloads ohne `gdn_boundaries` und Records ohne
|
||
`hidden_last` werden wie in der Referenz akzeptiert. Ungültige Blob-Namen
|
||
(einschließlich Pfad-Traversal), falsche Bytezahlen und Lesefehler werden abgewiesen.
|
||
|
||
Referenz unverändert gepinnt auf `e652d55e2652137a4abcf1312357abbf3eb9d692`.
|
||
`tools/mtplx-session-codec-reference.py` verwendet dessen tatsächliche
|
||
`encode_payload`-/`decode_payload`-Funktionen mit kleinen synthetischen Tensoren,
|
||
keine Modellgewichte. Blockgrößen 0/256/1024 ergeben 1568/19/13 Blobs, jeweils
|
||
41.480 Payload-Bytes. Alle **1600 Blobs byteidentisch**, ebenso Payload-Spec,
|
||
restaurierte Datentypen/Shapes/Hashes und erneute Serialisierung. Der Rust-Test
|
||
liest die originalen Python-Dateien, nicht nur seine eigenen Writes. Zusätzlich
|
||
geprüft: selektive Blob-Zugriffe, Legacy-Records, Lesefehler, ungültige Namen,
|
||
abgeschnittene Daten und Abbruch vor dem zweiten Block nach genau einem Write.
|
||
|
||
Belege: `local-eval-results/session-codec-20260910.GQsCzv/`.
|
||
Maßgebliche finale Fixtures unter `compat/`, Logs `reference-compat.*.log` und
|
||
`rust-ready.*.log`; `rust.*.log` ist der vorausgehende erfolgreiche Grundvergleich.
|
||
Alle Programme einzeln unter `test-supervisor 2048 15 15`, keine geladenen Modelle
|
||
oder Downloads. Finaler Rust-Test: **1 Test bestanden**, 0,24 s Testzeit,
|
||
0,967 s Supervisor; Peak Physical 171.524.912 Bytes. Referenz-Supervisor 0,315 s,
|
||
Peak 156.140.192 Bytes; der winzige Referenzlauf überlappte einen CPU-Build.
|
||
Diese Werte sind Funktionsdiagnostik, **kein Performance-A/B**. Release-Testbuild,
|
||
gezieltes Clippy mit `-D warnings`, Format-/Diffprüfung bestanden; alle Tests beendet.
|
||
|
||
**Import-Korrektur nach vollständigem Caller-Trace (10.09.):** Die vorige
|
||
Forderung, hier einen Zero-Copy-Host-Owner zu portieren, war falsch. Zwar besitzt
|
||
`python/src/convert.cpp:190,259` einen `copy=None`-Übernahmepfad. Aber der tatsächlich
|
||
von `mtplx/cache_bank/codec.py:395–409` verwendete `mx.array(...)`-Konstruktor
|
||
übergibt in `python/src/array.cpp:311` ausdrücklich `create_array(v, t, true)`;
|
||
`convert.cpp:706–722` reicht dieses **copy=true** an `nd_array_to_mlx` weiter.
|
||
Deshalb kopiert der Codec auch seitenalignierten Host-Speicher. Der Default eines
|
||
internen Helfers ist kein Beleg für das Verhalten seines konkreten Aufrufers.
|
||
|
||
Die modellfreie Probe `tools/mtplx-host-import-reference.py` bestätigt direkt in
|
||
der unveränderten installierten MTPLX-Runtime: alignierte 16-KiB-, unalignierte
|
||
16-KiB-, kurze 17-Byte- und leere Eingaben werden nicht übernommen; keine hält den
|
||
NumPy-Host-Owner fest. Nach der Freigabe liegen 16384/16384/17/0 Bytes im Pool.
|
||
Belege: `local-eval-results/host-import-20260910.dfNdNK/reference-verified.stdout.log`
|
||
(finale Probe mit Assertions; `reference-default.stdout.log` war der erste
|
||
erfolgreiche Lauf).
|
||
Der erste Versuch mit einem `copy`-Keyword wurde vom Python-Konstruktor abgewiesen;
|
||
`reference.stdout.log` / `reference.stderr.log` sind **kein erfolgreicher Nachweis**.
|
||
|
||
Die reale Abweichung war das Umgehen des kanonischen Allocators außerhalb einer
|
||
GPU-Scope. `decode_tensor` kopiert nun ausdrücklich über `streams.allocator()`;
|
||
leere Tensoren behalten den bestehenden null-storage-Descriptor. Es wurde **kein**
|
||
Zero-Copy-/Host-Lifetime-Pfad oder neuer nativer Allocator eingeführt. Der gezielte
|
||
Rust-Test prüft Referenzgrößen, Copy-Semantik, View-/GPU-Hold-Lebensdauer, Pool-Rückgabe
|
||
und Wiederverwendung beim zweiten Import. **Beide Codec-Tests bestanden**:
|
||
`mtplx_session_codec_host_import_matches_reference` und
|
||
`mtplx_session_codec_matches_original_blobs_and_restore` (weiterhin alle 1600 Blobs).
|
||
Der neue Test läuft ausdrücklich ohne aktive GPU-Scope und würde bei der alten
|
||
`scalar_buffer`-Route an der aktiven Pool-Belegung scheitern.
|
||
|
||
Nachweise im selben Verzeichnis: `rust.stdout.log` / `rust.stderr.log`.
|
||
Supervisor 2048 MiB / Start 15 s / Fortschritt 15 s; keine Modelle, Downloads oder
|
||
parallelen Builds während der Proben. Beide Tests 0,24 s, Supervisor 0,938 s,
|
||
gemessener Peak Physical 168.657.664 Bytes. Der 0,105-s-Pythonlauf ist für eine
|
||
belastbare Peak-Speichermessung zu kurz; keine Performance-A/B-Aussage.
|
||
Release-Testbuild (`/tmp/ds4-host-import-build.log`), gezieltes Clippy mit
|
||
`-D warnings` (`/tmp/ds4-host-import-clippy.log`), Format-/Diffprüfung bestanden;
|
||
alle Prozesse regulär beendet. Testbinary SHA256:
|
||
`39a0165f0e0aa26b6a4db2075cb3f59786bef9a21db2395c381c46ecdeb4ef6e`.
|
||
Die native Bridge und Buffer-Lifetime-Implementierung wurden in diesem Schritt
|
||
nicht verändert. Die Python-Extension der unveränderten Referenz hat SHA256
|
||
`5ff77c777a73864d2af86defd61b141467746636f0047b76b66a7ae645fa12fb`.
|
||
|
||
**Qwen-Request-Grenze und abbrechbare Ausgabe, 2026-09-10:**
|
||
`qwen_mtplx/request.rs::Execution::generate_text` benutzt ausschließlich
|
||
`session_turn` für Prefill/AR/MTP und liefert das bestehende `GenerationOutput`
|
||
mit dem gemeinsamen `GeneratedText`. Es gibt keinen zusätzlichen skalaren
|
||
Sampling-/Decode-Loop. Tokenzähler schließen wie in der UI EOS aus, während der
|
||
Sessionzustand die vollständige Tokenfolge inklusive EOS behält. UTF-8,
|
||
Thinking-Wechsel und Text-Stops verwenden dieselbe Ausgabe-Verarbeitung wie die UI.
|
||
|
||
Ein tatsächlich im Adapter beobachteter Abbruch oder Text-Stop liefert den
|
||
bereits erzeugten Text, aber **keinen finalen Sessionzustand**. GPU-/IO-/Observer-
|
||
Fehler werden nicht als erfolgreiche Abbrüche verschluckt. Der Adapter versucht
|
||
nicht, einen möglicherweise vorausgerechneten AR-/MTP-Cache nach einem Stream-Stop
|
||
als vollständigen Chat zu speichern. Die nächste Generierung restauriert einen
|
||
gültigen Bankeintrag. Die Referenz speichert den Prompt bereits vor Decode
|
||
(`generation.py::_maybe_store_prefix_snapshot`, Zeilen 3888–3973); bisher hielt
|
||
Rust diesen Snapshot nur auf dem `session_turn`-Stack und verlor ihn bei Fehlern.
|
||
Nun übernimmt ihn ein Storage-Callback vor `TurnProgress::Decode`, sodass er
|
||
auch nach einem Abbruch beim Caller verbleibt. Ein fehlgeschlagenes Prefix-Store
|
||
bleibt wie in MTPLX nichtfatal (`prefix_snapshot_error`).
|
||
|
||
Der vorhandene Vollmodell-Chat-Test läuft jetzt durch diesen Request-Adapter,
|
||
nicht mehr durch einen separat im Test zusammengesetzten Text-Callback.
|
||
AR und MTP jeweils **1 Test bestanden**: alle drei natürlichen Antworten,
|
||
sämtliche Tokens und finalen Fingerprints, Boundary-Positionen und zusätzlich
|
||
alle MTP-Zyklen und Head-Offsets unverändert zur gespeicherten Referenz.
|
||
Zusätzlich je Modus: Abbruch vor Prefill ohne Ausgabe/Store, echter Observer-
|
||
Fehler bleibt Fehler, Abbruch nach erster Ausgabe erhält Teiltext und Prompt-
|
||
Snapshot, Literal-Stop leakt keinen Text, fehlgeschlagener Prefix-Store erreicht
|
||
trotzdem den Decode-Einstieg. Die zwei folgenden regulären Chat-Turns restaurieren
|
||
weiterhin exakt den gültigen Finalzustand, nicht die unterbrochenen Cache-Reste.
|
||
|
||
Belege: `local-eval-results/request-turn-20260910.lh9PZ4/{ar,mtp}.{stdout,stderr}.log`.
|
||
Nur installierte Qwen-Gewichte, sequentiell, kein paralleler Build; unveränderte
|
||
Referenz-Overrides, SSD-Ngram, Chunk2048, ungedrosselt, Supervisor 81920/30/45,
|
||
100-ms-GPU-Canary mit 2-s-Abbruch. AR/MTP 601/529 Canary-Proben, null Fehler/Stalls;
|
||
Prefill-Maxima 7,005/3,794 ms, Decode-Maxima 0,834/1,241 ms. Die zusätzlichen
|
||
Abbruch-Proben zwischen den regulären Turns liegen im äußeren Testabschnitt
|
||
`finishing`, nicht in einer nachgebildeten GUI-Phase. Kein GUI-Eventloop-Nachweis.
|
||
Peak Physical 82.724.992.648/83.067.795.392 Bytes; beide Supervisoren regulär beendet.
|
||
|
||
| Modus / Turn | Prefill s | Decode s |
|
||
| --- | ---: | ---: |
|
||
| AR Summary | 10,480830 | 12,810777 |
|
||
| AR Story | 0,111735 | 27,830894 |
|
||
| AR Python | 0,141198 | 5,605803 |
|
||
| MTP Summary | 9,687827 | 6,756337 |
|
||
| MTP Story | 0,122406 | 29,269802 |
|
||
| MTP Python | 0,154803 | 4,568898 |
|
||
|
||
Diese Zeiten sind gegenüber mehreren vorherigen Diagnostikläufen schlechter,
|
||
insbesondere der kalte Prefill. **Keine Performance-Parität oder unveränderte
|
||
Performance behauptet:** kein Warmup, keine zeitnah gepaarte Referenz und zusätzliche
|
||
Abbruch-Proben. Die Ursache der Zeitdifferenz ist damit nicht belegt und muss in
|
||
der kontrollierten End-to-End-Abnahme geprüft werden; die Funktionsprüfung darf
|
||
sie nicht als erledigt deklarieren. Release-Testbuild und gezieltes Clippy mit
|
||
`-D warnings` (`/tmp/ds4-request-{build,clippy}.log`), Format-/Diffprüfung bestanden.
|
||
Testbinary SHA256 `6c44e2150e9bc34e362d73fb5dd688357ca71e5f7fbed3179c9510ad42b12959`.
|
||
|
||
Der Request-Adapter bleibt Teil des `cfg(test)`-Ports. **Noch keine produktive
|
||
Umschaltung:** `Generator`/UI/`model-eval` müssen erst denselben Owner einschließlich
|
||
Session-Auswahl/Identität/Disk-Store, Power-Pausen und laufender gemeinsamer Metriken
|
||
benutzen. Die sechs 2%-Vergleiche bleiben vollständig offen; kein Bundle/Commit/Push.
|
||
|
||
**Gemeinsame Fortschritts-/Decode-Messung und frischer Golden-Master-Abgleich, 10.09.:**
|
||
`request::RequestProgress` liefert nun den bestehenden UI-/Runtime-Callback
|
||
`(used, limit, Option<decode_tps>)` ab dem gecachten Frontier, für Prefill und
|
||
jeden ausgegebenen Token. Der warme Backend-Fortschritt ist bereits absolut;
|
||
gecachte Tokens werden nicht doppelt addiert. Der Adapter nutzt `Metrics` für
|
||
Prefix-Reuse und denselben `DecodeTimer` wie die UI. AR und MTP melden ihre
|
||
Decode-Endgrenze jetzt **vor** finalem Token-/Cache-Capture; bisher kam
|
||
`TurnProgress::Finalize` erst danach. Normale Ergebnisse übernehmen die gemessene
|
||
Backend-Decode-Dauer, Fehler/Abbruch verwenden weiterhin die gemeinsame RAII-
|
||
Zeitmessung. Weder Sampling noch Shader/Command-Submission wurden verändert.
|
||
|
||
Zwei modellfreie Tests bestanden: `qwen_request_progress_uses_ui_frontiers_and_decode_timer`
|
||
und `decode_timer_excludes_later_work_and_resets_between_requests`. Die AR-/MTP-
|
||
Referenz-Chats samt Abbruchfällen jeweils erneut bestanden; zusätzliche Assertions
|
||
prüfen Start-/Endfrontier, jeden Token-Fortschritt, Kontextlimit und die exakt im
|
||
gemeinsamen Metrikobjekt gespeicherte Decode-Dauer. Belege:
|
||
`local-eval-results/request-progress-20260910.DvrBll/{timing,ar,mtp}.*.log`.
|
||
AR/MTP: 607/529 Canary-Proben, keine Fehler/Stalls; Prefill-Maxima 10,841/0,906 ms,
|
||
Decode 0,690/0,901 ms, Finishing 0,789/0,580 ms. Peak Physical
|
||
82.719.667.704/83.067.533.128 Bytes. Negative/übergelaufene OS-Disk-Write-Zähler
|
||
in diesen Logs sind ungültig und werden nicht als IO-Leistung interpretiert.
|
||
|
||
Die wiederholten kalten Prefills nahe 10 s wurden unmittelbar am unveränderten
|
||
MTPLX-Master gegengeprüft. Der erste AR-Referenzlauf benötigte 11,367 s, der zweite
|
||
9,664 s: **keine belegte Rust-spezifische Ursache für den Abstand zu älteren ~5–6-s-
|
||
Läufen**, aber auch keine Erklärung der äußeren Ursache allein aus diesen Proben.
|
||
Dabei wurde die Referenz-Metrikgrenze vollständig nachverfolgt:
|
||
`generation.py::_generation_rate_fields` zieht Prefill, Restore und sonstige
|
||
Prompt-Phase ab; `elapsed_s` ist dagegen die Gesamtspanne einschließlich Prefill.
|
||
Der Recorder gibt nun direkt `decode_elapsed_s`, `decode_tok_s` und
|
||
`prompt_state_total_time_s` aus, statt einen Vergleich mit reiner Rust-Decode-Zeit
|
||
aus der Gesamtzeit ableiten zu müssen. Modellfreier Original-Stats-Gegencheck
|
||
(`reference-rates.*.log`): 14 s Gesamtzeit minus 10 s Prefill, 1 s Restore, 1 s
|
||
sonstige Vorbereitung = 2 s Decode und 50 Token/s bei 100 Tokens.
|
||
|
||
Zeitnaher diagnostischer Vergleich, **kein Warmup/Median und keine produktive
|
||
UI-/Harness-Abnahme**. Beide Seiten dieselben installierten Gewichte, Server-
|
||
Overrides, Chunk2048, SSD-Ngram, niedriges Thinking, ungedrosselt/100 %, durchgängiger
|
||
100-ms-Canary mit 2-s-Abbruch, Supervisor 81920/30/45, sequentiell ohne CPU-Builds.
|
||
README-Prompt-SHA256 auf beiden Seiten
|
||
`69a37cf788e427fd384558517092e9a2a222f33910be63b48175516bf15ad84d`.
|
||
Neue Referenz-Receipts stimmen nach Entfernung ausschließlich der Zeitfelder mit
|
||
den bisherigen Tokens, Texten, Cache-Fingerprints, Boundaries und MTP-Zyklen überein.
|
||
Quellen: `reference-{ar,mtp}-rates.{stdout,stderr}.log` im selben Verzeichnis.
|
||
|
||
| Qwen / Prompt | Prefill Rust / MTPLX s | Decode Rust / MTPLX Token/s | Rust-Decode-Differenz |
|
||
| --- | ---: | ---: | ---: |
|
||
| AR Summary | 9,950 / 9,664 | 48,91 / 50,22 | −2,60 % |
|
||
| AR Story | 0,113 / 0,119 | 48,03 / 47,02 | +2,16 % |
|
||
| AR Python | 0,141 / 0,140 | 47,08 / 46,85 | +0,48 % |
|
||
| MTP Summary | 9,840 / 12,351 | 69,07 / 66,56 | +3,78 % |
|
||
| MTP Story | 0,121 / 0,125 | 47,89 / 45,83 | +4,49 % |
|
||
| MTP Python | 0,158 / 0,154 | 72,32 / 69,03 | +4,77 % |
|
||
|
||
Die Raten verwenden auf beiden Seiten Tokens inklusive EOS; die UI-Completion-
|
||
Zahl bleibt unverändert ohne EOS. Positiv bedeutet schneller. AR Summary verfehlt
|
||
in diesem Einzelvergleich 98 % der Referenzgeschwindigkeit; außerdem sind einzelne
|
||
Prefill-Vergleiche außerhalb 2 %. Das Gesamtziel ist damit ausdrücklich **nicht**
|
||
erfüllt. Native MTP-Akzeptanz (ohne Context-Copy-Zyklen), identisch in beiden Ports:
|
||
Summary 301/444 = 67,79 %, Story 746/1920 = 38,85 %, Python 225/279 = 80,65 %.
|
||
Das passt zum geringen MTP-Nutzen bei der Story und erklärt, warum kein pauschaler
|
||
Speedup vorausgesetzt werden darf; es ersetzt keine Zerlegung der einzelnen Kosten.
|
||
Die frischen Referenzen hatten 602/592 Canary-Proben ohne unvollständige Probes,
|
||
maximal 3,066/2,516 ms über alle Phasen. Alle Prozesse sind regulär beendet.
|
||
|
||
Release-Testbuild, Test- und Produktions-Clippy mit `-D warnings`, Format-/Diffcheck
|
||
bestanden (`/tmp/ds4-request-progress-{build,clippy,production-clippy}.log`).
|
||
Testbinary SHA256 `cfc781c74406ecef37d27c77ed9f204c6480b8326db1c2f14b1c277fae432eaa`.
|
||
Offen: produktiver Owner/Session-Store, gemeinsame Executor-Verdrahtung und echte
|
||
Power-Pausen unter 100 % (bei AR-Lookahead genügt Schlafen im Token-Callback nicht),
|
||
danach warme wiederholte Abnahme aller drei Modelle mit/ohne Spekulation. Dieser
|
||
Schritt fügt keine Warte-/Flushpunkte bei 100 % ein und erklärt den Test-Port nicht
|
||
zur produktiven UI-Ausführung. Kein Bundle, Commit oder Push.
|
||
|
||
**Backend-explizite Allokation als Integrationsvoraussetzung, 10.09.:**
|
||
`gpu::Buffer::{bytes,untracked}` hatten zuvor unter `cfg(test)` automatisch die
|
||
MTPLX-Rundungs-/Pool-Policy verwendet, während Produktbuilds direkt DS4 allozierten.
|
||
Dieser versteckte Backendwechsel ist entfernt. DS4/GLM und der alte Qwen-Executor
|
||
verwenden dieselben nativen Allokationsfunktionen unabhängig vom Buildtyp. Alle
|
||
Aufrufe im kanonischen Qwen-Graph und seinen Fixtures wählen ausdrücklich
|
||
`mtplx_bytes`, `mtplx_untracked` oder `mtplx_floats`; Rundung, leere Deskriptoren,
|
||
aktiver Pool und GPU-Lebensdauer bleiben für diesen Pfad unverändert. Keine neue
|
||
Allokator-Abstraktion, kein geänderter Kernel und keine Scheduling-/Power-Änderung.
|
||
|
||
Neun überwachte modellfreie Tests bestanden: vier Bridge-/Lebensdauerprüfungen
|
||
einschließlich der neuen Backend-Isolation innerhalb und außerhalb eines Qwen-
|
||
Scopes, vier vorhandene Allokator-Referenzprüfungen und die Encoder-/Pool-Anbindung.
|
||
Die neue Prüfung weist insbesondere nach, dass DS4-Allokationen keine MTPLX-
|
||
Rundung übernehmen und auch bei aktivem Qwen-Scope dessen Pool nicht beanspruchen.
|
||
Rohdaten: `local-eval-results/explicit-allocator-20260910.olnx1y/` mit
|
||
`allocation`, `allocator` und `encoder` stdout/stderr. Test- und Produktions-Clippy
|
||
mit `-D warnings`, Release-Testbuild, Format- und Diffprüfung bestanden.
|
||
Build-/Clippy-Logs: `/tmp/ds4-explicit-allocator-{build,clippy,production-clippy}.log`.
|
||
Testbinary SHA256 `d070eaa625a15a8d1abc6c4b23a0b28b057495b05e8417c732ed8cedbfc32cc4`.
|
||
|
||
Anschließend beide vollständigen Qwen-Referenz-Chats einschließlich der vorhandenen
|
||
Abbruch-/Text-Stop-/Cache-Fehlerfälle bestanden (`ar`/`mtp` stdout/stderr im selben
|
||
Verzeichnis). Unveränderte Referenzen `session-chat-20260910.jT3hf5/reference-{ar,mtp}-boundary.stdout.log`,
|
||
installierte Gewichte, Power100, Chunk2048, SSD-Ngram, sequentiell unter Supervisor
|
||
81920/30/45 und durchgängigem 100-ms-Canary; keine neuen Downloads. Referenztokens,
|
||
Texte, Cache-/Boundary-Zustände, MTP-Zyklen und gemeinsame Fortschritts-/Decode-
|
||
Metriken unverändert korrekt. AR/MTP: 604/551 Canary-Proben, keine Fehler oder
|
||
Stalls; GPU-Completion-Maximum Prefill 2,026/2,697 ms, Decode 0,658/1,175 ms.
|
||
Peak Physical 82.718.471.720/83.064.911.928 Bytes; Supervisor-Ende nach
|
||
62,657/58,785 s, beide exit 0. Diese kalten Einzel-Regressionsläufe sind weder
|
||
ein frischer gepaarter Performancevergleich noch die UI-/Harness-Endabnahme.
|
||
|
||
**Gemeinsame Modell-Metadaten vom alten Qwen-Executor entkoppelt, 10.09.:**
|
||
`engine::ModelRef::Qwen` verweist jetzt auf `QwenMetadata`, nicht mehr auf den alten
|
||
`QwenModel` mit dessen Gewichts-Mappings und PLE-Leserpool. Tokenizer, Chat-/History-
|
||
Rendering, Fortsetzung, Stop-/Thinking-Erkennung, Modellübersicht und Checkpoint-
|
||
Identität liegen in dieser gemeinsamen Struktur. Der bestehende Produkt-Executor
|
||
delegiert unverändert dorthin. Der separate Metadaten-Lader verwendet dieselbe
|
||
Artefakt-/Header-/Tokenizer-Validierung, öffnet aber keine Gewichts-Mappings,
|
||
GPU-Kontexte oder PLE-Leser; der kanonische Controller benötigt dafür keine zweite
|
||
Instanz des alten Modell-Executors. Sein vollständiger Chat-Test verwendet bereits
|
||
diesen Loader. Prefill-/Decode-Controller, Kernel und Persistierungsformat wurden
|
||
in diesem Schritt nicht verändert.
|
||
|
||
Vier überwachte Metadaten-/Artefakttests bestanden, darunter
|
||
`pinned_qwen_metadata_matches_product_without_executor_state`: mit/ohne MTP gleiche
|
||
Übersicht (2469/2527 Tensoren), gleiche Checkpoint-Identität, Direct-/Low-/XHigh-
|
||
Rendering, History und Fortsetzung einschließlich `skip_previous_eos`, Stop- und
|
||
Tokenbyte-Verhalten; zusätzlich bestehende Literal-Goldens und Fail-Closed-Prüfungen.
|
||
Rohdaten: `local-eval-results/qwen-metadata-20260910.qJ4vq2/metadata.{stdout,stderr}.log`.
|
||
Test-/Produktions-Clippy mit `-D warnings`, Release-Testbuild, Format-/Diffcheck
|
||
bestanden. Logs: `/tmp/ds4-qwen-metadata-{clippy,production-clippy,build}.log`.
|
||
Testbinary SHA256 `067370d61a22354d8de9ffe7bbd98d150b647b75b8b617dd7e96447d6465c2d2`.
|
||
Die vollständigen AR-/MTP-Chats mit dem separaten Metadaten-Lader bestanden danach
|
||
ebenfalls: gleiche eingefrorene Referenzen und Supervisor-/Power-/Canary-Einstellungen
|
||
wie oben, unveränderte Token-/Text-/Cache-/Boundary-/MTP- und Abbruch-Assertions.
|
||
Rohdaten `ar`/`mtp` stdout/stderr im selben Verzeichnis. AR/MTP: 571/553 Canary-Proben,
|
||
keine Fehler oder Stalls; maximale GPU-Completion im Prefill 2,261/2,347 ms, im
|
||
Decode 1,049/0,548 ms. Peak Physical 82.622.526.968/83.166.132.544 Bytes;
|
||
Supervisor-Laufzeit 59,333/57,389 s, jeweils exit 0. Keine neue gepaarte
|
||
Performance-Abnahme und keine Zuordnung der Prefill-Zeitstreuung zu diesem Patch.
|
||
Die produktive Turn-Auswahl bleibt noch auf dem alten Executor. Diese Entkopplung
|
||
schließt die gemeinsame Metadaten-Schnittstelle, nicht die Controller-/Cache-/Power-
|
||
Anbindung; noch kein neues UI-Bundle oder Nachweis der sechs Performance-Zellen.
|
||
|
||
**Power-Steuerung am kanonischen Executor angebunden, 10.09.:**
|
||
`Execution::load` nimmt jetzt den effektiven `power_percent` entgegen; 0 bedeutet
|
||
wie im DS4-Executor automatisch 100, Werte über 100 werden vor dem Modellladen
|
||
abgelehnt. Der reale Chat-Test bezieht den Wert aus `ExecutionPreferences` /
|
||
`EngineExecutionSettings`; Standard bleibt 100. `DS4_QWEN38_TEST_POWER=75` ist nur
|
||
ein expliziter Diagnosearm, keine Änderung der Paritätskonfiguration.
|
||
Die bestehende DS4-Formel ist als `throttle_delay` wiederverwendet:
|
||
EWMA 0,875/0,125, Pause = Mittelwert * (100-power)/power. Separate persistente
|
||
Prefill-/Decode-Mittelwerte; keine Pause im Text-Callback. Der AR-Pfad pausiert an
|
||
seinen Forward-/Lookahead-Grenzen, MTP nach abgeschlossenen Verify-/Repair- bzw.
|
||
ContextCopy-Runden; Prefill nach ausgeführten Chunks, History-Updates und Tail,
|
||
einschließlich restaurierter Suffixe. Vor dem Schlafen wird der Modellstream
|
||
synchronisiert, damit bereits eingereichte GPU-Arbeit nicht durch die Pause läuft.
|
||
Bei 100 werden weder zusätzliche Uhren gelesen noch Commands eingereicht oder
|
||
synchronisiert. Keine Chunk-Verkleinerung, keine Kerneländerung.
|
||
|
||
Pausenzähler und tatsächliche Schlafzeit werden in den Chat-Receipts getrennt
|
||
ausgewiesen; Prefill-Zeit enthält die zusätzliche Warte-/Pausenzeit, Decode-Wallzeit
|
||
ebenfalls. Der neue kleine Metal-Test lässt ein GPU-Ereignis zunächst uneingereicht:
|
||
bei 0/100 bleibt es uneingereicht (Commit-Zähler 0, kein Sleep-Aufruf), bei 75 muss
|
||
es vor Beginn des Sleep-Aufrufs signalisiert sein. Ein Drain-Fehler darf nicht
|
||
schlafen oder einen erfolgreichen Pausenzähler erhöhen. Ein separater CPU-Test
|
||
prüft dieselbe DS4-Mittelung und ihren 100%-Bypass. Diese Power-Anbindung liegt
|
||
weiterhin im `cfg(test)`-Controller, nicht im produktiv ausgewählten QwenExecutor;
|
||
die gesamte EngineSettings-/MTPLX-Serverdefault-Auswahl und Produktumschaltung
|
||
bleiben offen.
|
||
|
||
**Power-Verifikation:** Zwei gezielte Power-Tests plus die drei bestehenden
|
||
AR-/Prefill-Treiberreferenzen bestanden unter Supervisor `2048 15 15`.
|
||
Test-/Produktions-Clippy mit `-D warnings`, Release-Testbuild, Format und Diffcheck
|
||
bestanden; Logs `/tmp/ds4-power-{clippy,production-clippy,build}.log`.
|
||
Testbinary SHA256 `88429c4652219fa1c3db3fd544ee672c80ef2df849631b96560fb0ec4b06380b`.
|
||
Anschließend vollständige installierte Qwen-Chats, sequenziell AR100, MTP100,
|
||
AR75, MTP75, unter `81920 30 45` und durchgehendem Canary. Unveränderte
|
||
`session-chat-20260910.jT3hf5/reference-{ar,mtp}-boundary.stdout.log`-Referenzen,
|
||
SSD-Ngram, Chunk 2048, Low, Seed 0, gleiche Server-Flags wie im vorherigen Lauf.
|
||
Alle vier liefen bis EOS und bestanden sämtliche Prompt-/Token-/Text-/State-/
|
||
Boundary-/MTP-Cycle- sowie Owner-Abbruch-/Textstop-Assertions. Keine Assertion und
|
||
keine Referenz geändert. Zähler kumulativ über den Chat einschließlich kurzer
|
||
Abbruchproben; sie sind nicht mit der Anzahl sichtbarer Tokens gleichzusetzen.
|
||
|
||
| Modus | Supervisor s | Prefill-Pausen | Decode-Pausen | Canary-Proben | Prefill max ms | Decode max ms |
|
||
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
|
||
| AR 100 | 56,180 | 0 | 0 | 524 | 3,466 | 0,747 |
|
||
| MTP 100 | 56,282 | 0 | 0 | 527 | 3,780 | 0,720 |
|
||
| AR 75 | 90,502 | 7 | 2246 | 846 | 1,515 | 1,393 |
|
||
| MTP 75 | 90,247 | 15 | 892 | 844 | 2,645 | 1,130 |
|
||
|
||
Überall keine Canary-Fehler/Stalls. Bei 100 tatsächlich 0 s Schlafzeit. Bei 75
|
||
AR Prefill/Decode 7,464/22,663 s tatsächliche Schlafzeit, MTP 12,754/20,345 s.
|
||
Das Duty-Cycle-Setting ist keine Messung elektrischer GPU-Leistung; EWMA und
|
||
Aufwachlatenz erlauben keine pauschale lineare Laufzeitprognose. Peak Physical
|
||
AR100/MTP100/AR75/MTP75: 82.720.290.248 / 83.179.927.464 /
|
||
82.617.677.328 / 83.078.084.640 Bytes. Rohdaten:
|
||
`local-eval-results/qwen-power-20260910.K856XD/`,
|
||
`{throttle,drivers,ar100,mtp100,ar75,mtp75}.{stdout,stderr}.log`.
|
||
Die 100%-Läufe belegen Funktionsregression und ausgebliebene Drosselung; die
|
||
75%-Läufe belegen die aktivierte Steuerung. Kein frisches Referenzpaar, kein
|
||
Warmup-/Wiederholungsdesign, daher keine neue 2%-Abnahme aus diesen Diagnosezeiten.
|
||
Kein Bundle, Commit oder Push.
|
||
|
||
**EngineSettings und MTPLX-Serverdefaults im kanonischen Einstieg (10.09.):**
|
||
`Execution::open(&EngineSettings)` liefert Executor und bestehende `TurnOptions`.
|
||
Er übernimmt den installierten Modellpfad, integriertes MTP an/aus, Power und den
|
||
nativen Prefill-Chunk-Override (automatisch 2048). Die gemeinsame
|
||
`effective_settings`-Aufbereitung liefert nun auch im Drei-Turn-Test Engine- und
|
||
TurnSettings; die Referenzkonfiguration wird nur noch geprüft, nicht in die
|
||
Ausführungsoptionen kopiert. Der native Chunk-Vertrag entspricht dem begrenzten
|
||
Sustained-Pfad mit Final-Logits-Prefill. Die bisherige `Execution::load`-Methode
|
||
bleibt für unveränderte Modell-/Treiberdiagnosen ohne zusätzliche Serverdefaults.
|
||
|
||
Die Qwen-Verzweigung von MTPLX `_server_runtime_env_overrides` liegt als lokale
|
||
Override-Map vor: neun Family-Speed-Flags, gemeinsamer Compiled-GDN-Off-Schalter,
|
||
NAX-Verify-Default 0 und bei MTP zwingender Verify-Snapshot. Keine Env-Mutation,
|
||
keine TLS-Profilumschaltung. Gewichts-Fusion, CompilePolicy und alle produktiven
|
||
Graph-Options-Aufrufe des Controllers (auch ContextCopy-Repair) lesen diese Werte.
|
||
Explizite Operatorwerte bleiben gemäß Referenz erhalten; der zwingende Snapshot
|
||
ist dieselbe Ausnahme wie im Original. AR-Pipeline/Sync-Eval, native MTP-Tiefe 3,
|
||
Committed-History, Capture-/Repair-Flags, Cache-Snapshot-/Suffix- und Boundary-
|
||
Defaults werden in vorhandene Optionsstrukturen übersetzt. Das ist keine Abnahme
|
||
sämtlicher optionaler MTPLX-Generation-Lanes oder experimenteller Kernel-Overrides.
|
||
|
||
`tools/mtplx-policy-reference.py` ruft ausschließlich die Original-Konfigurations-
|
||
funktionen aus Commit `e652d55e2652137a4abcf1312357abbf3eb9d692` auf, ohne Modellladen
|
||
oder Generierung. 268 AR-/MTP-Fälle: unset, explizit ein/aus, leere und ungültige
|
||
Werte, GDN-Interlock, numerische Grenzen und Boolean-Aliase. Der erste Recorder-
|
||
Lauf deckte auf, dass Capture-Commit/Deferred-Repair anders als einfache `_env_truthy`
|
||
mit `env_bool` arbeiten: Aliase enable/disabled akzeptieren, ungültige Werte
|
||
ablehnen. Rust bildet diese Leser getrennt ab. Der korrigierte Recorder behält
|
||
Fehlerfälle als solche, statt sie auszuschließen. Alle 268 Vergleiche bestanden.
|
||
Der Seed der bestehenden eingefrorenen Vollmodellreferenz bleibt explizit 0 im
|
||
Executor-Test; `GenerationPreferences` akzeptiert aktuell nur positive explizite
|
||
Seeds. Dieser Fixture-Override ist **kein** Nachweis einer Seed-0-UI-Eingabe.
|
||
|
||
Danach AR/MTP-Vollchats über `Execution::open`, jeweils 100 %, Low, 2K, SSD-Ngram,
|
||
Supervisor `81920 30 45` und durchgängiger Canary. Anders als zuvor keine manuell
|
||
gesetzten Qwen-Speed-, Compile-, Sustained- oder Snapshot-Flags: sämtliche 12/13
|
||
in `qwen_runtime_setting` protokollierten Umgebungswerte waren `null`; effektive
|
||
Werte exakt wie die eingefrorene Referenz. Beide Chats einschließlich aller
|
||
Prompt-/Output-/Logits-/Hidden-/Cache-/Boundary-/MTP-Cycle- und Abbruch-Assertions
|
||
bestanden. Keine Referenz und keine bestehende Assertion abgeschwächt.
|
||
AR: 562 Canary-Proben, Prefill/Decode-max 1,416/0,804 ms, Peak Physical
|
||
82.725.746.312 Bytes, Supervisor 58,395 s. MTP: 549 Proben, max 2,085/0,559 ms,
|
||
Peak Physical 83.187.169.336 Bytes, Supervisor 57,055 s. Keine Fehler/Stalls,
|
||
keine Drosselungspausen. Drei bestehende AR-/Prefill-Treiberreferenzen ohne
|
||
Servervorgaben bestanden anschließend ebenfalls.
|
||
|
||
Rohdaten: `local-eval-results/qwen-policy-20260910.FBHrg3/`,
|
||
`{reference,reference-fixed,policy,drivers,ar,mtp}.{stdout,stderr}.log`.
|
||
Finale Binary SHA256 `2711ff2ae542a91d0c62d69fccc7e62de0deb4a91a884dfd9cb924e03ea559c5`.
|
||
Test-/Produktions-Clippy, Release-Testbuild, Format und Diffcheck bestanden;
|
||
Logs `/tmp/ds4-policy-{clippy-final,production-clippy,build-final}.log`.
|
||
Der Controller ist weiterhin `cfg(test)`; dieser neue Einstieg wird noch nicht
|
||
vom produktiven Generator ausgewählt. KV-Persistierung, produktive Umschaltung,
|
||
UI-/Harness-Abnahme und gepaarte sechsstellige Performance-Matrix bleiben offen.
|
||
Kein Bundle, Commit oder Push; keine 2%-Abnahme aus diesen Diagnosezeiten.
|
||
|
||
**SSD-Checkpoint am kanonischen Live-Owner (10.09., nach dem Policy-Nachweis):**
|
||
`qwen_mtplx/session_checkpoint.rs` verbindet den vorhandenen Referenz-Codec mit
|
||
`LiveSession::save_checkpoint/load_checkpoint`. Eine einzelne `QWMTKV01`-Datei
|
||
enthält rohe Tensorblobs und ein begrenztes Manifest; keine dtype-Konvertierung,
|
||
keine zweite Datenbank, keine neuen Writer-Threads. Die bestehende DS4-Verwaltung
|
||
übernimmt weiterhin Conversation-Key, Index, Prefix-Suche, Budget, Touch und Eviction.
|
||
Temporärdatei, `sync_all` und Rename folgen dem bestehenden Rust-DS4-Verfahren.
|
||
Modellidentität, Kontext, Vokabular, MTP, Tokenpräfix und vollständige Blobbereiche
|
||
werden geprüft. Abbruch-/IO-Fehler veröffentlichen weder einen partiellen Checkpoint
|
||
noch einen neuen Live-Zustand/Tag. Alte `DS4QWN01`-Dateien sind ausdrücklich inkompatibel
|
||
und müssen vom gemeinsamen Aufrufer als Cache-Miss/Rebuild behandelt werden.
|
||
|
||
Der modellfreie Metal-Test prüft bitgleiches Payload-/Blob-Roundtrip einschließlich
|
||
BF16, Recurrent-State, MTP und Boundaries, bytegenaue IO-Zähler, fehlende Datei,
|
||
Abbruch nach IO-Beginn, Modell-/Kontext-/MTP-Wechsel, ungültige Token, überlaufende
|
||
und falsche Blobbereiche, falsche Tensorgrößen, Trunkierung und altes Dateiformat.
|
||
Alle Fälle bestanden; ein fehlgeschlagenes Speichern bewahrt die vorherige Datei,
|
||
fehlgeschlagenes Laden den vorherigen Live-Zustand.
|
||
|
||
Der bestehende vollständige Drei-Turn-Oracle besitzt nun einen optionalen
|
||
`DS4_QWEN38_CHECKPOINT_DIR`-Diagnosepfad: nach jedem natürlich beendeten Turn
|
||
Speichern und `KvStore::record`, alle Live-Snapshots und die Engine verwerfen,
|
||
Engine erneut öffnen, `KvStore` erneut öffnen/find/touch und von SSD laden.
|
||
Es handelt sich um eine **prozessinterne Engine-Neuöffnung**, noch nicht um einen
|
||
Neustart des produktiven UI-Prozesses. Die Folge-Turns behalten unverändert sämtliche
|
||
eingefrorenen Prompt-/Output-/Logits-/Hidden-/Boundary-/MTP-Cycle-Assertions. Kein
|
||
RAM-Prefix bleibt als alternative Quelle erhalten. Summary → Story → Python
|
||
bestand AR und MTP bei Power 100, Low, Chunk 2048; keine Drosselungspausen, keine
|
||
zusätzlichen Voll-Prefills der bereits gecachten History.
|
||
|
||
| Modus | Checkpointgrößen, Turn 0/1/2 (Bytes) | Speichern (ms) | Laden (ms) | GPU-Canary max, gesamt / Prefill / Decode (ms) |
|
||
| --- | --- | --- | --- | --- |
|
||
| AR | 675831746 / 714926075 / 723427506 | 359,805 / 519,763 / 438,827 | 181,206 / 217,471 / 185,126 | 6,126 / 1,485 / 0,711 |
|
||
| MTP | 678764762 / 722567188 / 733621273 | 366,524 / 406,042 / 385,907 | 172,320 / 183,714 / 176,829 | 3,996 / 1,264 / 0,527 |
|
||
|
||
Canary durchgängig inklusive Speichern/Neuladen, 812/727 Proben, jeweils null
|
||
Fehler/Stalls. Die Gesamtmaxima liegen in Loading; dessen Phasenlabel umfasst
|
||
hier auch das SSD-Laden. Supervisor-Gesamtzeit 86,094/77,604 s, maximale Physical-
|
||
Footprints 81.629.560.424 / 82.099.961.736 Bytes. Genau ein Modellprozess, kein
|
||
Download, Supervisor `81920 30 45`; kein Gesamtlaufzeitlimit. Der kleine Test lief
|
||
separat mit `2048 15 15`. IO-/Neuladezeiten sind Diagnosewerte mit aktivem Canary
|
||
und warmem OS-Dateicache, keine SSD-Kaltstart- oder Performance-Paritätsabnahme.
|
||
|
||
Rohdaten: `local-eval-results/qwen-checkpoint-20260910.clSZAD/`,
|
||
`{small,ar,mtp}.{stdout,stderr}.log`, Testcheckpoints in `{small,ar-cache,mtp-cache}`.
|
||
Referenzen unverändert: `local-eval-results/session-chat-20260910.jT3hf5/`,
|
||
`reference-{ar,mtp}-boundary.stdout.log`.
|
||
Binary SHA256 `8e87e337ac78c502d0d03fccd7f375b61e13ae4cb446c88fad5aa99bcf7feda3`.
|
||
Test-Clippy und Release-Testbuild bestanden, Logs `/tmp/ds4-checkpoint-{clippy,build}.log`.
|
||
|
||
**Historischer Integrationsblocker (durch den folgenden Anschluss überholt):**
|
||
`qwen_mtplx` bleibt `cfg(test)`; der produktive
|
||
Generator wählt noch den alten Executor. Der neue Dateiadapter ist mit dem realen
|
||
KV-Index im Vollmodelltest geprüft, aber noch nicht mit Bootstrap, Sessionwechsel,
|
||
Kompaktierung und der produktiven Backend-Umschaltung verbunden. Erst deren
|
||
Anschluss macht diese Nachweise für UI und produktive Harness wirksam. Keine
|
||
UI-/Harness- oder 2%-Abnahme, kein Bundle, Commit oder Push.
|
||
|
||
**Produktiver Owner angeschlossen (10.09., nach dem SSD-Checkpoint-Nachweis):**
|
||
`Generator::open` wählt Qwen jetzt vor dem alten `LoadedModel`-Loader über
|
||
`Executor::open_qwen` aus. `qwen_mtplx` ist nicht mehr test-exklusiv. Der neue
|
||
`owner.rs` delegiert vollständige Turns an `LiveSession`, einschließlich AR/MTP,
|
||
anstatt den alten skalaren Generatorloop zu benutzen. Bootstrap-/Suffix-Prefill,
|
||
Reset, Resident-Sessionwechsel und Checkpoint-Dispatch erreichen denselben Owner.
|
||
Die gemeinsame Runtime bleibt der Einstieg von UI und `model-eval`. Der alte
|
||
Qwen-Executor bleibt für Diagnosepfade vorhanden, wird vom Generator nicht gewählt.
|
||
|
||
`qwen_product_generator_chat_matches_reference` bestand AR und MTP mit den
|
||
unveränderten drei eingefrorenen Referenzturns: natürliche Abschlüsse, exakte
|
||
Prompt-/Output-Tokens, Reasoning/Text sowie finale Logits-/Hidden-Hashes. Nach jedem
|
||
Turn werden Resident-Sessionwechsel und SSD-Restore über den wirklichen Generator
|
||
geprüft. Zusätzlich bestehen kalter und fortgesetzter Pure-Prefill und dessen
|
||
Abbruch ohne Veröffentlichung eines partiellen Zustands.
|
||
|
||
Rohdaten: `local-eval-results/qwen-product-20260910.8EeH8M/`,
|
||
`{ar,mtp}.{stdout,stderr}.log`; Testbinary SHA256
|
||
`4cb3f4e0b9e26f441088b8367f7d53a33f6a584a07424cc4ee0e356f44501e7d`.
|
||
Testzeiten AR 59,52 s / MTP 52,49 s, Canary 555 / 489 Proben, null Fehler/Stalls,
|
||
Maximum 3,475 / 4,045 ms. Dies sind überwachte Integrationstests, keine gepaarte
|
||
Performance-Abnahme. Die groben Phasen umfassen auch nachfolgende Checkpointarbeit;
|
||
ein UI-Render-/Eventloop-Nachweis ist damit nicht erbracht. Der OS-Disk-Write-Zähler
|
||
enthält ungültige Werte und ist kein Durchsatznachweis.
|
||
|
||
Offen nach diesem Anschluss: tatsächlicher Bootstrap-/Kompaktierungsablauf und
|
||
Abbruch/Fortsetzung im Generator, normaler Release-Worker mit prozesskaltem Ping,
|
||
Release-Bundle samt UI-Nachweis sowie die vollständige Performance-Matrix.
|
||
MTP-Zähler werden bisher am Turn-Ende veröffentlicht, PLE-Hot-Cache-Zähler sind
|
||
angebunden, weitere SSD-Zähler noch nicht. Die gemeinsame Buffer-Ownership wurde
|
||
für Produktion aktiviert; Auswirkungen auf DS/GLM müssen mitgemessen werden.
|
||
Optionale Referenz-APIs und historische Diagnoseadapter sind kein Nachweis, dass
|
||
alle optionalen MTPLX-Policies produktiv integriert sind.
|
||
|
||
**Lebenszyklus-Nachprüfung, erster Lauf:** Der ergänzte
|
||
`DS4_QWEN38_TEST_LIFECYCLE=1`-Pfad prüft nach dem Chat den echten
|
||
`prepare_bootstrap` samt Cache-Hit und `Generator::compact` samt Rebuild.
|
||
AR bestand die drei Referenzturns erneut, wurde danach im Kompaktierungs-Prefill
|
||
vom externen 80-GiB-Limit beendet: Physical-Peak 86.164.456.144 Bytes, Lauf
|
||
68,460 s, `memory_limit`. Kein erfolgreicher Kompaktierungsnachweis. Bis zum
|
||
Abbruch lagen Canary-Proben vor; eine finale Canary-Zusammenfassung fehlt wegen
|
||
des Supervisor-Abbruchs. Rohdaten `ar-lifecycle.{stdout,stderr}.log` im obigen
|
||
Produktverzeichnis. Wiederholung mit 88 GiB überwachten Speichergrenze, unveränderten
|
||
Modellparametern und unveränderter Ausführung; kein künstliches Cache-Leeren oder
|
||
Verkleinern von Prefill-Chunks. Testbinary SHA256
|
||
`6c72d5d8ba2ef563a4b5d945d4dc7d0098b16f849be0f126fdc10998eac308d8`.
|
||
|
||
**Lebenszyklus erfolgreich nachgeprüft (10.09.):** Die unveränderte Wiederholung
|
||
mit 88-GiB-Watchdog bestand AR und MTP einschließlich drei Referenzturns,
|
||
Bootstrap (37 Tokens), erneutem Bootstrap ohne Prefill und Kompaktierung samt
|
||
gespeichertem Rebuild. Rebuild 1961 / 2138 Tokens, jeweils `tail_start=2`,
|
||
nichtleere sinnvolle Task-State-Summary. Supervisor 69,176 / 64,457 s,
|
||
Physical-Peak 86.300.246.808 / 86.341.305.472 Bytes. Canary 643 / 599 Proben,
|
||
null Fehler/Stalls, Maximum 3,014 / 3,385 ms. Rohdaten
|
||
`{ar,mtp}-lifecycle-88g.{stdout,stderr}.log`. Die erhöhte Supervisorgrenze verändert
|
||
nicht die Engine oder ihre Speicherpolicy; kein Nachweis eines behobenen Leaks.
|
||
|
||
**Normaler Release-Worker, kalter Ping (10.09.):** `--warmup off` ist im
|
||
`model-eval` verfügbar, Default bleibt `on`; Options-Test bestanden. Normale
|
||
Binary SHA256 `89d6ef5ea14fbfdb980d4512aee89fbbb77955964f6f52ad8e4c963dd58c9f97`,
|
||
kein Testbinary-Einstieg. Power 100, Low, Chunk 2048, Kontext 32768,
|
||
Temperatur 0,6, top-p 0,95, min-p 0, Seed 42, Plain-Chat, maximaler Produkt-Tokenwert,
|
||
Canary an, 80-GiB-Watchdog, Startup 30 s / Fortschritt 45 s. Keine Downloads,
|
||
isolierte temporäre Sessions, kein Warmup und kein globales Leeren des OS-Dateicaches.
|
||
AR/MTP enden natürlich mit „Pong!“, 55 / 63 Completion-Tokens. Gesamt
|
||
10,157 / 9,384 s, Laden 6,406 / 5,495 s, gemeldetes Prefillfenster
|
||
2,617 / 2,296 s (einschließlich Systembootstrap), Decode 0,953 / 1,409 s.
|
||
Die 41 Prompttokens enthalten 30 im selben kalten Lauf aufgebaute Bootstrap-Tokens;
|
||
der Quotient aus 11 Suffix-Tokens und dem gesamten Prefillfenster ist deshalb
|
||
keine reine Kernel-Prefillgeschwindigkeit. Keine Paritätsabnahme aus kaltem Ping.
|
||
Canary-Maximum 3,703 / 3,935 ms, im Prefill 0,629 / 0,628 ms; kein Stall.
|
||
Headless-Control-Loop-Maximum 57 / 47 ms ist keine Messung des GUI-Eventloops.
|
||
Rohdaten `cold-ping-{ar,mtp}.{stdout,stderr}.log` im Produktverzeichnis.
|
||
|
||
Dabei neu belegt: normale GPU-Busy-/Command-Buffer-Zähler bleiben fälschlich null.
|
||
Der bisherige Recorder hängt am nativen DS4-Wait, den der kanonische MTPLX-Pfad
|
||
nicht benutzt. Die separate Canary-Messung ist davon unabhängig. Der Anschluss
|
||
an MTPLX-Command-Completion ist in Arbeit; keine zusätzlichen GPU-Waits/Flushes
|
||
als Instrumentationsersatz. Diese Nullwerte sind nicht als GPU-Leerlauf auszuwerten.
|
||
|
||
**GPU-Busy-Instrumentation korrigiert und nachgeprüft (10.09.):** Der vorhandene
|
||
native Recorder ist nun auch an die asynchrone MTPLX-Command-Completion angeschlossen.
|
||
Mutexgeschützte Snapshots verhindern konkurrierende Zugriffe von UI/Worker und
|
||
Completion-Thread; eine Mess-Epoche schließt nach Reset verspätet eintreffende
|
||
MTPLX-Completions aus dem vorherigen Messfenster aus. Keine neue GPU-Arbeit,
|
||
kein zusätzlicher Wait, Flush oder geänderter Kernel-/Submission-Plan.
|
||
Der bestehende Encoder-Regressionscheck prüft nun positive GPU-Zeit und exakt
|
||
eine Buchung je Command-Buffer auch nach späterem Wait; Canary-Probes bleiben
|
||
ausgeschlossen. Bestanden unter `test-supervisor 2048 15 15`,
|
||
`busy-counter.{stdout,stderr}.log`, Testbinary SHA256
|
||
`c7cf8b3d524673dad7e1cfeec6de4b7e419129c34f073f042dc377b80234136e`.
|
||
|
||
Erneuter normaler Release-Ping AR/MTP mit unveränderten Parametern, jeweils
|
||
prozesskalt: natürliches Ende, exakt gleiche Tokenzahlen, Reasoning und Antworten
|
||
wie vor der Messkorrektur. Binary SHA256
|
||
`4763e16687ed53c787825a391f45d51d6fe793f8bb6dc157bf7d4dfd627458ec`.
|
||
Rohdaten `cold-ping-{ar,mtp}-busy.{stdout,stderr}.log` im Produktverzeichnis.
|
||
|
||
| Messung | AR | MTP |
|
||
| --- | ---: | ---: |
|
||
| Gesamter Request inklusive Laden (s) | 8,630 | 8,721 |
|
||
| Modellladen (s) | 5,505 | 5,494 |
|
||
| Prefillfenster inklusive Bootstrap (s) | 1,989 | 2,276 |
|
||
| Decode-Loop (s) | 0,950 | 0,773 |
|
||
| Completion-Tokens | 55 | 63 |
|
||
| Decode-Loop tok/s | 57,90 | 81,54 |
|
||
| GPU-Zeit, Summe der Command-Buffer (ms) | 2121,73 | 1980,39 |
|
||
| Längster Command-Buffer (ms) | 112,22 | 120,46 |
|
||
| Command-Buffer | 12730 | 9162 |
|
||
| GPU-Canary max, gesamt / Prefill (ms) | 3,444 / 0,616 | 3,873 / 0,620 |
|
||
| Headless-Control-Loop max (ms) | 52 | 59 |
|
||
|
||
Canary 82 / 84 Proben, null Fehler/Stalls, Supervisor Exit 0. Summierte GPU-Zeit
|
||
ist keine queueübergreifende Vereinigungszeit. Unterschiedliche Pipeline-/OS-
|
||
Caches zwischen Prozessstarts verhindern eine Performance-Aussage aus dem
|
||
Vorher/Nachher-Ping; insbesondere die schnellere MTP-Wiederholung ist **kein**
|
||
belegter Beschleunigungseffekt der Messkorrektur. CPU-Overhead der Completion-
|
||
Instrumentation bleibt Teil der noch offenen warmen Referenzabnahme. Normaler
|
||
Headless-Einstieg ist jetzt geprüft, ein neues GUI-Bundle und GUI-Eventloop-Nachweis
|
||
bleiben offen. Keine Behauptung der vollständigen 2%-Parität.
|
||
|
||
**Laufende MTP-Zähler und Abbruch/Fortsetzung nachgewiesen (10.09.):**
|
||
Der kanonische `decode_mtp` meldet über den vorhandenen `TurnProgress`-Kanal jeden
|
||
abgeschlossenen Zyklus. Der produktive Owner veröffentlicht diese Werte sofort
|
||
in denselben atomaren `Metrics`, die UI und Harness lesen. Keine neue GPU-Arbeit,
|
||
kein zusätzlicher Thread und keine zusätzliche Synchronisation. Der bisherige
|
||
Turn-Ende-Sammelpass entfällt, damit keine doppelte Buchung entsteht. Verifier-
|
||
und Repair-Zeiten bleiben bis zur Umrechnung kumulativ innerhalb des Turns;
|
||
Sub-Millisekunden-Anteile werden nicht je Zyklus abgeschnitten. Bei Abbruch bleibt
|
||
der letzte beobachtete abgeschlossene Zyklus erhalten; unvollständige Zyklen
|
||
werden nicht als abgeschlossen behauptet.
|
||
|
||
Zusätzliche Zählkorrektur: Context-Copy-Runden führen ebenfalls einen gebatchten
|
||
Target-Verifier aus. Vorher wurden sie bei `verifier_passes` ausgelassen.
|
||
Der eingefrorene MTP-Chat enthält pro Turn 148+7, 640+2 und 93+2
|
||
MTP-/Context-Copy-Verifikationen. Native MTP-Draft-/Acceptance-Zähler zählen weiter
|
||
nur die nativen Drafts, nicht die kopierten Kontexttokens. Der modellfreie Test
|
||
prüft Live-Publikation ohne Turn-Ende, Zeit-Rundung, Context-Copy-Verify, Primary-EOS
|
||
ohne Verify und ausbleibende Doppelbuchung beim Finalize; bestanden.
|
||
|
||
Der vollständige Produkt-Generator-Test prüft jetzt zusätzlich, dass MTP-Zähler
|
||
bereits während der Textausgabe eintreffen, und vergleicht nach jedem Turn deren
|
||
Delta mit allen eingefrorenen Referenz-Cycles. AR muss die MTP-Zähler unverändert
|
||
lassen. Beide Modi bestehen weiterhin exakte Tokens, Texte, Logits-/Hidden-Hashes,
|
||
Resident-Switch und SSD-Restore.
|
||
|
||
Im erweiterten Lebenszyklustest wird auf einem kopierten Checkpoint ein
|
||
ununterbrochener Kontrollturn erzeugt. Abbruch vor Decode und während Decode
|
||
müssen die Originaldatei SHA256-identisch erhalten. Nach Aufhebung des Abbruchs
|
||
muss derselbe Request dieselben finalen Tokens, Reasoning und Text wie der
|
||
Kontrollturn liefern. AR und MTP bestanden jeweils mit 23 Completion-Tokens und
|
||
„PONG“. Abgeschlossene MTP-Zähler bleiben auch nach Abbruch sichtbar. Bootstrap-
|
||
Cache-Hit und Kompaktierung/Rebuild bestehen anschließend ebenfalls. Dies testet
|
||
den produktiven Generator, nicht UI-Buttonzustände oder jeden denkbaren IO-Abbruch.
|
||
|
||
Rohdaten: `local-eval-results/qwen-live-metrics-20260910.iD9AZm/`,
|
||
`{unit,ar,mtp}.{stdout,stderr}.log`, isolierte Checkpoints in `{ar,mtp}-cache`.
|
||
Testbinary SHA256 `d9c6fd174b51af793b61d0f06740cdc398fa85778fb8ec8d908ec442cbefa75b`.
|
||
Power 100, Low, Referenz-Seed 0, Chunk 2048, Kontext 32768; nur installierte
|
||
Gewichte. Volltests `test-supervisor 90112 30 45`, kleiner Test `2048 15 15`.
|
||
AR/MTP Supervisor 72,130 / 70,118 s; Physical-Peak 86.596.617.488 /
|
||
86.535.603.592 Bytes. Canary 672 / 651 Proben, keine Fehler/Stalls, Maximum
|
||
3,004 / 3,192 ms, im Prefill 0,887 / 0,998 ms. Keine warmen gepaarten
|
||
Performance-Abnahmen aus diesen Integrationsläufen. Clippy-Log
|
||
`/tmp/ds4-live-mtp-clippy3.log`, Build `/tmp/ds4-live-mtp-test-build.log`.
|
||
|
||
Die normale Harness serialisiert die kumulativen `speculation`-Felder nun auch
|
||
in `runtime_sample`, nicht nur als Turn-Delta im Endergebnis. Ein normaler
|
||
Release-Lauf zur Nachprüfung dieses JSON-Einstiegs ist wie folgt bestanden.
|
||
|
||
**Warmer laufender Chat über die normale Headless-Binary (10.09.):**
|
||
`warm-chat-mtp.{stdout,stderr}.log` im selben Verzeichnis, normale Binary SHA256
|
||
`b74e3126e911b3f57d83829ee216c77d45fbe29fb597694ab28c2895ec1301dc`.
|
||
`model-eval --warmup on --plain-chat on`, README-Summary → Lighthouse-Story →
|
||
Python `is_prime` mit fünf Assertions, ein zusammenhängender Chat. Power 100,
|
||
Low, Chunk 2048, Kontext 32768, Temperatur 0,6 / top-p 0,95 / min-p 0, Seed 42,
|
||
MTP an, Canary an, Speicherwatchdog 88 GiB, Startup 30 s / Fortschritt 45 s.
|
||
Keine Gesamtzeitbegrenzung; alle drei Messturns enden natürlich mit `stop`.
|
||
README SHA256 `80c01ea096843312de6662d3cd8c94c8e14bdf286b58824752981fc4920fd1f8`.
|
||
Der vollständige erste Prompt ist nach direktem JSON-Vergleich bytegleich mit
|
||
`reference-mtp-boundary.stdout.log`; die frühere Annahme eines abweichenden
|
||
README-Inhalts ist damit verworfen. Referenz-Seed 0 und erster Referenz-Prefill
|
||
ohne Bootstrap-Reuse unterscheiden sich von diesem Lauf: weiterhin keine
|
||
gepaarte Performance-Abnahme, keine Verrechnung als 2%-Pass.
|
||
|
||
| Messturn | Prompt / cached / completion | Gesamter Turn (s) | Prefillfenster tok/s | Decode-Loop tok/s |
|
||
| --- | --- | ---: | ---: | ---: |
|
||
| Summary | 2748 / 30 / 519 | 9,446 | 1304,22 | 72,14 |
|
||
| Story | 3296 / 3268 / 1450 | 28,113 | 264,15 | 52,13 |
|
||
| Python | 4780 / 4747 / 230 | 3,151 | 242,65 | 81,00 |
|
||
|
||
Während Decode enthält die Harness 7 / 27 / 3 `runtime_sample`-Ereignisse mit
|
||
steigenden kumulativen Cycle-Zählern 36→185 / 208→841 / 868→913, nicht erst
|
||
ein Endergebnis. Summary fachlich lesbar, abgeschlossene Lighthouse-Geschichte
|
||
ohne Rückfrage, Python-Code vor Ausführung geprüft. Die generierten fünf Asserts
|
||
und ein unabhängiger Trial-Division-Vergleich für -10 bis 5000 (5011 Fälle)
|
||
bestehen unter isoliertem Python mit 3-s-CPU-Grenze; keine Imports im generierten
|
||
Code, keine Netzwerk-/Toolnutzung. Beleg `python-validation.stdout.log`.
|
||
|
||
Gesamtprozess einschließlich Warmup 49,581 s, Supervisor Exit 0, maximaler
|
||
Fortschrittsabstand 1,625 s. Canary 456 Proben, null Fehler/Stalls, Maximum
|
||
3,293 ms; Headless-Control-Loop-Maxima 53 / 37 / 33 ms. Der Supervisor meldet
|
||
82.983.156.272 Bytes als abgetasteten Peak-Footprint; dieser ist kein lückenloser
|
||
Kernel-Lifetime-Peak. GPU-Busy-Zähler sind in allen Turns positiv. Clippy und
|
||
Formatprüfung bestehen (`/tmp/ds4-live-mtp-final-clippy.log`). Kein GUI-Bundle,
|
||
kein GUI-Eventloop-Nachweis und keine vollständige Referenzmatrix in diesem Schritt.
|
||
|
||
**Warmer Bootstrap-Suffix: Vergleichsprofil und Boundary-Lücke (10.09.):**
|
||
Die ersten Vergleichspaare unten sind **Zwischendiagnosen, keine Freigaben**.
|
||
Die strengere Zustandsprüfung deckte danach einen nicht angeglichenen Sustained-
|
||
Prefill-Modus auf. Maßgeblich ist die abschließende Profilkorrektur unten.
|
||
Der angeglichene Referenztreiber `tools/mtplx-execution-reference.py --source-run`
|
||
übernimmt den vollständigen normalen Harness-Startvertrag einschließlich
|
||
Warmup, Seed 42, Sampler-Floatwerten und Bootstrap-Reuse. Er akzeptiert nur drei
|
||
natürlich abgeschlossene Plain-Chat-Turns und prüft je Turn Prompt-, Cache- und
|
||
Ausgabetokenzahl sowie den vollständigen Text. Der erste Versuch gegen den oben
|
||
genannten alten Stand scheiterte ausdrücklich: Summary 448 statt 519 Tokens.
|
||
Rohdaten: `local-eval-results/qwen-matched-warm-20260910.ig0qT1/`.
|
||
|
||
Erste Untersuchung: MTPLX `_prefill_restored_prompt_suffix` übergibt die
|
||
Chunkgröße **implizit**. Ohne `MTPLX_SUSTAINED_PREFILL` ist zunächst der gesamte
|
||
Body ein Span, den die aktive rekurrente Boundary-Policy auf ihr 256er-Tailraster
|
||
aufteilt. Der kalte committed-MTP-Pfad dagegen übergibt 2048 explizit. Rust hatte
|
||
im warmen Pfad eine eigene gleichmäßige 2048er-Schleife und erfasste dort keine
|
||
Boundaries. Der erste Patch verwendete den vorhandenen `prefill::spans`-Helper
|
||
mit denselben Regeln und erfasst absolute rekurrente Zwischenzustände vor dem
|
||
History-Append. Optionale Capture-Fehler brechen wie im Original den Turn nicht ab.
|
||
Keine pauschale Änderung des UI-Chunkwerts und keine neue Cache-Persistenz.
|
||
|
||
Der neue normale MTP-Chat und der anschließende unveränderte MTPLX-Lauf stimmen
|
||
für **alle drei Turns** in Prompt-/Cache-/Ausgabetokenzahlen und vollständigem
|
||
Text überein: 2748/30/448, 3225/3197/997, 4256/4223/301. Beide enden natürlich.
|
||
Summary-Prefill-Fortschritt nun in beiden Pfaden: 30, 286, 542, 798, 1054, 1310,
|
||
1566, 1822, 2078, 2334, 2590, 2747, 2748. Damit ist die neue Warm-Prefill-Lücke
|
||
nicht bloß durch ein anderes gesampeltes Ergebnis verdeckt.
|
||
|
||
Rohdaten: `local-eval-results/qwen-warm-suffix-20260910.vWPeE5/`,
|
||
`product-mtp-metal.{stdout,stderr}.log` und `reference-mtp.{stdout,stderr}.log`.
|
||
Binary SHA256 `bff5b55c15a101f236f6bf3466d62154417ef9a93ee235b7efbae6ee570eddd9`.
|
||
MTP-Produkt: 401 Canary-Proben, null Fehler/Stalls, Maximum 3,158 ms,
|
||
Headless-Control-Loop-Maxima 38/32/44 ms. Prozess inklusive Warmup 43,565 s,
|
||
abgetasteter Peak-Footprint 80.643.439.968 Bytes. Referenz-Supervisor Exit 0,
|
||
44,238 s und Lifetime-Peak 81.251.187.272 Bytes. Sein Disk-Write-Rohzähler läuft
|
||
erneut über und ist kein brauchbarer IO-Nachweis.
|
||
|
||
Boundary-Regressionstest und Referenztreiber-Vertragstest bestehen, Release-Build
|
||
und fokussiertes Release-Clippy bestehen. Ein erster Sandbox-Versuch endete vor
|
||
der Inferenz mit fehlendem Metal-Gerät; der oben ausgewertete Lauf erfolgte mit
|
||
Metal-Zugriff. AR-Vergleich und exakte finale Tensor-/Tokenprüfung des warmen
|
||
Produkt-Generators folgen. Canary aktiv, Einzelpaare und teils parallele
|
||
CPU-Kompilierung: ausdrücklich **keine saubere 2%-Performance-Abnahme**.
|
||
|
||
**Strengerer Nachweis und abschließende Profilkorrektur:** Der vorhandene
|
||
Produkt-Generator-Test unterstützt nun Bootstrap/Warmup vor dem laufenden Chat
|
||
und prüft neben exakten Tokens, Texten und finalen Logits-/Hidden-Hashes auch
|
||
rekurrente Boundary-Positionen. Der erste MTP-Turn scheiterte (`exact-mtp.*`):
|
||
Rust bewahrte Bootstrap-Boundary 29, die Referenz nicht. Ohne Sustained-Modus
|
||
wählt MTPLX für den kalten MTP-Bootstrap `_prefill_with_hidden_sequence` ohne
|
||
Boundary-Capture; die UI nutzt hingegen den begrenzten Streaming-Pfad.
|
||
Der vorhandene `mtplx-policy-reference.py` bildet diese native Policy bereits
|
||
mit `MTPLX_SUSTAINED_PREFILL=1` ab. Dies fehlte im neuen Chat-Referenztreiber.
|
||
|
||
Der Treiber setzt jetzt denselben Sustained-Modus und den originalen
|
||
request-lokalen Chunk-Override. Rusts warmer Pfad verwendet entsprechend den
|
||
vorhandenen Spans-Helper mit 2048er-Hauptchunks und 256er-Unterteilung nur im
|
||
letzten Body-Chunk. Die zwischenzeitliche Unterteilung des gesamten Bodys nach
|
||
dem nicht angeglichenen Referenzprofil ist zurückgenommen. Die echte Korrektur
|
||
sind das fehlende Tail-Raster und absolute Captures vor dem History-Append,
|
||
nicht eine allgemeine Chunkverkleinerung. Optionales Capture bleibt wie im
|
||
Original fehlertolerant. End-to-end-Nachweise dieses endgültigen Profils stehen
|
||
zum Zeitpunkt dieses Eintrags aus; obige Text-Pässe ersetzen sie nicht.
|
||
|
||
Zusätzlich korrigiert: Der erste AR-Referenzlauf verlor den Bootstrap-Hit,
|
||
weil der Treiber `hidden_variant=None` statt der vom originalen Resolver
|
||
normalisierten Identität `post_norm` bankte. Nach Korrektur passen auch dort
|
||
die Texte aller drei Turns (`reference-ar-policy.*`), jedoch noch unter dem
|
||
zwischenzeitlichen Nicht-Sustained-Profil. Das war kein Produktfehler.
|
||
|
||
**Endgültiges Sustained-Profil in beiden Modi bestanden (10.09.):**
|
||
`local-eval-results/qwen-warm-suffix-20260910.vWPeE5/manifest.md` trennt alle
|
||
Zwischenstände von den maßgeblichen `*-sustained.*`-Receipts. Die normalen
|
||
UI-Runtime/Headless-Chats und originalen MTPLX-Chats stimmen in allen drei Turns
|
||
überein: AR 570/1129/266, MTP 438/1144/279 Ausgabetokens. Der erweiterte
|
||
Produkt-Generator-Test besteht für beide Modi außerdem exakte Tokens inklusive
|
||
EOS, finale Logits-/Hidden-Hashes, rekurrente Grenzen, laufende MTP-Zähler,
|
||
Resident-Wechsel und SSD-Restore. Die separate Lifecycle-Cancel-Erweiterung
|
||
wurde in diesen Wiederholungen nicht zugeschaltet. Python-Ausgaben bestehen
|
||
je fünf Assertions und 5011 unabhängige Fälle. Die fehlgeschlagenen strengeren
|
||
Tests bleiben erhalten; keine Abschwächung der Assertions für den grünen Stand.
|
||
|
||
Normale AR/MTP-Canary-Maxima 3,741/3,471 ms, null Fehler/Stalls; kein tatsächlicher
|
||
GUI-Eventloop-Nachweis. Release-Binary SHA256
|
||
`0ecc5f13e94a78f71c116d877ab0fa0101edf76e2b9b4cfdecc40c927d7e1b90`.
|
||
Fokussierte Tests, Clippy und Formatcheck bestanden. Die auffällig langsame
|
||
AR-Referenz in diesem Einzelpaar wird nicht als bewiesener Produktvorteil
|
||
gewertet: saubere alternierende Wiederholungen ohne Canary stehen aus.
|
||
GLM-2-Row-Verify, vollständige sechszellige Performance-Abnahme und aktualisiertes
|
||
GUI-Bundle bleiben offen. Die Warm-Prefill-Funktionslücke ist damit geschlossen,
|
||
nicht das gesamte Paritätsziel.
|
||
|
||
**Drei alternierende Paare pro Qwen-Modus ohne Canary — keine Abnahme (10.09.):**
|
||
`local-eval-results/qwen-clean-pairs-20260910.Y2DWsl/{manifest.md,comparison.json}`
|
||
enthält zwölf natürlich abgeschlossene Prozesse mit identischen Antworten und
|
||
vollständigen Settings-/Rohdatenbelegen. Reihenfolge pro Modus P1,R1,R2,P2,P3,R3;
|
||
Power100, Low, gleiche Warmup-/Bootstrap-/Sustained-Verträge, kein Build parallel.
|
||
Die Referenz kann mit `--token-events progress` die Token-JSON-Ausgabe auf echten
|
||
Fortschritt einmal pro Sekunde begrenzen; Tokens/Text bleiben vollständig in den
|
||
End-Receipts. Kleiner modellfreier Test prüft die Rate und verhindert Fortschritt
|
||
ohne neue Tokens. Beide Canary-Summaries bestätigen jeweils null Proben.
|
||
|
||
Der frühere günstige Einzelvergleich ist keine ausreichende Freigabe: Im zweiten
|
||
Paar liegt Rust AR bei Summary/Story/Python 2,34/4,63/10,71% hinter MTPLX, MTP
|
||
6,48/4,26/3,24%. Im ersten und dritten Paar ist Rust schneller; beide Programme
|
||
driften im Verlauf stark. Kein Aussortieren langsamer Läufe oder Median-Pass.
|
||
MTP-Story behält 515 Cycles / 1539 Drafts / 624 Accepts, doch GPU-Busy steigt
|
||
17,193→21,100s und CB-Zahl 142256→147830; Checkpoint-Write bleibt 358→366ms.
|
||
Das verengt die Suche, beweist aber weder thermisches Drosseln noch einen
|
||
Rust-Schedulerfehler. Die GPU-Clock-/Temperaturzeitreihe fehlt.
|
||
|
||
Passive Diagnose: macOS meldete keine Thermalwarnung und normalen Speicherdruck.
|
||
Powermetrics ist ohne Administratorpasswort nicht verfügbar. Das installierte
|
||
mactop lieferte zwei Idle-Samples, beendete sich aber mit Exit139; dieser
|
||
Hilfsprozess ist kein verlässlicher Zusatzmonitor und wurde nicht in die
|
||
Benchmarkserie eingebaut. Die Rust-Speicher-/Fortschrittswächter blieben aktiv.
|
||
Nächster Messblock: zuverlässige optionale passive Geräte-Telemetrie und
|
||
Submission-/GPU-Zeitkorrelation; Prefill-Zeitgrenzen getrennt angleichen.
|
||
Keine Behauptung, das gesamte Ziel sei nur durch Messrauschen verfehlt:
|
||
Ursache bleibt zu belegen, GLM-2-Row-Verify und DS/GLM-Abnahme bleiben offen.
|
||
|
||
**Prompt-Eval-Messgrenzen im gemeinsamen Produktpfad veröffentlicht (10.09.):**
|
||
`local-eval-results/qwen-prompt-timing-20260910.gPvUlU/{manifest.md,comparison.json}`
|
||
belegt vier vollständige serielle Chats (Produkt/MTPLX, AR/MTP). Die bereits
|
||
berechneten Target-/History-/Restore-Zeiten werden vor Decode über dieselben
|
||
MetricsSnapshots veröffentlicht, die UI und Harness beobachten. Das bisherige
|
||
UI-Prefillfenster bleibt unverändert; nicht verfügbare Messung bleibt `null`,
|
||
gemessener Exact-Hit darf null Sekunden haben. Keine neue GPU-Arbeit oder
|
||
Änderung der Ausführungsstrategie. Regressionstest prüft Reset und dass spätere
|
||
Checkpoint-/Decode-Arbeit die Promptzeiten nicht verändert.
|
||
|
||
Alle Antworten/Tokenzahlen stimmen mit Original und vorheriger Clean-Serie
|
||
überein. Die neue Sicht grenzt einen verbleibenden MTP-Summary-Rückstand ein:
|
||
Eval Rust 2,999957s / MTPLX 2,887888s, also -3,736% Durchsatz; History
|
||
52,902 / 52,791ms, Target 2,947055 / 2,835097s. In diesem Paar liegt der Rest
|
||
im Target-Intervall, nicht im History-Aufbau oder Checkpoint. Ursache innerhalb
|
||
Target (GPU-Takt/Dispatch/Streaming/Kernel) weiter offen. Andere Turns in diesem
|
||
Einzelpaar schneller, aber keine Aufhebung der vorherigen Drift und kein 2%-Pass.
|
||
Originale Prompt-State-Gesamtzeit und UI-Phase bleiben wegen zusätzlicher Arbeit
|
||
ausdrücklich getrennt. Alle Wächter beendet ohne Fehler; Canary aus, kein
|
||
GUI-Eventloop-Nachweis. Fokussierter Regressionstest, Treibertests, Release-Clippy,
|
||
Build, Format- und Diffcheck bestanden. P14–P16 und Bundle weiter offen.
|
||
|
||
**Restumfang (historisch; nachfolgende Produktnachweise oben beachten):** Nicht-streamender Hidden-Sequence-Prefill und Session-Restore,
|
||
optionale Prefill-Cleanup-/Repaging- und
|
||
recurrent Boundary-Snapshot-Pfade mit dem AR-Decode verbinden,
|
||
Default-GPU-RNG in den Owner integrieren, verbleibende MTP-Options-/Requestpfade und
|
||
die Guard-/Drain-Übergänge einschließlich Owner-Progress sowie die
|
||
produktive UI/Harness-Integration abschließen. Die sechs vollständigen
|
||
Geschwindigkeitsvergleiche sind
|
||
noch abzuschließen. Diese
|
||
Modulnachweise sind kein Nachweis der vollständigen spekulativen
|
||
Generierung oder der Performance-Parität aller drei Modelle.
|
||
|
||
**Realer MTP-Head mit Draft/Verify/Commit, 2026-09-10:**
|
||
Der persistente `Execution`-Pfad besitzt zusätzlich den MTP-QSA-Cache und
|
||
verwendet die bestehenden `TextModel::mtp_forward`-/`mtp_update_cache`-Graphen
|
||
über `draft` und `append_mtp_history`. Trunk-Aufrufe geben den bereits
|
||
modellseitig gehaltenen Widened-Stream weiter; Float32-Diagnose nutzt denselben
|
||
Auswerter für Logits und Hidden States. Keine neuen Kernel oder Engine-Duplikate.
|
||
|
||
Der Vollmodell-Oracle `tools/mtplx-execution-reference.py --mtp` lädt den
|
||
installierten Head über das originale `Model.attach_mtp`. Er prüft eine
|
||
zusammenhängende echte Modelloperationsfolge, **nicht** den vollständigen
|
||
`generate_mtpk`-Sampler/Generator:
|
||
|
||
- Kalter Ping: Promptkörper (40 Tokens) und letztes Token getrennt, entsprechend
|
||
`generation._prefill_with_hidden_sequence`; 40 verschobene Hidden/Token-Paare
|
||
für den Draft-Cache. Kein ungeteiltes 41-Token-MTP-Prefill.
|
||
- Drei rekursive Draft-Aufrufe mit dem tatsächlich geladenen Head, anschließend
|
||
Vier-Token-Verify mit originalem Capture-Scope und GDN-/PLE-Snapshots.
|
||
- Tatsächliche Greedy-Ablehnung nach dem ersten akzeptierten Draft: zwei von
|
||
vier Verify-Eingaben bleiben. Originaler `commit_verified_window`, MTP-Trim
|
||
von Offset 43 auf **41**, Erhalt der ersten autoritativen Draft-Zeile,
|
||
Ergänzung nur der folgenden Target-Historie bis Offset 42. Dies entspricht
|
||
dem Retain-/Reappend-Pfad in `generation.generate_mtpk` um Zeile 12110.
|
||
- Nächster Target-Aufruf und nächster Draft bei Offset 43 prüfen die Wirkung
|
||
des Commits auf die Fortsetzung, nicht nur die Rückgabewerte des Trim-Aufrufs.
|
||
|
||
Referenz und Rust stimmen für alle 40 Prefill-Logit-Reihen sowie **16 vollständige
|
||
Logit-/Hidden-State-Fingerprints**, Shapes, Greedy-Entscheidungen und Cache-Offsets
|
||
bitgenau überein. Zwei separat geprüfte Konfigurationen: direkte Modell-Defaults
|
||
und originale MTP-Server-Familiendefaults (13 protokollierte Werte, einschließlich
|
||
`MTPLX_SKIP_VERIFY_SNAPSHOT=0`). Das Rust-Testprogramm prüft diese Umgebungswerte
|
||
vor dem Laden, ebenso Vollständigkeit und Reihenfolge der Referenzoperationen.
|
||
|
||
Rohdaten im bestehenden `execution-20260910.Ngpzu7/`:
|
||
`reference-mtp-retained.*` / `canonical-mtp.*` (Familiendefaults),
|
||
`reference-mtp-plain.*` / `canonical-mtp-plain.*` (direkte Defaults).
|
||
Das frühere `reference-mtp.*` ist durch den Retain-Abgleich ersetzt: es baute
|
||
die erste bereits autoritative Draft-Zeile unnötig neu auf und ist **keine**
|
||
Abnahmegrundlage. Sein Disk-Write-Rohzähler enthält zudem einen offensichtlich
|
||
ungültigen OS-Wert nahe u64::MAX; daraus werden keine IO-Leistungswerte abgeleitet.
|
||
|
||
Alle vier maßgeblichen Prozesse einzeln unter unverändertem
|
||
`test-supervisor 81920 30 45` und durchgehendem 100-ms-GPU-Canary mit 2-s-Abbruch.
|
||
Keine Canary-Fehler, alle Prozesse regulär beendet. Lifetime-Peak MTPLX/Rust:
|
||
76.770.450.672 / 76.379.298.192 Bytes (Familie),
|
||
74.458.239.088 / 74.179.498.048 Bytes (direkt).
|
||
Canary-Maxima MTPLX/Rust **4,170 / 15,104 ms** (Familie) und
|
||
**3,911 / 92,204 ms** (direkt). Beide Rust-Ausreißer liegen im Laden, nahezu
|
||
vollständig bis zur Scheduling-Rückmeldung. Der Host-gemessene Wait-Wert
|
||
trennt hier GPU-Scheduling und verspätete Probe-Thread-Rückkehr nicht; die
|
||
Latenzdifferenz bleibt offen, wird nicht durch das 2-s-Risikoflag wegdefiniert.
|
||
|
||
Release-Testbuild, gezieltes warnings-denied Clippy und Format-/Diffprüfung
|
||
bestanden. Keine Downloads, kein Bundle, Commit oder Push.
|
||
**Weiter offen:** vollständiger Sampler/Generator einschließlich RNG, adaptiver
|
||
Draft-Tiefe, natürlichem MTP-EOS und laufendem Chat; produktiver Executor;
|
||
Serverprofil-/Lazy-Eval-/Submission-Vertrag. Die bisherige Bank erzeugt MTP-
|
||
Ladedeskriptoren noch vor der Trunk-Materialisierung (Head-Daten bleiben lazy),
|
||
während MTPLX den Head erst danach anhängt; auch diese Reihenfolge ist vor
|
||
Produktabnahme anzugleichen. Der neue Pfad bleibt `cfg(test)`. Die 2%-Matrix
|
||
und UI-/Headless-Responsiveness-Abnahme sind damit ausdrücklich nicht erreicht.
|
||
|
||
Modellweiter Capture-Commit prüft zunächst alle Einträge. Erst danach erfolgen
|
||
QSA-Trim, reine GDN-Rekurrenz über das akzeptierte Präfix beziehungsweise
|
||
PLE-Snapshot-Restore, erneutes Staging und Layer-Forward des Präfixes.
|
||
Ablehnungen bleiben ohne Cache-Mutation; Capture-Clear entfernt nur Capture-
|
||
Referenzen. Keine zusätzlichen Eval-/Wait-Grenzen im Commit eingeführt.
|
||
|
||
Prüfbelege: vorhandene Decoder-Fixtures um den echten äußeren Modellaufruf
|
||
erweitert, beide Attention-Typen mit/ohne PLE, cache-only Prefill, Head-Slicing,
|
||
Capture an/aus und Trace-Wiederverwendung. Bekannte Embedding-/Widened-/Logits-
|
||
Werte bitgenau, fehlender Snapshot unverändert abgelehnt, Zwei-Token-Commit
|
||
erfolgreich; PLE-History ist danach `[3,4]` statt Verify-Tail `[5,6]`.
|
||
Fortsetzung mit übergebenen Embeddings und separatem Head ebenfalls bestanden.
|
||
Zusätzlicher CPU-Test prüft Compile-Kill-Switch und Run-Grenzen.
|
||
Rohdaten: `local-eval-results/model-graph-20260909.JbRO3E/commit.*.log`;
|
||
GPU unter unverändertem `test-supervisor 2048 15 15`, kein Modell geladen.
|
||
Release-Testbuild, warnings-denied Clippy, Quell-Identität und Format-/Diffprüfung
|
||
bestanden. Die synthetischen Ein-Layer-Smokes sind keine vollständigen
|
||
Golden-Master-Modellfixtures oder Durchsatzmessungen. P16 und die Sechs-Zellen-
|
||
Performance-Abnahme innerhalb 2 % bleiben offen.
|
||
|
||
**MTP-Head-Verbindung 2026-09-09:** `qwen_mtplx/mtp.rs` und die Methoden
|
||
`mtp_forward`, `mtp_update_cache`, `make_mtp_cache` am äußeren Modell bilden
|
||
`qwen4_exp.py:4134–4250` ab. RMSNorm über die volle Breite 10240 vor dem
|
||
Reshape in vier 2560-Streams, gemeinsame Hidden-Projektion, normierte und
|
||
projizierte Token-Embeddings als Broadcast-Add, eigener nicht-PLE-QSA-Decoder
|
||
und eigener Mixer. Der LM-Head und das Embedding bleiben mit dem Trunk geteilt.
|
||
Rekursive Drafts verwenden den Pre-Mixer-Output des vorherigen Drafts;
|
||
Cache-only Updates erzeugen weder Mixer noch LM-Head. Übergebene Embeddings
|
||
ersetzen den Lookup, Positionen kommen aus dem eigenen QSA-Cache.
|
||
|
||
Der verbundene synthetische Test prüft drei rekursive Drafts und danach
|
||
mehrzeilige Cache-Updates (2 Lookup-Zeilen und 3 explizite Embedding-Zeilen),
|
||
bekannte BF16-Ergebnisse mit unterschiedlichen Hidden-Streams, Offset-Fortschritt,
|
||
optionale Hidden-Ausgabe und unveränderte Trunk-Caches/`last_widened`.
|
||
Der erste Lauf (`head.*.log`) scheiterte beim mehrzeiligen Update am zuvor
|
||
fehlenden batched QuantizedMatmul-Zweig. Dieser wird nun direkt nach
|
||
`quantized.cpp` ausgeführt: originale Batch-Strides, `_batch_1`-Kernel aus der
|
||
unveränderten gepinnten Metallib und kein Split-K bei B > 1. Kein Zerlegen in
|
||
Einzelzeilen oder zusätzliches Contiguous-Materialisieren als Ersatz.
|
||
|
||
Nach Ergänzung bestehen beide Decoder-Tests (`fixed.*.log`, 0,33 s,
|
||
gesampelter Peak-Footprint 314.868.528 Bytes). Der bestehende affine
|
||
Referenztest besteht unverändert 78 Fälle in je drei physischen Varianten,
|
||
also 234 exakte Vergleiche (`affine.*.log`, 1,00 s).
|
||
Der zusätzliche Batch-Test besteht 24 Identitätsprojektionen mit K=64/128/2560,
|
||
M=1/3/33/64 und Broadcast- beziehungsweise permutierten Batch-Strides. Er
|
||
prüft bitgenaue Ausgabe und die tatsächlich ausgeführten Kernel samt Geometrie.
|
||
21 Fälle dispatchen ohne Inputkopie direkt batched; bei drei Broadcast-Fällen
|
||
mit M=1 verlangt bereits die Referenz wegen des Null-Strides der Singleton-
|
||
Matrixachse eine Kopie und anschließend non-batched Dispatch. Die anfangs
|
||
pauschale Ein-Dispatch-Erwartung wurde entsprechend korrigiert, nicht der
|
||
Referenzpfad verändert (`batched-fixed.*.log`, 0,25 s, gesampelter Peak
|
||
163.578.600 Bytes).
|
||
Release-Testbuild, warnings-denied Clippy für App/Tests, beide CPU-Policy-Tests,
|
||
Quell-Identität sowie Format-/Diffprüfung bestanden.
|
||
Rohdaten: `local-eval-results/mtp-head-20260909.gXSh00/`.
|
||
Alle GPU-Läufe einzeln unter `test-supervisor 2048 15 15`, keine Modelle
|
||
geladen oder heruntergeladen. Dies ist ein Funktionsnachweis mit künstlichen
|
||
Gewichten, kein Nachweis der realen MTP-Akzeptanz, Compile-Fusion oder
|
||
Performance-Parität; der gesamte kanonische Pfad bleibt `cfg(test)`.
|
||
|
||
**Arraygraph-Nachweis 2026-09-09:** `qwen_mtplx/moe.rs` bildet die tatsächliche
|
||
Aufruffolge von MTPLX `SparseMoeBlock`, `_FusedGateUpSwitchGLU` und dem
|
||
gepinnten `SwitchGLU`/`Qwen3NextMLP` ab:
|
||
|
||
- Präziser Softmax über alle Experten, ArgPartition, strided Top-k-Slice,
|
||
GatherAxis und optionale Score-Normalisierung bleiben einzelne Array-Knoten.
|
||
- Gather-Sort ab 64 Routen, Argsort/inverse Argsort, U32-Floor-Divide,
|
||
Gather/Unsort und die ursprünglichen Expand-/Squeeze-/Reshape-Views.
|
||
Expert- und Shared-Gewichte bleiben graph-eigene Arrays.
|
||
- Gemeinsame Gate/Up-Projektion verwendet Split, den vorhandenen kompilierten
|
||
SiLU und gewöhnliche Multiplikation. Getrennte Projektionen verwenden den
|
||
unveränderten kompilierten SwiGLU-Kernel als **einen** Knoten. Experten:
|
||
Up vor Gate; Shared Expert: Gate vor Up, wie in den beiden Referenzklassen.
|
||
- Fusioniertes AR (S=1) und Verify (S=2–4) haben zwei CustomKernel-Knoten mit
|
||
Original-Inputreihenfolge, Output-Layouts, Gruppen32/64 und Dispatch-Geometrie.
|
||
Sie werden nur bei den ursprünglichen Flag-/Batch-/Quantisierungsbedingungen
|
||
selektiert. Der Shared-Gate-Aufruf liegt im fusionierten Zweig vor dem Shared
|
||
MLP, im Standardzweig danach. Keine zusätzliche Eval-/Wait-Grenze im Modellblock.
|
||
|
||
`mtplx_graph_sparse_moe_matches_reference` vergleicht die unveränderten 220
|
||
vollständigen MTPLX-MoE-Belege zweimal: zunächst mit lazy Parameter-Views,
|
||
danach mit zuvor ausgewerteten Parametern. Eingabe und Modellbesitzer werden
|
||
vor der Auswertung freigegeben; der Graph muss ihre Lebensdauer selbst halten.
|
||
**440/440 Ausgaben exakt**. Rohdaten:
|
||
`local-eval-results/moe-graph-20260909.xLwfFW/graph.*.log`.
|
||
Diagnostischer Gesamtlauf 17,988 s, OS-Lifetime-Peak 5.194.256.488 Bytes
|
||
(4,84 GiB), unter dem unveränderten 8-GiB-/15-s-Wächter. Dies ist kein
|
||
Modell-Durchsatzbenchmark und kein Vergleich gegen die frühere Buffer-Testzeit.
|
||
Der zusätzliche vorhandene GatherQMM-Test einschließlich Streamwechsel,
|
||
physischer Views und lazy/vorbereiteter Ausführung ist ebenfalls bestanden
|
||
(`gather.*.log`).
|
||
|
||
Der anschließende vollständige Lauf mit Dispatch-Erfassung
|
||
(`dispatch.*.log`) besteht ebenfalls alle 440 Vergleiche. Zusätzlich wird an
|
||
der tatsächlichen nativen Dispatch-Grenze geprüft: exakt die beiden passenden
|
||
fusionierten Kernel in H-/Down-Reihenfolge, Gruppen-/M-Spezialisierungen,
|
||
Grid und Threadgroup sowie `dispatchThreads`; in allen nicht geeigneten
|
||
Fällen keine dieser beiden Fusionen. Quell-Identitätsprüfung, Release-Testbuild,
|
||
warnings-denied Clippy und Format-/Diffprüfung sind bestanden.
|
||
|
||
Der gemeinsame synthetische Pack-Generator berechnet nun `n*k/32*bits`,
|
||
damit die gültigen 512-Experten-Packs nicht bereits im Zwischenprodukt
|
||
`n*k*bits` einen u32-Überlauf erzeugen; die Pack-Werte bleiben identisch.
|
||
|
||
- MTPLX `_FusedGateUpSwitchGLU.__call__` sortiert ab 64 Routen und benutzt den
|
||
gemeinsamen gate/up-Gather auch im sortierten Fall. Der vorangestellte Kommentar
|
||
zur Large-M-Fallback-Absicht ist nicht der ausgeführte Code. Shared Expert ist
|
||
ebenfalls gemeinsam gepackt. Der noch nicht migrierte Rust-Produktpfad führt
|
||
beide Prefill-Projektionen getrennt aus; der neue Arraygraph ist oben belegt.
|
||
- Aktivierte gepackte Gewichte, Top-10-Routenauswahl/Ties, Sortiergrenze S=5/6/7,
|
||
inverse Permutation, Gewichtung, Tile-Reste und stark ungleich verteilte Experten
|
||
vergleichen. Auch der standardmäßig deaktivierte `FUSED_MOE_VERIFY` gehört
|
||
gemäß Auftragspräzisierung zum Port, ohne ihn abweichend zur Referenz zu aktivieren.
|
||
- Abnahme: Referenz-Outputs und Routenzuordnung für identische Matrizen; bestehender
|
||
`qwen_sorted_routed_prefill_matches_grouped_output` bleibt unverändert gültig.
|
||
Performance-Abnahme erst am vollständig integrierten Referenzport, keine
|
||
erneute Auswahl einzelner Bestandteile anhand von Teilbenchmarks.
|
||
|
||
BK-Teilversuch 2026-09-05: Die online geprüfte, tatsächlich benötigte
|
||
[MLX-0.32.2-Implementierung](https://raw.githubusercontent.com/ml-explore/mlx/v0.32.2/mlx/backend/metal/quantized.cpp)
|
||
nutzt im NAX-Pfad BK=64 und für sortierte Experten BM=32 bei weniger als 64
|
||
Durchschnittszeilen je Experte. Rust Sorted-QMM nutzt BM=64/BK=32 mit M5-MPP.
|
||
Der lokale allgemeine MLX-Checkout steht hingegen auf **0.32.3** (`b636898`);
|
||
er ist nicht ungeprüft als Code der installierten MLX-0.32.2-Referenz zu behandeln.
|
||
|
||
Nur BK von 32 auf 64 geändert und geprüft: vorhandener
|
||
`qwen_sorted_routed_prefill_matches_grouped_output` mit 137 Zeilen/ungleichen
|
||
Expertenbelegungen exakt bestanden. Vollständiger AR-Chat ebenfalls identische
|
||
Antworten/Tokenzahlen, alle Stop/Exit0. Summary-Prefill 5,578 s, großer GPU-Buffer
|
||
3,812 s, gegenüber normal zuvor 5,291 s / 3,861 s und erneut 5,289 s / 3,848 s.
|
||
PLE-pread im Summary beträgt im BK64-Lauf 552 ms statt 227 ms im ersten Kontrolllauf;
|
||
die höhere Gesamt-Prefillzeit ist deshalb kein isolierter BK-Nachteil. Umgekehrt
|
||
beweist die kleine GPU-Differenz ohne Wiederholungen keinen belastbaren Vorteil.
|
||
**BK64 zurückgenommen**, keine unbewiesene Optimierung verbleibt im Produkt.
|
||
Rohbelege: `sorted-bk64-check.log`, `qwen-bk64-ar.*` im gleichen Messverzeichnis.
|
||
BM-/Experten-Worklist und BF16- statt FP32-Aktivierungsspeicher bleiben getrennte
|
||
P07/P09-Kandidaten; die BK-Geometrie allein erklärt den Rückstand nicht.
|
||
|
||
BF16-Speicher-Teiländerung danach umgesetzt (2026-09-05, siehe P09): Der sortierte
|
||
Gather und dessen SwiGLU-Zwischenergebnis speichern jetzt BF16 direkt für den
|
||
Sorted-QMM-Eingang. BM64/BK32 und die getrennten gate/up-Dispatches bleiben bestehen.
|
||
Das ist kein Abschluss der ausstehenden Routing-/Fusions-/Tile-Vergleiche.
|
||
|
||
**BM32 isoliert geprüft und zurückgenommen (2026-09-05):** Route-Map, Worklist-
|
||
Kapazität und Sorted-Dispatch konsistent auf 32er-M-Blöcke umgestellt; der
|
||
Grouped-Referenzpfad blieb bei 64. Alle acht exakten Formen bis S2048 bestanden.
|
||
Vollständiger AR-Chat mit identischen Antworten: Summary-Prefill 5629 ms und
|
||
großer GPU-Buffer 3977 ms gegenüber BF16/BM64 zuvor 5289–5368 ms / 3604–3662 ms
|
||
bei ähnlicher PLE-Lesezeit. Kein globaler BM32-Produktpfad bleibt zurück.
|
||
Der kleine Canary-Maximalwert von 1,26 ms in diesem langsameren Lauf ist erneut
|
||
kein Ersatz für Performance-Messung. Kein MTP-Leistungsnachweis aus diesem Versuch.
|
||
|
||
Der genauer geprüfte [MLX-0.32.2-NAX-Kernel](https://raw.githubusercontent.com/ml-explore/mlx/v0.32.2/mlx/backend/metal/kernels/quantized_nax.h)
|
||
verteilt das Grid über zusammenhängende sortierte Routen und durchläuft innerhalb
|
||
eines Tiles dessen Expertengrenzen; nur beteiligte SIMD-Gruppen rechnen. Rust
|
||
erzeugt dagegen getrennte, je Experte aufgerundete Workitems. Bloß BM32 zu kopieren
|
||
stellt diese Ausführung nicht her. Worklist-Verteilung und aktive SIMD-Gruppen
|
||
bleiben innerhalb P07 zu untersuchen; der negative Versuch widerlegt keine
|
||
formabhängige kleinere Tile-Strategie.
|
||
|
||
**Sortierte Gate/Up-Fusion geprüft und zurückgenommen (2026-09-06):** Gemeinsames
|
||
Dispatch-Grid bei unveränderten Gewichtsansichten/Tile-Mathematik besteht alle
|
||
acht exakten Vergleichsformen. 16 abwechselnde Komponentenpaare: GPU-Zeit bei
|
||
S2048 9,405→9,376 ms, bei S137 0,794→0,850 ms. Vollständiger AR-Chat textidentisch,
|
||
Prefill4880 statt4907 ms bei gleicher PLE-Lesezeit784 ms; kein belastbarer
|
||
allgemeiner Gewinn und keine Erklärung des großen Rückstands. Kein experimenteller
|
||
Fusionspfad verbleibt. Belege: `local-eval-results/20260906-sorted-gate-up/manifest.md`.
|
||
|
||
### P08 — Attention/QSA-Kernel und KV-Datentransfers
|
||
|
||
Kanonischer Graphstand 2026-09-07: Batch-Matmul/Softmax, Dense-SDPA-Fallback,
|
||
Rows-Gather und gekachelter portabler Prefill-Gather sind verbunden; siehe
|
||
„Verbundene Attention-Matrixpfade und Softmax“ und „Gekachelter portabler
|
||
Prefill-Gather“, „Fused-Vector-SDPA und typisierte Metal-Konstanten“ sowie
|
||
„Originale RoPE-Graphen und KV-Cache-Objektsemantik“ sowie „Direkte Sparse-
|
||
Attention-Consumer im Arraygraph“. Originaler Flash-Skip-Decode und TensorOps-
|
||
Prefill sind als eigene CustomKernel-Primitive geprüft. Auch die vollständige
|
||
originale Blockmaskenrekonstruktion samt ScatterAxis ist verbunden und geprüft
|
||
(siehe „Vollständige QSA-Blockmaskenrekonstruktion“). RoPE und gewöhnlicher
|
||
KVCache sind jetzt im kanonischen Arraygraph geprüft, einschließlich
|
||
Python-Objektalias/Graphdescriptor-Unterscheidung. Auch der positionale QSACache
|
||
einschließlich FP32-Spiegel und Replay-Reservierungen verwendet diese Semantik
|
||
(siehe „Positionaler QSACache im kanonischen Arraygraph“). Die originalen
|
||
Query-/Pooling-CustomKernel sind inzwischen vollständig parametrisiert als
|
||
Array-Primitiven geprüft (siehe „Parametrisierte QSA-Query-/Pooling-Primitiven“).
|
||
Die gemeinsamen Float-Summen samt QSA-F32-Mittelwert sind ebenfalls portiert;
|
||
GDN/PLE/HC nutzen jetzt dieselbe Reduktionsauswahl (siehe „Gemeinsame Float-
|
||
Summen und QSA-Mittelwert“).
|
||
Auch F32-/F16-Matmul inklusive TF32 on/off und der verbundene Eager-QSA-
|
||
Score-Ausdruck sind nun im kanonischen Graph geprüft (siehe „Kanonischer
|
||
Float-Matmul und verbundener QSA-Score-Pfad“).
|
||
Sort/Argsort/Partition/Argpartition sind jetzt ebenfalls als kanonische
|
||
Operationen geprüft; der bisherige Buffer-Argsort teilt deren Backend
|
||
(siehe „Gemeinsames kanonisches Sort/Argpartition“).
|
||
Die Eager-Auswahl verbindet jetzt Scores, Maskierung, Argpartition, QSACache-
|
||
Spiegel und alle fünf Rückgabeformen einschließlich Kachel-Eval und Lane-
|
||
Zählern (siehe „Verbundene kanonische Eager-QSA-Auswahl“).
|
||
Die Verbindung zur kanonischen Indexer-Ausführung ist nun geprüft (siehe
|
||
„Durchgehender kanonischer Indexer und Cache-Commit“). Der vollständige
|
||
BF16/D256-Attention-Aufruf ist inzwischen ebenfalls verbunden (siehe
|
||
„Verbundener Qwen-Attention-Modulaufruf“).
|
||
Der gemeinsame Projektions-/Vorbereitungs-/Update-Vorlauf ist inzwischen
|
||
mit fortlaufendem Cache und Eager-Auswahl geprüft (siehe „Gemeinsamer
|
||
QSA-Indexer-Vorlauf und fortlaufender Cache“).
|
||
Der kanonische Fused-Selektor einschließlich aller drei Ausgabeformen,
|
||
Graph-Scratch-Siblings und ursprünglicher Query-Chunking-Regel ist ebenfalls
|
||
geprüft; alter und neuer Aufrufer teilen dessen Backend (siehe „Fused-QSA-
|
||
Selektor im kanonischen Arraygraph“). Der vektorisierte Prefill-Selektor
|
||
ist nun ebenfalls als zusammenhängender Zweistufen-Graph geprüft, mit
|
||
TensorOps BF16/F16 und dem allgemeinen F32-Ausdruck (siehe „Zweistufiger
|
||
Prefill-Selektor im kanonischen Arraygraph“). Compiled-Indexer und Routing
|
||
sind nun ebenfalls verbunden.
|
||
Die dafür benötigten dynamischen Slice-/Update-Primitiven sind jetzt mit
|
||
gemeinsamem Copy-/Offset-Encoder geprüft (siehe „Dynamische Cache-Fenster
|
||
im kanonischen Arraygraph“); die Graphbank ist inzwischen angeschlossen.
|
||
Der reine Compiled-Body samt tatsächlichem Arraygraph-Replay ist inzwischen
|
||
für die erfassten Q/K-/Hidden-Fälle geprüft (siehe „Reiner Compiled-Indexer
|
||
und kanonisches Graph-Replay“). Der Host-Core mit vollständigen Compile-
|
||
Schlüsseln, Validierung und Statistik ist nun ebenfalls geprüft (siehe
|
||
„Kanonischer Compiled-Host-Core und Engagement“). Parameter-Lebenszyklus,
|
||
Cache-Commit und Routing sind nun mit 200 vorhandenen vollständigen Aufrufen,
|
||
720 Zulässigkeitsfällen und 26 zusätzlichen Lifecycle-Receipts geprüft.
|
||
Weitere Compiled-Geometrien/Dtypes und die allgemeine Nicht-MPP-Score-Fusion
|
||
bleiben offen.
|
||
Andere SDPA-Dtypes/Geometrien einschließlich Full-SDPA sowie die vollständige
|
||
Modell-/Produktintegration bleiben offen. Die folgenden Befunde zum alten Produktpfad sind dadurch
|
||
noch nicht behoben.
|
||
|
||
Priorität P1; nach P02, P04; Quellcodedifferenzen und Nachweislücken.
|
||
|
||
- Dense Decode, Verify unter/über 16k, Prefill unter/über 32k, Sparse-Selection,
|
||
Pooling, Tail und Positionierung mit MTPLX `QSACache`, `QSAIndexer` und Attention
|
||
vergleichen. Rust poolt in einer CPU-Dispatchschleife und staged Dense-KV erneut.
|
||
- BF16-KV, F16-Staging für FlashAttention und F32-Zwischenpuffer getrennt prüfen;
|
||
kopierte Bytes, Layout/Strides und tatsächliche M5-Kernel protokollieren.
|
||
- Abnahme: Masken/Indices/States und numerischer Referenzvergleich an 2048,8192,
|
||
16384,32768 und ihren Nachbarpositionen sowie partiellen Pool-Blöcken. Der entfernte
|
||
8192-Flash-Guard benötigt einen direkten numerischen Test oberhalb der alten Grenze.
|
||
Ein Allokationstest für langen Kontext ersetzt keinen Attention-Test.
|
||
|
||
### P09 — Affine Matmuls, HC und Speicherformate
|
||
|
||
Kanonischer Graphstand 2026-09-07: Originale affine Quantisierung sowie der
|
||
installierte GatedResidual-Read einschließlich eager Norm/Matmul/Mean,
|
||
Fused/V3-Auswahl und Modul-Pack-Cache sind verbunden und mit128 tatsächlichen
|
||
MTPLX-Fällen exakt geprüft; siehe „Verbundener GatedResidual einschließlich
|
||
eager Prefill“. Decoder-/Modell- und Produktintegration sowie Gesamtperformance
|
||
sind weiterhin offen. Historische Befunde unten bleiben vom aktuellen
|
||
kanonischen Port zu unterscheiden.
|
||
|
||
Priorität P1; nach P01, P02, P04; Teiltests bestanden, Gesamtnachweis offen.
|
||
|
||
**K-Tile/Padding/BF16-Versuch verworfen (2026-09-06):** Ein kombinierter Versuch
|
||
mit gruppengroßem K-Schritt, gepaddetem Gewichtstile und BF16-Geräteingang senkte
|
||
die isolierte QKV2048-Zeit auf2,654 ms, beschleunigte die vollständigen Chats aber
|
||
nicht erkennbar: AR/MTP-Summary-Prefill4233/4387 ms gegenüber4214/4351 ms der
|
||
vorherigen Kontrolle; GPU-Buffer2140/2151 gegenüber2160/2159 ms. Kleine
|
||
Projektionsausgänge bezahlen zusätzliche Konvertierungskosten. Canary-Maxima
|
||
49/83 ms, kein allgemeiner Responsivitätsgewinn. Alle drei Antworten pro Modus
|
||
Stop/Exit0 und exakt gleiche Texte, Tokens und MTP-Akzeptanz wie die gültige
|
||
Rust-Kontrolle; kein erneuter MTPLX-Paritätsnachweis aus diesen Zahlen.
|
||
|
||
Der erste Versuch war wegen eines übersehenen direkten GDN-QMM-Aufrufers
|
||
(FP32 an BF16-Kernel) ungültig und wurde abgebrochen. Neuer Integrationstest
|
||
reproduziert den Fehler bei5 Zeilen und prüft nach Korrektur4/5/32/65/2048 Zeilen
|
||
inklusive Unpack exakt. Anschließend wurde die gesamte unvorteilhafte Variante
|
||
zurückgenommen, nicht nur der falsche Aufrufer repariert. Test und gewöhnliche
|
||
GPU-Timestamps im Operator-Test bleiben erhalten; Produkt-Binary und Metal
|
||
sind SHA256-identisch zur vorherigen gültigen Wortloader-Kontrolle. Die Tests
|
||
bestehen auch nach Rücknahme. Belege und Rückmessungen:
|
||
`local-eval-results/20260906-qmm-k-tile/manifest.md`.
|
||
|
||
**Wortweise QMM-Entpackung (2026-09-06):** Der gemeinsame Affine-QMM-Loader liest
|
||
gepackte Wörter/Skalen/Bias jetzt einmal je4/8 Werte, wie der vorhandene sortierte
|
||
Loader und MTPLXs `QuantizedBlockLoader`, statt pro Einzelwert. FMA/BF16-Rundung,
|
||
Tile-Geometrie, Split-K und Aktivierungsformat unverändert. Alle bestehenden
|
||
Projektionsgoldens einschließlich partieller Tiles bestehen. Die erweiterten
|
||
Operator-Timings grenzen QKV2048 ein: MTPLX2,060 ms, Rust vorher7,272 ms,
|
||
wortweise3,150 ms (Host-Aufruf und Completion, keine reine GPU-Zeit).
|
||
Separat geprüfte BF16-Aktivierungsvarianten brachten keinen generellen Gewinn
|
||
und sind zurückgenommen; FP32 ist damit nicht als alleinige Ursache bewiesen.
|
||
Vollständiger AR-Chat text-/tokenidentisch: erster Prefill4214 statt4907 ms,
|
||
größter GPU-Buffer2160 statt2656 ms, ähnliche PLE-Lesezeit792/784 ms. Canary-Max
|
||
3,962 ms; Einzelvergleich, kein GUI- oder2%-Nachweis. Weitere Form-/Layout-/
|
||
Referenzwiederholungen bleiben offen. Belege:
|
||
`local-eval-results/20260906-sorted-gate-up/manifest.md`.
|
||
|
||
Vollständige MTP-Kontrolle ebenfalls text-/token-/acceptance-identisch mit Stop
|
||
beendet: erster Prefill4351 statt5079 ms; Decode70,622/47,038/66,224 tok/s.
|
||
AR/MTP-Canary-Max3,962/3,006 ms, keine Fehler. Diese Einzelkontrollen ersetzen
|
||
keine saubere zeitnahe Referenzmatrix; DeepSeek/GLM wurden dabei nicht neu gemessen.
|
||
|
||
**Verifier-Zeilenspezialisierung (2026-09-06):** Der gemeinsame Wide-QMV-Metal-
|
||
Helper spezialisiert nun 2/3/4 Zeilen mit konstanten Akkumulator-Indizes und
|
||
unrollten inneren Schleifen wie die installierten MTPLX-Kernel. Zwölf zusätzliche
|
||
echte MTPLX-Projektionshashes (QKV/Router/GDN-Control/Shared-Gate) bestehen vor und
|
||
nach der Änderung; vorhandene Prefill-Goldens bleiben gültig. Vollständiger
|
||
MTP-Chat bei 100%/2048/Low, ohne Profiler, mit Canary: unveränderte Texte, Tokens
|
||
und Akzeptanz, Decode 70,732/47,279/68,033 statt 57,166/37,921/52,799 tok/s.
|
||
Canary-Max31,552 ms, Decode-Max0,874 ms. Erster Prefill5079 statt zuvor4609 ms:
|
||
keine belegte Prefill-Verbesserung. Einzelvergleich, keine gepaarten sauberen
|
||
Referenzwiederholungen und keine 2%-Abnahme. Belege und Grenzbedingungen:
|
||
`local-eval-results/20260905-verifier-stage-counters/manifest.md`.
|
||
AR-Kontrolle ebenfalls vollständig/textidentisch beendet, Decode
|
||
48,919/48,795/48,857 tok/s, keine beobachtete Regression. Deren Canary-Max3,141 ms
|
||
ist ebenfalls viel kleiner als im historischen Lauf, obwohl AR den geänderten
|
||
Wide-QMV-Pfad nicht nutzt. Deshalb die verbesserten Canary-Maxima nicht kausal
|
||
der Kerneländerung zuschreiben; zeitnahe gepaarte Messungen bleiben erforderlich.
|
||
|
||
**Vor weiterer QMM-Optimierung belegte Abweichung (2026-09-05):** Der erweiterte
|
||
Projektions-Komponententest besteht bei QKV 4-bit/g64 mit 32/64/2048 Zeilen und
|
||
Router 8-bit/g64 mit 2048 Zeilen. Router 32 und 64 weichen ab. Die Referenzwerte
|
||
wurden danach durch die quantisierten Projektionsmodule von MTPLXs
|
||
`GatedDeltaNet` und `SparseMoeBlock` bestätigt; alle zwölf generierten Hashes
|
||
entsprechen dem vorherigen direkten Bibliotheks-Diagnosetest. MTPLX bleibt das
|
||
Qwen-Orakel; diese Operatorchecks ersetzen keinen Modell-/Serving-Vergleich.
|
||
Belege: `tools/qwen-qmm-reference.py`, `local-eval-results/20260905-qmm-loader/`
|
||
mit `mtplx-components.jsonl` und `affine-all-shapes-before.log`. Der Test sammelt
|
||
alle Formfehler und schlägt weiterhin fehl; keine Golden-Hashes wurden angepasst.
|
||
**Ursache inzwischen bestätigt (2026-09-05):** Im begrenzten Komponententest
|
||
wurden über LLDB die vom unveränderten, installierten MTPLX angeforderten
|
||
Pipeline-Namen und Dispatch-Geometrien gelesen. Router 31/32 Zeilen verwendet
|
||
`affine_qmm_t_splitk_bfloat16_t_gs_64_b_8_alN_true`, Grid 16×1×20; Router 63/64
|
||
Grid 16×2×10. Danach folgt jeweils `col_reduce_small_1_reduce_sumbfloat16`
|
||
mit 32×8 Threads. Router 2048 und die geprüften QKV-Matrizen verwenden dagegen
|
||
NAX-QMM, ohne K-Split. Das ist nun ein Nachweis der installierten Ausführung,
|
||
nicht eine Annahme anhand eines anderen Bibliotheks-Checkouts.
|
||
|
||
`tools/qwen-qmm-reference.py --check-split-k` reproduziert beide Router-Goldens
|
||
bitgenau mit 20 beziehungsweise 10 expliziten QMM-K-Partitionen und anschließender
|
||
BF16-Reduktion. Ein ungeteilter gebatchter Kontrollfall liefert dagegen genau die
|
||
bisherigen abweichenden Rust-Hashes. Die 32-Zeilen-Kontrolle muss beim kleineren K
|
||
im QMM-Pfad bleiben: 64 gepaddete Eingabezeilen, anschließend Auswahl der ersten
|
||
32. Ohne diese Kontrolle wechselte der erste Diagnoseversuch die Operatorform
|
||
und reproduzierte das Golden nicht. Golden-Hashes unverändert; Assertions für
|
||
beide Split- und Unsplit-Kontrollfälle bestanden. Keine Timing-Abnahme unter LLDB.
|
||
|
||
Diagnosebeleg: `local-eval-results/20260905-router-splitk/manifest.md`.
|
||
|
||
**Split-K-Teilkorrektur umgesetzt und nachgemessen (2026-09-05):** Gemeinsamer
|
||
Affine-QMM-Pfad mit formabhängiger K-Aufteilung, BF16-Zwischen-/Reduktionsrundung
|
||
und wiederverwendbarem 2-MiB-Puffer. Der erste Versuch scheiterte an nativen
|
||
BF16-SIMD-Overloads; nach Abgleich mit der installierten MTPLX-Abhängigkeit ist
|
||
die Float-SIMD-Zwischenoperation mit BF16-Ergebnisrundung korrigiert. Unveränderte
|
||
QKV-/Router-Goldens bestehen jetzt, einschließlich zuvor fehlerhafter Router
|
||
32/64. Zusätzliche tatsächliche MTPLX-Projektionsgoldens für GDN-Steuerung (N=48)
|
||
und Shared-Expert-Gate (N=1) bei 32/64/2048 bestehen ebenfalls, jeweils mit
|
||
Tail-/Sentinel-Prüfung; beide Reduktionspfade einschließlich 40 Partitionen sind
|
||
abgedeckt. CPU-Test für Split-Policy, Alignment und Puffergrenzen bestanden.
|
||
|
||
Vollständige AR-/MTP-Produktchats bei 100%, Chunk2048, Low, identischen eingefrorenen
|
||
Prompts und Canary an enden natürlich. Beide Python-Ausgaben bestehen neun Fälle.
|
||
Erster Prefill4,436/4,609s; Decode AR48,740/48,486/48,332 und
|
||
MTP57,166/37,921/52,799tok/s. Canary max110,710/96,768ms, keine Fehler.
|
||
Das beseitigt die nachgewiesene numerische Teilabweichung, nicht den verbleibenden
|
||
Durchsatz-/Latenzrückstand. Gesampelte Historien ändern sich; kein isolierter
|
||
Kernel-Speedup und keine 2%-Abnahme daraus ableiten. Alle Produktionsformen,
|
||
QMV/QMM-Dispatch-Grenzen, HC und Kernel-Performance bleiben innerhalb P09 offen.
|
||
Belege, Hashes und reproduzierbare Prüfung:
|
||
`local-eval-results/20260905-splitk-implementation/manifest.md`.
|
||
|
||
- Pro Operator Form, Quant-Bits/Group-Size, Packung, Akkumulator, gespeicherten
|
||
Datentyp und BF16-Rundungsstelle erfassen. Rust speichert viele BF16-gerundete
|
||
Aktivierungen als F32; Werteparität beweist nicht Bandbreiten-/Speicherparität.
|
||
- QMV/QMM/Gather/Sorted-QMM, HC-read/mix/write, Norm/Gates, Embedding und LM-Head
|
||
abdecken; aktive MTPLX-Fusionen von nicht aktivierten Experimenten trennen.
|
||
- Abnahme: vorhandenen `qwen_affine_qmv_and_qmm_match_mlx_reference` und Stage-Trace-
|
||
Tests wiederverwenden, keine Golden-Hashes still ändern. Produktionsformen plus
|
||
Tail-/Kapazitätsfälle. Vor Änderungen Kernel-Zeit, Dispatchzahl, Kopierbytes und
|
||
Peak-Transients ermitteln; Dtype-Änderungen nur mit Referenzbeweis.
|
||
|
||
**Sorted-MoE-Eingangsspeicher umgesetzt, Rest offen (2026-09-05):**
|
||
`kernel_qwen_route_gather_rows` und die nur dort verwendete BF16-SwiGLU-Variante
|
||
schreiben gepacktes BF16; `kernel_qwen_affine_sorted_qmm_mpp` liest es als
|
||
`tensor<device bfloat>`. Bisher wurden BF16-gerundete Werte als FP32 gespeichert.
|
||
Die bestehende SwiGLU-Formel/Rundungsfolge bleibt gemeinsam templatisiert; der
|
||
Grouped-/Decode- und Shared-Expert-Pfad bleibt FP32. Outputs und Akkumulatoren
|
||
des Sorted-QMM bleiben FP32. Vorhandene Scratch-Puffer werden wiederverwendet,
|
||
ihre Kapazität wurde nicht verkleinert: kein behaupteter Peak-Allokationsgewinn.
|
||
|
||
Der bestehende exakte Grouped-vs-Sorted-Test wurde auf S=5,6,7,32,64,65,137,2048
|
||
erweitert; alle Fälle bestehen mit MAE0/max0/assert_eq. Danach sechs vollständige
|
||
überwachte Chats: BF16 AR/MTP, Rückkehr zu hash-identischem FP32-Metal AR/MTP,
|
||
erneut BF16 AR/MTP. Alle Stop/Exit0; Antworten, Reasoning, Tokenzahlen und
|
||
Draft-/Accept-/Cycle-Zahlen exakt identisch zu den vorherigen jeweiligen Kontrollen.
|
||
|
||
| Modus / Pfad | Summary Prefill ms | größter GPU-Buffer ms | PLE pread ms | Prefill-Canary max ms | Prozess ms |
|
||
| --- | ---: | ---: | ---: | ---: | ---: |
|
||
| AR FP32 Rückmessung | 5606 | 3863.26 | 607 | 125.06 | 60572 |
|
||
| AR BF16 Lauf 1 | 5289 | 3603.53 | 618 | 1.32 | 59791 |
|
||
| AR BF16 Lauf 2 | 5368 | 3662.29 | 613 | 156.50 | 59900 |
|
||
| MTP FP32 Rückmessung | 5770 | 3821.95 | 611 | 122.33 | 57956 |
|
||
| MTP BF16 Lauf 1 | 5677 | 3741.14 | 853 | 115.85 | 59514 |
|
||
| MTP BF16 Lauf 2 | 5494 | 3606.83 | 610 | 16.93 | 55938 |
|
||
|
||
100%, Chunk2048, Low, gleiche drei Prompts und fortlaufender Chat, Canary an,
|
||
keine Layer-Profilierung. Der größte Prefill-GPU-Buffer ist wiederholt kürzer
|
||
(AR 5,2–6,7%, MTP 2,1–5,6%). Das ist **keine 2%-Referenzabnahme** und kein Beleg,
|
||
dass Decode allgemein schneller wurde. Die hohe PLE-Streuung beeinflusst auch
|
||
die Gesamtlaufzeit. Insbesondere widerlegt der zweite AR-Lauf eine aus dem ersten
|
||
niedrigen Canary-Wert abgeleitete allgemeine Responsivitätsverbesserung.
|
||
Kein GUI-Eventloop-Nachweis; die Spitzen bleiben P04/P05/P07/P08 zugeordnet.
|
||
Details/Hashes und normierte End-to-End-Decodewerte:
|
||
`local-eval-results/20260905-gdn-delta/bf16-comparison.json`, `bf16-storage.md`.
|
||
|
||
Zusätzliche M5-Primärquelle für die verbleibenden P07/P09-Arbeiten:
|
||
[Apples MPP Programming Guide, §§2.3.1–2.3.5](https://developer.apple.com/download/files/Metal-Performance-Primitives-Programming-Guide.pdf)
|
||
behandelt Tile-Reste/Occupancy, cachefreundliche Work-Reihenfolge und statische
|
||
Tensor-Extents zur Vermeidung unnötiger Bounds-Checks. Das stützt die genannten
|
||
Messkandidaten, beweist aber weder eine konkrete Beschleunigung unseres Kernels
|
||
noch einen behaupteten FP32-Fallback auf Nicht-Tensor-Hardware. Keine weitere
|
||
Geometrie-/Synchronisationsänderung mit der BF16-Änderung vermischt.
|
||
|
||
**Sorted-QMM-Gewichtsloader optimiert (2026-09-05):** Der skalare Aufruf von
|
||
`qwen_quant_weight` im Staging las Packed-Word, Scale und Bias für jeden einzelnen
|
||
Wert erneut. Der Loader lädt diese nun einmal je Wort und entpackt daraus die
|
||
4 beziehungsweise 8 Werte mit derselben FMA und BF16-Rundung. Die installierte
|
||
Konfiguration verwendet bei allen 144 Switch-MLP-Projektionen 4 Bit / Gruppe64.
|
||
Der unveränderte Grouped-Kernel dient weiter als exakte Kontrolle. Alle acht
|
||
Formen bestehen erneut, auch nach der Rückmessung. Nur diese Loader-Änderung
|
||
bleibt zusätzlich zur zuvor geprüften BF16-Speicherung bestehen; BM64/BK32,
|
||
Barrieren, Command-Buffer-Grenzen und Scratch-Kapazität bleiben unverändert.
|
||
Die Wiederverwendung der Scale-/Bias-Werte ist auch im tatsächlichen
|
||
[MLX-0.32.2-QuantizedBlockLoader](https://raw.githubusercontent.com/ml-explore/mlx/v0.32.2/mlx/backend/metal/kernels/quantized.h)
|
||
belegt; dessen Implementierung wurde nicht als Engine-Code übernommen.
|
||
|
||
Gepaarte vollständige Chats **ohne aktiven Canary** (weiterhin Supervisor,
|
||
100%, 2048, Low, bestehende drei Prompts und derselbe fortlaufende Chat):
|
||
|
||
| Modus / Loader | Prefill Summary / Story / Python ms | Runtime-Decode Summary / Story / Python tok/s | größter Summary-GPU-Buffer ms | Summe Chat-Turns ms | Prozess inkl. Laden/Warmup ms |
|
||
| --- | --- | --- | ---: | ---: | ---: |
|
||
| AR skalar | 5297 / 794 / 840 | 48,34 / 47,83 / 48,11 | 3611,37 | 37807 | 58959 |
|
||
| AR wortweise | 4310 / 620 / 622 | 48,25 / 47,83 / 47,86 | 2942,65 | 36385 | 56029 |
|
||
| MTP skalar | 5508 / 828 / 868 | 52,55 / 40,00 / 69,63 | 3612,77 | 35039 | 56833 |
|
||
| MTP wortweise | 4487 / 647 / 648 | 54,22 / 41,61 / 72,89 | 2943,32 | 32616 | 56390 |
|
||
|
||
Mit Canary wurde der wortweise Loader separat gemessen: Summary-Prefill AR4309 ms
|
||
/ MTP4465 ms, großer GPU-Buffer 2940/2937 ms; Prefill-Probe max108,29/28,95 ms,
|
||
keine Fehler. Der AR-Canary-an/aus-Vergleich zeigt in diesen Läufen praktisch
|
||
gleiche Prefillzeit, ist aber keine allgemeine Garantie kostenfreier Messung.
|
||
Die Probe bleibt optional. Alle sieben aktuellen Chats (inklusive BM32-Trial)
|
||
enden dreimal natürlich mit Stop/Exit0; Startvertrag und vollständige Antworten,
|
||
Reasoning, Tokenzahlen sowie Draft-/Accept-/Cycle-Zahlen stimmen mit den
|
||
jeweiligen vorherigen **Rust**-Kontrollen exakt überein.
|
||
|
||
Der große Prefill-Buffer wird auch ohne Canary rund18,5% kürzer. Die AR-Decode-
|
||
Rate bleibt praktisch gleich. MTP-Decode und Prozesszeit sind stärker durch
|
||
PLE-Lesezeit/Warmup beeinflusst (z.B. Summary PLE905 ms skalar vs607 ms neu);
|
||
keinen allgemeinen Decode-Gewinn ausschließlich dem Prefill-Loader zuschreiben.
|
||
Das sind gepaarte Diagnosemessungen, **keine 2%-Abnahme gegen MTPLX** und kein
|
||
UI-Eventloop-Beweis. Versionen, Einzelwerte, End-to-End-Decodewerte und beide
|
||
isolierten Patches: `local-eval-results/20260905-moe-tiles/manifest.md`,
|
||
`comparison.json`. Reiner Matrix-/Staging-Restvergleich und P07/P08 bleiben offen.
|
||
|
||
### P10 — PLE-Streaming und Hot-Cache mit Referenzkosten vergleichen
|
||
|
||
Kanonischer Graphstand 2026-09-07: PLE-Projektion/Gate und dilatierte
|
||
Faltung einschließlich lazy Cache-Fortsetzung sind mit84 echten MTPLX-Fällen
|
||
unmittelbar und verzögert exakt geprüft; siehe „PLE-Projektion und dilatierte
|
||
Cache-Fortsetzung“. Zusätzlich ist der CPU-Staging-Hash samt roher History mit
|
||
64 Original-Receipts geprüft; siehe „N-Gram-CPU-Staging-Hash und rohe History“.
|
||
Der lazy GPU-Hash bis zu den Tabellen-IDs ist mit60 tatsächlichen GPU-Receipts
|
||
unmittelbar und verzögert geprüft; siehe „Lazy N-Gram-GPU-Hash bis zu den
|
||
Tabellen-IDs“. Der vollständige residente `_graph_path` ist einschließlich
|
||
Lookup/Dequantisierung mit24 Original-Ausgaben sofort und verzögert geprüft;
|
||
siehe „Verbundener residenter N-Gram-Graph“. Der Sidecar-Gather samt Prefetch,
|
||
Hot-Cache/Bypass und gemeinsamer Tabellenauswahl ist mit192 Original-Receipts
|
||
in drei Auswertungsarten geprüft; siehe „Verbundener Sidecar-Gather und
|
||
Tabellenauswahl“. Der verbundene Stage-Lifecycle einschließlich QA und Fehler-
|
||
History ist mit136 Original-Receipts in zwei Auswertungsarten geprüft; siehe
|
||
„Verbundener N-Gram-Stage-Lifecycle“. Der vollständige PLE-Aufruf einschließlich
|
||
Sidecar-/Resident-Safetensors-Attach und CPU-Load ist mit144 Original-Receipts
|
||
in zwei Auswertungsarten geprüft; siehe „Vollständiger PLE-Aufruf mit
|
||
Safetensors-Ladeanbindung“. Modellweite Residency-/Memory-Plan-Auswahl,
|
||
übrige Gewichte und Gesamtmodell-/Produkt-Integration bleiben offen.
|
||
Keine P10-Performanceabnahme.
|
||
|
||
Priorität P1; nach P02, P04; Unterschiede belegt, Anteil an Laufzeit offen.
|
||
|
||
- Referenz `NGramEmbedding.stage`, `_SidecarGather._rows_matrices` gegen Rust
|
||
`PleReader::rows`/`ple_batch_with_state`: Staging-Zeitpunkt, deduplizierte IDs,
|
||
pread-Queueing, Kopien und cachefreie große Prefills prüfen.
|
||
- Rust `touch` hängt jedes Mal einen Eintrag an `order`; bereinigt wird nur beim
|
||
Überschreiten der Nutzdatenkapazität. Wiederholte reine Cache-Hits lassen damit
|
||
Metadaten unbeschränkt wachsen. `cache_bytes` erfasst nur 100 Nutzbytes pro Row,
|
||
nicht HashMap/Queue. MTPLX hält seine OrderedDict-Einträge begrenzt.
|
||
- Abnahme: identische PLE-Rows über EOS/Chunk/Replay-Grenzen; begrenzte tatsächliche
|
||
Cache-Metadaten bei Wiederholung. Warm-/Cold-Lookups in beiden Implementierungen
|
||
messen: einzigartige Rows, Bytes, Wall-IO, CPU-Gather, Staging, GPU-Dequant/Projektion.
|
||
Nur nicht überlappende kritische Zeitanteile von Gesamtzeit abziehen.
|
||
- Die in MTPLX `_SidecarGather` dokumentierten M5-NVMe-Mikrosekunden sind historische
|
||
Autorenmessungen; sie ersetzen keine Referenzmessung auf diesem Gerät.
|
||
|
||
### P11 — Qwen-MTP-Sampler, Depth und unnötige Arbeit
|
||
|
||
Priorität P1; nach P02, P03, P04, P09; Quellcodedifferenz belegt,
|
||
direkte Lazy-Übernahme vermessen und nicht beibehalten; Gesamtnachweis offen.
|
||
|
||
**Target-Verteilungen gezielt verglichen (2026-09-05):** Direkte zeilenweise
|
||
Materialisierung wie im aktiven MTPLX-Pfad implementiert, gegen den bisherigen
|
||
Batch-Sampler geprüft und im vollständigen Produktchat nachgemessen. Alle Texte,
|
||
Reasoning-Inhalte, Tokens und Draft-/Accept-Zähler bleiben identisch. Der
|
||
Regressionstest prüft außerdem jeden Ablehnungs-Slot, All-Accept plus Bonus,
|
||
identische weitere RNG-Ziehungen, konzentrierte/breite Masse und CPU-Fallbacks.
|
||
Das ist Rust-Eager/Lazy-Äquivalenz, noch kein vollständiges MTPLX-Sampler-Orakel.
|
||
|
||
Die isolierte Messung mit 32 alternierenden Paaren zeigt aber: vier gebatchte
|
||
Verteilungen kosten rund 0,80ms; lazy 1/2/3/4 benötigte Zeilen rund
|
||
0,53/1,02/1,49/2,04ms. Nur sofortige Ablehnung profitiert. Die Produktänderung
|
||
wurde deshalb zurückgenommen; Vergleichstest bleibt. Der aktuelle Produktionscode
|
||
entspricht nachweislich wieder dem vorherigen Stand, CLI neu gebaut. Eine schnellere
|
||
äquivalente Ausführung ist zulässig; ein anderer Aufrufplan allein ist kein Fehler.
|
||
|
||
Der vollständige wiederhergestellte Harness-Pfad wurde anschließend mit vorhandener
|
||
MTP-Profilierung ausgeführt, erneut mit exakt identischen Antworten/Zählern.
|
||
588 Vier-Zeilen-Verifikationen inklusive Warmup: Median Encoding-Wall3,217ms,
|
||
anschließendes GPU-Warten42,025ms, Readback0,004ms. Host-Zeitgrenzen, keine
|
||
isolierten Kernelzeiten; Profiling und Canary an. Der große Restaufwand liegt
|
||
damit im GPU-Verify-/Submission-Pfad, nicht im Auslesen der Verteilungen.
|
||
P05–P09 sind dafür weiter zu lokalisieren; keine Performance-Parität behauptet.
|
||
Belege und reproduzierbare Prüfungen:
|
||
`local-eval-results/20260905-lazy-target-distributions/manifest.md`.
|
||
|
||
- Draft-D3 wie Referenzdefault vergleichen. D1..D5-Unterstützung ist eine getrennte
|
||
Funktionslücke, kein Grund, während des Default-A/B heimlich die Tiefe zu ändern.
|
||
- Voller Verify-Block: Rust berechnet/verliest alle Target-Verteilungen; MTPLX
|
||
`generation.py` materialisiert lazy bis zur ersten Rejection bzw. Bonusposition.
|
||
CPU/GPU-Sync, Top-k-Pfad und Full-Vocab-Fallback jeweils zählen.
|
||
- RNG nicht pauschal als verschieden bezeichnen: Rust enthält bereits
|
||
NumPy-kompatibles SeedSequence/PCG64. Draw-Reihenfolge, Softmax/top-p/min-p,
|
||
Rejection und Residual müssen auf gleichen Logits/Drafts geprüft werden.
|
||
- Abnahme: deterministische Akzeptanz-/Korrekturfälle, identische Zufallsziehungen,
|
||
gleiche Verteilungssemantik; pro Zyklus Drafts/Accepted/Bonus/Correction, Forward-
|
||
Breiten und Zeiten. Hohe Python-Akzeptanz ist eine Messhypothese, keine Garantie.
|
||
|
||
### P12 — Qwen-MTP-Commit, Fallback und vollständiger Abschluss
|
||
|
||
Priorität P0; nach P03, P04, P06, P11; potenziell schwerer Fallback belegt.
|
||
|
||
Kanonischer Graphstand 2026-09-07: Validierung und reine GDN-Capture-Rekurrenz
|
||
sind mit den vorhandenen Array-Primitiven verbunden und gegen 26 tatsächliche
|
||
MTPLX-Commit-/Decode-Receipts geprüft. Globale Validierung vor Mutation,
|
||
QSA-/PLE-Zweige, Ablehnungszähler, Rollback-/Repair-Orchestrierung und
|
||
Produktintegration bleiben offen; siehe „GDN-Capture-Commit mit nachfolgendem
|
||
Decode“. Die folgenden Befunde betreffen weiterhin den alten Produktpfad.
|
||
|
||
- `restore_or_replay` fällt bei Capture-Fehler auf `replay_tokens` zurück, das
|
||
nach Reset den **gesamten bisherigen Kontext tokenweise** ausführt. Der Fehler
|
||
erscheint nur in stderr, nicht als eindeutig gezähltes Laufzeitereignis.
|
||
- Gegen MTPLX `commit_verified_window`, Conv-Tape-Rekurrenz, Pending-Correction
|
||
und begrenzte Repair-Pfade abgleichen. Nicht bloß den Fallback schneller machen:
|
||
Ursache unvollständiger Captures und korrekte Zustandsgrenze bestimmen.
|
||
- Abnahme: kein unbemerkter Full-Context-Replay; gezielt ausgelöste Rejections an
|
||
jeder Draftposition, alles akzeptiert, EOS, Cancel, Kontextende und Save/Restore.
|
||
KV/GDN/PLE/MTP-History nach Commit mit Target-Referenz vergleichen; vorhandenen
|
||
`qwen_mtp_matches_target_and_restores_its_cache` erweitern statt neuen Teststack bauen.
|
||
|
||
### P13 — DSpark-/GLM-Sampling-Vertrag und effektive Einstellungen
|
||
|
||
Priorität P0; nach P01, P02 für die Messabnahme; Settings-Korrektur und
|
||
Receipt-Tests bestanden, End-to-end-Messung offen.
|
||
|
||
- DS4 `ds4.c:61906` wählt Metal-Confidence 0,6; `:66603` hebt nur bei
|
||
stochastischem Exact Sampling den nicht expliziten Wert auf mindestens 0,8.
|
||
Rust setzte vorher schon normal 0,8 und löste die Exact-Anhebung beim Laden
|
||
statt pro Turn auf. Jetzt gemeinsame Auflösung in
|
||
`EngineSpeculativeSettings::dspark_confidence_for_temperature`, verwendet von
|
||
beiden Proposal-Aufrufern und dem Harness-Receipt. Explizite Werte bleiben
|
||
unverändert, einschließlich 0 und 0,7. Kein Eingriff in gespeicherte Konfigurationen.
|
||
- Harness-Start enthält nun Sampling-Kategorie (`target_only`, `greedy`,
|
||
`opportunistic`, `exact`), Basis-/Turn-Confidence, explizit/automatisch,
|
||
Strict-/Exact-Flags und integriertes MTP-Timing. UI-Hilfetext korrigiert;
|
||
Performance-Fixture bezieht ihren Default aus denselben Produkt-Settings.
|
||
- DSpark opportunistic/strict/exact und GLM opportunistic/exact gesondert erfassen.
|
||
Rust GLM-Sampled-Dispatch leitet an greedy draft matching weiter; das entspricht
|
||
der opportunistischen Kategorie, nicht dem optionalen Exact-Modus der Referenz.
|
||
- Abnahme: Tabellengetriebener Test für fehlenden Wert, expliziten Wert, Exact und
|
||
Quality/Strict. Harness-Receipt enthält effektive Schwelle und Semantik, nicht
|
||
nur `acceleration.enabled`. Fehlende Exact-Unterstützung ausdrücklich markieren.
|
||
|
||
Verifikation 2026-09-05, ohne GPU-Modelllauf oder breite Gates:
|
||
|
||
- Regression vor Korrektur: Default-Test scheitert mit Ist 0,8 / Soll 0,6.
|
||
- `cargo test --release --bin ds4-server settings::tests::`: 8 bestanden,
|
||
einschließlich fehlender/gesetzter Werte und Exact bei Temperatur 0/1.
|
||
- `cargo test --release --bin ds4-server model_eval::tests::`: 8 bestanden,
|
||
einschließlich Receipt-Modi, Quality/Strict, GLM/Qwen und abgeschalteter Acceleration.
|
||
- `cargo test --release --bin ds4-server engine::metal::tests::dspark_`: 2
|
||
CPU-Tests bestanden; modellabhängiger Test blieb explizit ignored.
|
||
- `git diff --check`: bestanden. Keine Durchsatzverbesserung aus diesen Tests
|
||
abgeleitet. Vor der neuen DSpark-Messung bleiben P02/P03/P04 maßgeblich.
|
||
|
||
**Gemeinsamer DS4/GLM-Sampler angeglichen (11.09.):** Der CPU-only-Replay mit
|
||
32 echten GLM-Logit-Zeilen und512 gemessenen Auswahlen zeigte2,645ms pro Schritt
|
||
in Rust gegenüber0,834ms über die originale öffentliche DS4-Funktion. Die Rust-
|
||
Implementierung benutzt nun den begrenzten512-Kandidaten-Heap, originale Logit-
|
||
Tie-Reihenfolge, rohe CDF-Summen und DS4-Fallbacks statt vollständiger Sortierung
|
||
mit erneuter Normalisierung. Initial0,401ms/Schritt bei identischen512 Tokens;
|
||
64 Original-Fixturefälle und17 Sampling-Tests bestanden. Qwens MTPLX-Sampler und
|
||
die separate Verteilungsberechnung für spekulative Korrektur bleiben unverändert.
|
||
Ein kompletter GLM-AR-Chat bewahrt Ausgabe/Thinking/Frontiers und zeigt im einzelnen
|
||
Vorher-/Nachher-Paar5,3–6,6% höheren Decode-Durchsatz. Das ersetzt weder die
|
||
DSpark-Modusabnahme noch die wiederholte Gesamtmatrix. Details im
|
||
[GLM follow-up](glm-scheduling-followup-20260911.md).
|
||
|
||
### P14 — GLM-MTP tatsächlich batchen wie DS4
|
||
|
||
**Produktpfad umgesetzt, Referenz-Performanceabnahme offen (10.09.):**
|
||
`local-eval-results/glm-two-row-20260910.Y1SbdU/{manifest.md,comparison.json}`
|
||
enthält echten Zwei-Zeilen-Forward, Row0-Head, KDA-GPU-Backup/Restore,
|
||
Rejection-Replay und Rewind auf null/ein behaltenes Token. Vorhandene
|
||
Batch-Kernel laufen mit einem wiederverwendeten Zwei-Zeilen-Workspace;
|
||
HC-Expansion leitet ihre Zeilenzahl aus Bufferbytes ab, deshalb darf hier
|
||
nicht die 2048-Zeilen-Allokation verwendet werden. Speicheradmission ergänzt.
|
||
Tests an Frontier12/Context128 und Frontier4095/Context8192 bestehen Annahme,
|
||
Ablehnung, Rewind, Cap1 und bereits gesetztes Cancel. Replay-KDA/Logits sind
|
||
bitgenau skalar; der Grenzfall schaltet wie DS4 auf indexierten Batch um.
|
||
|
||
Der normale Vorher-Chat scheiterte an einem schon vorhandenen zu kleinen
|
||
skalaren Auswahlbuffer im Dense-Compact-KV-Pfad. DS4 reserviert dafür Context-
|
||
statt nur Top-K-Kapazität; gemeinsame Rust-Allokation korrigiert. Danach
|
||
vollständige AR/MTP-Chats bis EOS bestanden, beide Python-Ausgaben inklusive
|
||
5 Assertions und 5011 unabhängigen Fällen korrekt. Kein Speedup aus dem
|
||
abgebrochenen Vorher-Lauf. Decode AR 22,278/21,637/22,443 und MTP
|
||
22,576/19,350/30,768 tok/s; unterschiedliche Antworten/Historien, keine direkte
|
||
DS4-Messung oder 2%-Abnahme. Prefill-CB-Maxima 5,983s AR / 4,419s MTP bleiben
|
||
ein offener Responsivitätsbefund; Canary aus, kein GUI-Stall-Nachweis.
|
||
Aktueller DS4-Quellstand ec7642c: nichtfinale 2048er-Chunks können ebenfalls
|
||
ohne Layer-Flush laufen (>2048 oder Logits+>8 ist die Bedingung); daher nicht
|
||
blind zusätzliche Flushes als Lösung übernehmen. P15 weiter prüfen.
|
||
|
||
Zusätzlicher P13-Messpunkt (ursprünglicher Befund): GLM-MTP-Zähler werden mit Resident-State getauscht,
|
||
die Harness behandelt sie aber als Engine-Lifetime-Counter. Warmup→neuer Chat
|
||
kann deshalb den ersten Turn unterzählen. Vor Akzeptanzraten-Abnahme angleichen;
|
||
Rohwerte erhalten, keine bereinigten Quoten als Beweis ausgegeben.
|
||
|
||
**P13-Zählerscope korrigiert und geprüft (10.09.):**
|
||
`local-eval-results/glm-counter-scope-20260910.HgghwY/manifest.md` enthält den
|
||
roten/grünen Sessionwechsel-Test und den vollständigen Produkt-MTP-Chat. Die
|
||
fünf kumulativen Zähler bleiben nun auf der aktiven Engine, während Cache und
|
||
Draft-Zustand mit dem Chat wechseln. Test prüft Rückkehr in den alten Chat,
|
||
monotone Zähler und bitgleichen rekurrenten Zustand. Alle drei Antworten und
|
||
Tokenzahlen stimmen per `cmp` mit dem vorherigen Lauf überein. Summary zählt
|
||
nun385 statt377 Zyklen und241 statt236 Accepts: Warmup8/5 wurde zuvor fälschlich
|
||
abgezogen. Story/Python unverändert. Keine neue GPU-Arbeit; CB-Zahlen gleich.
|
||
Kein Performance-Pass: Decode22,336/18,682/29,075 tok/s, Prefill-CB-Max4,451s;
|
||
Canary aus. Wächter Exit0, kein laufender Modellprozess. Direkte DS4-Laufzeit-
|
||
Referenz und sechszellige Abnahme bleiben offen; Klärung der AGENTS.md-Regel
|
||
gegen Kompilieren/Aufrufen des C-Referenzprogramms erforderlich. Keine
|
||
C-Produktintegration vorgesehen oder vorgenommen.
|
||
|
||
Fokussierte GPU-/CPU-Tests, Release-Clippy, Build, Format-/Diffcheck bestanden.
|
||
Keine C-Integration, kein Bundle/Commit/Push, Gesamtziel weiterhin offen.
|
||
|
||
**Ursprünglicher Befund und Abnahmekriterien:**
|
||
|
||
Priorität P1; nach P04, P13; Quellcodedifferenz belegt.
|
||
|
||
- Rust `eval_speculative_greedy` führt beim kompatiblen Draft erst
|
||
`eval_glm53_capture(token)` und bei Acceptance nochmals `eval_glm53_capture(draft)`
|
||
aus. DS4 `ds4_session_glm_spec_cycle_impl` (`ds4.c:64176`) verifiziert das Paar
|
||
in einem Zwei-Zeilen-Batch mit KDA-Backup/Restore.
|
||
- Target-Forward, Draft-Head, Rollback und History separat vergleichen. Acceptance
|
||
allein beweist keinen Geschwindigkeitsgewinn, wenn Target-Arbeit nicht amortisiert wird.
|
||
- Abnahme: echter 2-Row-Verify-Aufruf im Receipt, korrekter KDA/DSA/KV-Zustand bei
|
||
Match/Mismatch/Cancel, gleiche Sampling-Kategorie und keine Output-Korruption.
|
||
Danach vollständige GLM-AR/MTP-Chats neu messen; alte überlappte Daten nicht verwenden.
|
||
|
||
### P15 — DS/GLM-Scheduling, Kaltstart und gemeinsame Runtime abgleichen
|
||
|
||
**Numerische GLM-Abweichung reproduziert (Fortsetzung11.09.):**
|
||
64 modellfreie Original-DS4-Sampler-Fälle sichern Tokens und RNG-Zustand ab;
|
||
Greedy-Tie/RNG- und Seed0-Abweichungen sind korrigiert, ohne Qwen zu ändern.
|
||
Die verwendeten positiven Seed42-Benchmarkfälle waren davon nicht betroffen.
|
||
Der neue feste-Historie-Test auf32 echten Original-DS4-Logit-Zeilen trennt die
|
||
Ursachen: Rust-Sampling derselben Zeilen liefert32/32 identische Tokens; Rust-
|
||
GPU-Ausführung derselben Eingaben liefert bereits nach Prefill max5,722/RMS0,851
|
||
Logit-Abweichung und bei Schritt17 ein anderes Sample. Der Test bleibt bewusst
|
||
rot und ignoriert für normale modellfreie Läufe. Die Referenz selbst bewahrt
|
||
den vollständigen AR-Chat exakt trotz optionalem Trace. Nächste Priorität ist
|
||
die erste divergierende HC/KDA/DSA/FFN-Stufe, nicht das Durchsatzetikett auf
|
||
auseinanderlaufenden Chathistorien. Belege/Kommandos und Grenzen stehen im
|
||
[GLM follow-up](glm-scheduling-followup-20260911.md).
|
||
|
||
**Fortsetzung 11.09.:** Der Benutzer bestätigt jetzt normalen GLM-Decode und
|
||
benutzbaren, aber gegenüber Qwen weniger geschmeidigen Prefill. Kein vollständiger
|
||
Freeze behauptet. Die unten am10.09. identifizierte residente skalare Flush-
|
||
Abweichung ist in beiden GLM-Schleifen korrigiert (periodisch alle4, ohne letzten
|
||
Layer/SSD-Streaming); Prefill-Fortschritt meldet nur abgeschlossene bestehende
|
||
Drains und den Batchabschluss. Frische vollständige AR/MTP-Vorher-/Nachher-Chats
|
||
bewahren Tokens/Text/Thinking/EOS ohne beobachtete harte Regression; einzelne
|
||
Laufpaare sind kein kontrollierter Speedup-Beweis. Der ausdrücklich genehmigte
|
||
Standalone-DS4-Benchmark benutzt originale DS4-Objekte ausschließlich außerhalb
|
||
des Produkts und reproduziert Low, separaten Bootstrap und laufende Chathistorie.
|
||
Die separate Canary-Prozessplatzierung war kein fairer Vergleich zum internen
|
||
Canary: gleichzeitig intern490,740ms versus extern höchstens3,331ms. Neue native
|
||
Metal-Zeitstempel lokalisieren eine300ms-Prefill-Probe fast vollständig vor dem
|
||
GPU-Start, nicht in der Host-Rückmeldung. Dieselbe Probe innerhalb des originalen
|
||
DS4-Prozesses reproduziert264,292ms Prefill-Spitze, ebenfalls vor dem GPU-Start;
|
||
771/771 Datensätze sind nach Korrektur der Watchdog-Ausgabeweiterleitung sauber
|
||
auswertbar. Die restliche Kosten-/Latenzdifferenz und weitere Abnahme bleiben in
|
||
[GLM follow-up](glm-scheduling-followup-20260911.md). P15 bleibt offen.
|
||
|
||
**GLM-Ausführungsursache lokalisiert (11.09.):** Rust übernahm die GLM-5.2-
|
||
Top-k-Chunkgrenze für GLM5.3: nach9 Bootstrap-Tokens2039 statt der originalen2048
|
||
Tokens. Nun bleiben GLM5.3-Chunks wie im aktiven DS4-Pfad vollständig; nur die
|
||
Attention-Slices werden an der Dense/Sparse-Grenze geteilt, auch für kreuzende
|
||
Verifier-Paare. Im unverändert vorgegebenen32-Schritt-Replay sind danach alle
|
||
Logit-Vektoren bitidentisch zur Originalreferenz, vorher lagen deutliche Fehler
|
||
bereits im ersten Vektor vor. Vollständige AR/MTP-Chats, Grenzfall-Livetest und
|
||
Performance-Neumessung bleiben erforderlich; dies allein schließt P15 nicht.
|
||
|
||
**Nachprüfung desselben Tages:** Der vollständige AR-Chat stimmt nun in allen
|
||
drei Antworten samt Thinking, Tokenzahlen und Prompt-/Cache-Grenzen überein.
|
||
Bei MTP wurde zusätzlich ein im gemeinsamen UI-/Harness-Consumer behaltenes
|
||
Stop-Token gefunden: der zweite Prompt hatte3249 statt3248 Tokens. Der Consumer
|
||
nutzt nun GLMs vorhandenen Zwei-Zeilen-Rollback, analog zur Stop-Behandlung des
|
||
originalen DS4-Agenten. Danach stimmt auch der vollständige MTP-Chat in allen
|
||
drei Antworten und Grenzen überein (593/872/167 ausgegebene Tokens). Der
|
||
Attention-Grenzfall4095+2 wurde live geprüft. Der strikte32-Logit-Replay und die
|
||
großen Layer0-Tensorvergleiche sind bitidentisch. Einzelne neue Geschwindigkeits-
|
||
paare und diese konkrete Workload schließen nicht die gesamte2%-Matrix oder
|
||
alle Interaktionsfälle ab; P15 bleibt offen. Ergebnisse und Einschränkungen im
|
||
[GLM follow-up](glm-scheduling-followup-20260911.md).
|
||
|
||
**Aktiver GLM-Pfad und durchgehender Canary geprüft (10.09.):**
|
||
`local-eval-results/glm-scheduling-canary-20260910.T1ABR1/{manifest.md,comparison.json}`
|
||
enthält zwei vollständige AR/MTP-Chats bis EOS bei Power100/Low und Canary an.
|
||
Ausgabe einschließlich Tokens/Thinking/Abschluss ist jeweils exakt zum letzten
|
||
Canary-off-Lauf. MTP854/AR935 Proben, keine Fehler, Maxima302,140/251,040ms im
|
||
Prefill; Decode-Maxima27,847/0,929ms. Keine Probe über2s. Ein mehrsekündiger
|
||
Modell-Command-Buffer blockiert diese unabhängige GPU-Probe nicht automatisch
|
||
gleich lange. Keine echte GUI-Eventloop- oder Referenz-Latenzabnahme daraus.
|
||
|
||
Wichtige Quellzuordnung: Im aktuellen DS4 ist expanded/full-KV deaktiviert;
|
||
GLM5.3 benutzt auch für den dichten Compact-Prefix den indexed-Graph. Dieser
|
||
übergibt die Batchtokenzahl als `command_rows`, nicht `pos+rows`. Deshalb passt
|
||
die vorhandene Prefill-Flush-Bedingung für die aktiven <=2048er-Chunks; die
|
||
anderslautende Bedingung des nicht aktiven full-KV-Pfads darf nicht blind in
|
||
Rust übernommen werden. Konkrete Restabweichung im residenten skalaren Decode:
|
||
DS4 flusht periodisch alle4 Layer (ohne letzten Layer), Rust nur einmal nach4.
|
||
SSD-Expert-Streaming hat eigene Command-Ownership-/Sync-Regeln und ist separat
|
||
abzugleichen. Außerdem Host-Encoding-Progress von abgeschlossener GPU-Arbeit
|
||
trennen. Das Manifest enthält die zusammenhängende Folgearbeit samt Abnahmen.
|
||
|
||
**GLM-Teilprefill: HC-Arbeitsmenge korrigiert (10.09.):**
|
||
`local-eval-results/glm-hc-bounds-20260910.BKGvSr/manifest.md` dokumentiert
|
||
den roten/grünen Produktpfad-Test. Dense und indexed DS4-Prefill begrenzen
|
||
HC-/Collapsed-Ausgaben mit token-genauen Views. Rust übergab bisher die gesamte
|
||
Workspace-Kapazität, obwohl sowohl HC-Expansion als auch Split/Sum ihre
|
||
Zeilenanzahl aus den Ausgabebytes ableiten. Der Regressionstest weist echte
|
||
Schreibzugriffe auf unbenutzte Zeilen nach. Fünf einmalig pro übergroßem Batch
|
||
erzeugte, nichtkopierende Views begrenzen jetzt sämtliche vier HC-Aufrufe je Layer;
|
||
der gemeinsame Pfad gilt für normalen Prefill und Zwei-Zeilen-Verifikation.
|
||
Alle fünf Guard-Ausgaben sowie die vorhandenen Rewind-/Rejection-/Counter-
|
||
Prüfungen bestehen. Keine neuen Flushes, keine Chunkverkleinerung, kein anderer
|
||
Kernel oder Sampler. Das beweist unnötige Arbeit, nicht deren Anteil an den
|
||
mehrsekündigen Command Buffers oder an GUI-Stalls. Eine zuerst vermessene Variante
|
||
mit Views auch für bereits exakte Workspaces wurde wegen schlechterer Laufzeiten
|
||
nicht beibehalten; Vorher-/Kontrollbinary sind hash-identisch. Die gezieltere
|
||
Variante besteht alle Guards mit 2048er-Workspace und den vollen MTP-Chat mit
|
||
exakt gleicher Ausgabe. Prefill Summary/Story/Python 6418/269/311ms gegenüber
|
||
6648/394/452ms im ersten Vorher-Lauf, Decode22,500/19,173/30,988tok/s.
|
||
Gesamt96,901s liegt zwischen den beiden Vorher-Läufen99,559/95,288s, deshalb
|
||
kein belastbarer Gesamt-Speedup. Maximaler CB weiterhin4,424s; Canary aus.
|
||
AR-Chat ebenfalls natürlich beendet, Tokens/Text/Thinking/Abschluss identisch
|
||
zum vorherigen AR-Beleg; Prefill8614/278/333ms, Decode21,648/20,967/21,778tok/s,
|
||
Max-CB6,150s. Kein frisches AR-Referenzpaar. Zwischenstände, Messstreuung und
|
||
ausstehende Responsivitätsabnahme bleiben sichtbar. P15/P16 offen.
|
||
|
||
Priorität P1; nach P01, P04, P13; Source-Inventar vorhanden, Detailbeweis offen.
|
||
|
||
- DS4 `ds4.c:35309` teilt nichtkleine Prefills auch wegen echter Progress-Callbacks.
|
||
GLM-Referenz `:47379` berechnet Stage-Sync, Layer-Flush, Progress-Flush und Drain
|
||
getrennt. Rust GLM koppelt Flush an Logits-Anforderung; Zwischenchunks können
|
||
anders laufen. DeepSeek/GLM nicht blind auf eine Qwen-spezifische Policy umstellen.
|
||
- Prefill/Decode-Power, echte Pausen bei <100%, Keine-Pause bei 100%, SSD-/Resident-
|
||
Varianten, finale und nichtfinale Chunks sowie Cancel-Keepalive prüfen.
|
||
- Kalten UI-`ping` separat reproduzieren: Modell-/Pipeline-Laden, Systembootstrap,
|
||
Restore und erster Prefill. Kein Warmup darf diesen Fehler unsichtbar machen.
|
||
OS-Pagecache nicht global leeren; Prozess-kalt und tatsächlich SSD-kalt unterscheiden.
|
||
- Abnahme: Dispatch-/Wait-/Progress-Trace je Phase gegenüber DS4-Code; kalter Ping
|
||
und warmer Chat enden ohne unbeobachtete Phase. Release-Bundle- und Harness-
|
||
Buildidentität dokumentiert. Noch fehlende direkte DS4-Laufzeitreferenz transparent
|
||
halten; C-Inferenz wegen Projektvorgabe nicht eigenmächtig starten.
|
||
|
||
### P16 — Gezielte Änderungen erneut messen und Gesamtmatrix abnehmen
|
||
|
||
Priorität P1; nach den relevanten P01–P15; offen.
|
||
|
||
**Original-DS4-Vergleich erweitert (11.09.):** GLM-AR/MTP bewahren nach dem
|
||
CPU-Sampler-Abgleich in je zwei vollständigen Paaren Ausgabe/Thinking/Frontiers.
|
||
Die umgekehrte Reihenfolge zeigt dennoch AR-Decode-Rückstände bis15,23% und
|
||
MTP-Summary-Prefill bis4,38%; auch die Originalreferenz schwankt stark. Kein
|
||
Median-Pass, keine thermische Erklärung ohne Taktbeleg. Details und unveränderte
|
||
Command-Buffer-Zahlen im [GLM follow-up](glm-scheduling-followup-20260911.md).
|
||
|
||
Der erste DeepSeek-Vergleich ist ausdrücklich ungültig: Der Referenztreiber
|
||
forderte2048 statt des UI-/DS4-Automatikwerts4096 an. Zusätzlich fügte der
|
||
gemeinsame Produkt-Renderer bei einem reinen Bootstrap-Cache fälschlich EOS vor
|
||
dem ersten User-Prompt ein (2742 statt2741 Tokens). Der Tokenizer selbst stimmt.
|
||
Ein gezielter CPU-Test reproduziert diesen UI-/Headless-Fehler vor der Korrektur;
|
||
nach dem Nichtleer-History-Guard bestehen DeepSeek- und GLM-Originalfixtures.
|
||
Referenztreiber auf Automatik angeglichen, keine Produkt-Chunkverkleinerung.
|
||
Das korrigierte vollständige DeepSeek-AR-Paar stimmt nun in allen Antworten,
|
||
Thinking-, Token- und Cache-Feldern überein, verfehlt aber im Einzelpaar noch
|
||
das Durchsatzziel. Das neue DSpark-Paar scheitert funktional: erste Antwort
|
||
bereits647 statt1208 Tokens bei identischem Prompt; anschließend jeweils ein
|
||
zusätzlich behaltenes EOS im Rust-Cache. Die normale Beendigung und bestandene
|
||
Python-Tests ändern diesen roten Vergleich nicht. Nächste zusammenhängende
|
||
DSpark-Einheit: erster divergenter Proposal-/Verify-Zyklus, Stop-/Capture-Frontier
|
||
und zusätzliche Vollvokabular-Readbacks gemeinsam gegen Original DS4 prüfen
|
||
und angleichen, dann neu messen. Konkrete Quellen, Rohdaten und Tests im
|
||
[DeepSeek follow-up](deepseek-reference-followup-20260911.md).
|
||
|
||
**DSpark-Zyklus-/Zustandsabgleich fortgesetzt:** Der neue vollständige
|
||
Diagnoselauf stimmt jetzt in allen1755 Originalzyklen einschließlich Warmup,
|
||
Antworten, Thinking und Cachepositionen überein. Ursachen waren fehlende
|
||
HC-/Attention-Norm beim Support-KV-Aufbau, der abweichende Einzeldraft-Verifier,
|
||
Seed-/Teilannahme-Capture, Cachefenster-/Scheduler-/EOS-Übergänge und fehlende
|
||
Aktivierungsquantisierung des tatsächlich installierten Q8-Confidence-Kopfs.
|
||
Zusammenhängende Quellen-/Taskliste und Rot→Grün-Belege stehen im verlinkten
|
||
Follow-up. Early-Confidence-Gate und Verifier-Readbacks/Submission sind inzwischen
|
||
ebenfalls angeglichen; alle1755 Originalzyklen bleiben exakt gleich. Noch keine
|
||
Leistungsabnahme: saubere Wiederholungspaare zeigen starke zeitliche Drift in
|
||
beiden Implementierungen. Die CPU-Worker-Policy ist ebenfalls angeglichen:
|
||
dauerhafte12 Threads inklusive Aufrufer, weiterhin1755 identische Zyklen.
|
||
Ein CPU-only-Dispatchvergleich zeigt einen kleinen Gewinn, keine Erklärung für
|
||
den verbleibenden Gesamtgap. Verifier-/Frontier-Puffer werden inzwischen über
|
||
Zyklen wiederverwendet; der32-Zyklen-Test prüft Pufferidentität und bytegenaue
|
||
Rücknahme, der vollständige Chat weiterhin alle1755 Originalzyklen. Auch der
|
||
Exact-Sampling-Test besteht. Die jüngsten beiden Paare verfehlen jedoch weiter
|
||
Teile des Durchsatzziels; kein belegter Gesamtgewinn durch diese Änderung.
|
||
|
||
**Messbedingung nach Nutzerklarstellung (11.09.):** Parallel laufen Videos und
|
||
beanspruchen einen Teil der GPU. Die genaue zeitliche Überlappung früherer
|
||
Messungen ist unbekannt. Die jüngsten seriellen Paare bleiben als Rohdaten
|
||
erhalten, gelten aber nicht als kontrollierte2%-Abnahme oder kausaler
|
||
Vorher/Nachher-Beleg. Weder alle Differenzen auf Videos schieben noch thermische
|
||
Drosselung behaupten. Keine weiteren Durchsatzserien während dieser Nutzung;
|
||
Funktionsprüfungen und Code-Abgleich bleiben möglich. Die vollständige
|
||
Sechsfeldmatrix, Responsivitätsabnahme und Zähler-Scope-Bereinigung bleiben offen.
|
||
Der Nutzer hat den Abschluss und Commit/Push dieses Zwischenstands freigegeben;
|
||
die vorgeschriebenen Commit-Gates umfassen auch den erneuten Bundle-Bau.
|
||
|
||
**Aktuelles interaktives Test-Bundle bereitgestellt (10.09.,22:32):**
|
||
`make bundle` und strikte Codesign-Prüfung bestanden. Das Bundle enthält den
|
||
zuletzt vermessenen Release-Code und identische Metal-Ressourcen; der genaue
|
||
signaturbedingte Mach-O-Unterschied ist im Manifest
|
||
`glm-scheduling-canary-20260910.T1ABR1` nachgewiesen. `model-eval --help` direkt
|
||
aus dem Bundle besteht ohne Modell-/GUI-Start. Der bisherige September6-Build
|
||
ist ersetzt. Kein tatsächlicher GUI-Eventloop-/Kaltstart-Test und keine
|
||
sechszellige Performance-Abnahme; die Anwendung ist als Teststand verfügbar.
|
||
|
||
**Neue Plain-Chat-Referenzdiagnose (2026-09-05):** Unveränderter MTPLX-Server,
|
||
exakte eingefrorene Eingabeprompts und Samplerwerte der Rust-Diagnose, keine
|
||
zusätzliche leere Systemnachricht; AR und MTP sequenziell, vollständiger
|
||
Summary/Story/Python-Chat. Alle Antworten natürlich beendet, Python-Prüfungen
|
||
bestanden, beide Supervisor exit 0. Erster Summary-Prompt identisch 2617 Tokens:
|
||
MTPLX-Prefill 2,455 s AR / 2,528 s MTP versus Rust 4,483 / 4,697 s mit sogar
|
||
30 bereits gecachten Tokens. Referenz-MTP-Decode 71,403/55,527/90,376 tok/s versus
|
||
Rust 53,976/38,874/61,596. Kein Pass: Canary an, jeweils Einzelmessung, andere
|
||
gesampelte Historien, Cache-Arbeit und Stop-Token-Zählweise. MTPLX zählt das
|
||
Stop-Token mit, Rust nicht; dieser Messvertrag gehört zu P04, keine unautorisierte
|
||
Änderung der Produktzähler. Referenz-Canary max 4,679/4,540 ms gegenüber
|
||
Rust 102,483/84,761 ms. Der Rückstand bleibt sichtbar, auch ohne Mehrsekunden-Stall.
|
||
Details, Rohdaten, Hashes und Grenzen:
|
||
`local-eval-results/20260905-plain-reference/manifest.md`.
|
||
|
||
- Während der zusammenhängenden Qwen-Portierung: Referenz-/Regressionstests für
|
||
Funktions-, Kernel- und State-Abdeckung; Änderungen und Restabweichungen hier
|
||
nachtragen. Gesamt-Performancevergleich erst nach vollständiger Integration,
|
||
nicht als Auswahlverfahren für einzelne Referenzbestandteile.
|
||
- Endmatrix: DeepSeek AR/DSpark, GLM AR/MTP, Qwen AR/MTP. Leistung 100%, Chunks
|
||
2048 soweit Produkt/Referenzvertrag, kleinster aktiver Thinking-Level; Sampler und
|
||
MTP-Einstellungen innerhalb jedes Referenzpaares identisch, keine künstliche
|
||
Gleichsetzung verschiedener Modellverträge.
|
||
- Pro Zelle separater Warmup, danach Summary README → Story → Python als ein
|
||
ongoing Chat bis EOS. Zusätzlicher kalter Ping; keine Gesamtzeitbegrenzung.
|
||
Startup-/Fortsetzungswatchdog, echte Fortschrittsereignisse, Speichergrenze,
|
||
Prozessüberwachung und genau ein GPU-Modell gleichzeitig.
|
||
- Saubere Performance-Läufe Canary aus, separate vollständige Responsiveness-Läufe
|
||
Canary an; mindestens drei gepaarte Wiederholungen in wechselnder Reihenfolge.
|
||
Bei Messstreuung in Größenordnung der 2%-Grenze kein Pass aus einem Einzelwert.
|
||
- Tabelle je Turn: neue/cached/Output/Thinking-Tokens, Load/Restore/Prefill/TTFT,
|
||
Prefill- und Decode-tok/s, Gesamtzeit, MTP-Akzeptanz und Zeitzerlegung,
|
||
GPU/Host/UI-p50/p95/p99/max, Peak-Footprint, IO und Abschlussursache.
|
||
- Inhaltliche Abnahme: Summary deckt README ab; vollständige Story ohne Rückfrage;
|
||
Python-One-shot anhand vorab festgelegter kleiner funktionaler Assertions prüfen.
|
||
Generierten Code vor Ausführung prüfen und isolieren, keine Tools/Netzwerkrechte.
|
||
- Durchsatzziel: mindestens 98% der matched-work Referenzgeschwindigkeit; schneller
|
||
erlaubt. Gesamtzeiten der natürlichen Chats zusätzlich zeigen, aber unterschiedliche
|
||
Antwortlängen nicht als Kernelregression ausgeben. Latenz separat abnehmen; ein
|
||
schneller Durchschnitt kompensiert keinen Mehrsekunden-Stall.
|
||
Nutzerentscheidung vom 2026-09-10: Die beobachteten 2,6% Rückstand bei **Qwen
|
||
Summary ohne MTP** sind als eng begrenzte Ausnahme akzeptiert, ausschließlich
|
||
wenn alle übrigen Punkte erledigt sind und die produktive Anwendung ansonsten
|
||
Funktions- und Performance-Parität erreicht. Keine allgemeine Toleranzerhöhung,
|
||
keine vorgezogene Abnahme und keine Ausnahme für Stalls, Prefill oder andere Turns.
|
||
|
||
### R01 — MTPLX-Speculation als zusätzliche Optimierungsquelle für DS/GLM
|
||
|
||
Separater Recherche-Task; nach belastbarer DS4-Baseline P13–P16, kein Wechsel des
|
||
Golden Masters und keine Voraussetzung für die erste Paritätsabnahme.
|
||
|
||
- Im gepinnten MTPLX existiert ein eigener DeepSeek-V4-Backendpfad
|
||
(`mtplx/models/deepseek_v4.py`, Registrierung `mtplx/backends/registry.py:299`).
|
||
Native MTP-Köpfe dort nicht ohne Prüfung mit DSpark/DFlash gleichsetzen.
|
||
- Generische Techniken wie batched verify, lazy distributions, begrenzte
|
||
Capture-Commits, Deferred Repair und Draft-Tiefensteuerung auf Übertragbarkeit
|
||
für beide Modelle untersuchen. Eine native GLM-5.3-Flash-Unterstützung wird hier
|
||
nicht behauptet; allgemeine Techniken können auch ohne diesen Backendpfad relevant sein.
|
||
- Ergebnis: kurze Kandidatenliste mit exakter Quellstelle, Artefakt-/Draft-Vertrag,
|
||
unveränderter oder abweichender Sampling-Semantik, gemessenem Referenzvorteil und
|
||
kleinstem A/B-Versuch. Nicht passende oder nur beworbene Vorteile aussortieren.
|
||
- Abnahme einer späteren Übernahme weiterhin gegen **antirez/ds4**: gleiche
|
||
Funktion, keine schlechtere Responsiveness, belegter Performancegewinn. Kein
|
||
Download anderer Artefakte und keine Umstellung auf MTPLX-Runtime als Abkürzung.
|
||
|
||
## Reihenfolge und Fortschrittsführung
|
||
|
||
Zuerst P01–P04 als belastbare Vergleichsgrundlage. Danach P05/P06 für den belegten
|
||
Qwen-Prefill-Fehler und P12 für unbeschränkte Repair-Kosten; P11 liefert dafür den
|
||
Sampler-/Acceptance-Nachweis. P07–P10 schließen die übrigen Kernel-/IO-Unterschiede.
|
||
P13 muss vor DSpark-Vergleichen erledigt werden, P14/P15 vor der DS/GLM-Freigabe.
|
||
P16 misst den vollständig integrierten Qwen-Port und die komplette Modellmatrix;
|
||
die frühere Mikrobenchmark-Auswahl pro Änderung ist aufgehoben.
|
||
|
||
Pro Task werden Status, konkreter Patch, Referenz-/Arbeitsstand, Testbefehl,
|
||
Rohdatenpfad, vorher/nachher und verbleibende Differenz ergänzt. Eine Abweichung
|
||
verlässt die Liste nur durch Nachweis oder ausdrückliche Nutzerentscheidung,
|
||
nicht durch Weglassen aus dem nächsten Bericht.
|