Files
daedalus-fourier/docs/k3_mc_phase7.md
T
marfrit 460a6a6d08 Calibration: M4 same-kernel measures worst-case contention
User-flagged 2026-05-18: the cycles 3 (MC) + 5 (CDEF) 'CPU only'
verdicts were based on M4 measuring same-kernel concurrent NEON+QPU,
which is the WORST case for memory-bandwidth contention. A real
decoder pipeline has CPU doing kernel A + QPU doing kernel B
concurrently — different access patterns contend less.

Concretely: in a real pipeline, CPU runs entropy + MC + other work
while QPU is idle except for IDCT + LPF. The 'opportunistic QPU
helper' for CDEF (or MC) hasn't been measured. M4 set the bar too
high.

Updates:
- docs/k3_mc_phase7.md §'M4 methodology caveat' added with the
  user's contribution framing
- docs/k5_cdef_phase3_partial.md §'Deployment recommendation'
  softened from 'CPU only' to 'CPU baseline; QPU helper viable in
  mixed-kernel deployment, unmeasured'
- docs/issues/003-mixed-kernel-m4-bench.md filed — the rigorous
  test to close the question (4 variants: bandwidth+bandwidth,
  compute+CDEF, same-kernel control, real-pipeline mix)
- ~/.claude/projects/-home-mfritsche-src-daedalus-fourier/memory/
  feedback_m4_same_kernel_worst_case.md added — carries the
  calibration into future cycles + Phase 8 deployment decisions
- MEMORY.md index updated

The bandwidth-bound vs compute-bound classification still holds at
the kernel level — Phase 9 cross-cycle lesson stays valid. But its
mapping to deployment is nuanced:
  - Bandwidth-bound on QPU → DEFINITIVE offload (M4 +ve, cycles 1+2+4)
  - Compute-bound on QPU → OPPORTUNISTIC helper if pipeline has
    bandwidth-light CPU work running concurrently (cycles 3+5,
    needs Issue 003 measurement)

Phase 8 V4L2 wrapper should keep CDEF + MC slot-able to either CPU
or QPU at runtime (not hard-baked), so Issue 003's result can update
the dispatch table without re-architecture.

No code changes. Doc + memory + issue only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 13:31:27 +00:00

180 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
cycle: 3
phase: 7
status: closed 2026-05-18 — RED engineering / PASS 30fps-floor / M4 NEGATIVE
date_opened: 2026-05-18
date_closed: 2026-05-18
parent: k3_mc_phase4.md (revised per phase5''')
host: hertz
verdict: cycle 3 closes; MC stays on CPU for higgs deployment; engineering negative documented
---
# Cycle 3, Phase 7 — Verification (v1 + M4''')
## v1 first-light
```
=== v3d MC 8h bench ===
n_blocks: 65536 iters: 100
=== M1''': QPU vs C reference bit-exact ===
blocks bit-exact: 65536 / 65536 (100.0000 %)
=== M2''': QPU throughput ===
M2''' = 1.413 Mblock/s
per-block = 707.9 ns
per-dispatch = 46390.5 us
R''' = 0.067 → RED band
30fps@1080p floor: 1.5x margin (isolation)
```
shaderdb (v1 MC):
```
SHADER-DB-ffcca249...: 488 inst, 2 threads, 0 loops, 197 uniforms,
25 max-temps, 0:0 spills:fills, 0 sfu-stalls, 488 inst-and-stalls, 7 nops
```
**Phase 5''' finding 2 prediction confirmed**: filter LUT inflated
uniforms to 197 (gate was at ~144). Compiler also forced to 2 threads
(from cycle-2's 4) due to register pressure (25 max-temps vs cycle-2's
21). The "no DP4A" structural deficit shows up directly here — 8
SMUL24 + 7 ADD per output pixel × 64 pixels per block × 8-lane
geometry = 488 instructions, 30× heavier than the LPF kernel.
## M4''' concurrent matrix (8s windows)
| Config | Mblock/s | per-core (NEON) | vs NEON-4 | 30fps |
|---|---|---|---|---|
| NEON 1-core | 14.479 | — | — | 14.9× |
| **NEON 4-core** | **15.248** | 3.24 4.48 | **baseline** | 15.7× |
| QPU only | 1.380 | — | — | 1.4× |
| **Mixed NEON-3 + QPU** | **12.277** | 3.78 4.16 | **19.5 %** | 12.6× |
| Mixed NEON-4 + QPU | 12.158 | 2.49 3.35 | 20.3 % | 12.5× |
**M4 gate: FAIL.** Mixed (12.28) < pure NEON-4 (15.25) by 2.97
Mblock/s. The QPU's 0.45 Mblock/s contribution under contention
doesn't compensate for losing one NEON core that delivers ~3.8.
## Cross-cycle comparison
| | Cycle 1 IDCT | Cycle 2 LPF | Cycle 3 MC |
|---|---|---|---|
| R isolation | 0.92 | 0.41 | **0.067** |
| 30fps floor margin (isolation) | 7.9× | 10× | **1.5×** |
| M4 mixed vs pure NEON-4 | +7.2 % | +6.9 % | **19.5 %** |
| 30fps floor margin (mixed) | 7.2× | 7.2× | **12.6×** |
| Verdict for higgs | GO QPU | GO QPU | **STAY CPU** |
| NEON 4-core scaling vs 1-core | 0.56× (bw-bound) | 0.82× (bw-bound) | **1.05× (compute-bound)** |
The MC result is **structurally consistent** with the V3D substrate
profile from `phase0.md`:
- No DP4A → 8-wide convolution doesn't pack as it does on NEON SDOT
- Filter coefficients drive uniform count high → register pressure → 2 threads
- High per-output-pixel multiply count → compiled instruction count
3× cycle 1, 6× cycle 2
NEON 4-core is *compute*-bound for MC (not bandwidth-bound like
the other two kernels). So 4-core scales nearly linearly with cores —
the NEON CPU has plenty of headroom and the QPU has nothing to add
even in concurrent mode.
## Deployment recipe (for higgs / libva-v4l2-request-fourier)
Per `project_consumer_target.md`, the eventual integration target is
V4L2 stateless → libva-v4l2-request-fourier → firefox-fourier. The
back-end-on-QPU/CPU split for the consumed decoder pipeline:
- **IDCT (cycle 1)** → QPU. R = 0.92, +7 % mixed, frees a CPU core.
- **LPF (cycle 2)** → QPU. R = 0.41, +7 % mixed, frees a CPU core.
- **MC (cycle 3)** → **CPU NEON baseline; QPU offload viable as
opportunistic helper, not yet measured.** R = 0.067 in isolation
was discouraging; M4 same-kernel mixed was 19.5 % which looks
conclusive but isn't — see *M4 methodology caveat* below.
- **Entropy** (VP9 Bool / AV1 ANS) → CPU. Structurally serial.
This is a **mixed-substrate deployment**, not a "QPU does everything"
plan. Realistic for higgs: entropy + MC on 2-3 ARM cores; IDCT + LPF
dispatched to QPU concurrently; 1-2 ARM cores left for vscode / etc.
## M4 methodology caveat (added 2026-05-18 after cycle 5)
The M4 mixed bench (`bench_concurrent_mc.c`) tests NEON-3 + QPU
running the SAME kernel concurrently. This is the **worst case** for
memory-bandwidth contention — both substrates competing for the same
bus with the same access pattern.
A real decoder pipeline has different shape: CPU runs entropy + MC
+ other CPU-bound work; QPU runs IDCT + LPF + (potentially) MC as
opportunistic helper. **Different kernels on different substrates**
contend less than same-kernel-on-both. Our M4-same-kernel result is
a pessimistic lower bound, not the actual deployment number.
Empirically supporting this: cycle 3 M4 showed per-core NEON
throughput in 3-core mode (3.78-4.16 Mblock/s) was higher than in
4-core mode (3.24-4.48), confirming bandwidth saturation at ≥4
cores. So freeing 1 core via QPU offload costs ~25 % of total NEON
MC throughput, but the QPU contributes 0.45 (-MC) or 1.4 (in CDEF
isolation) on top.
**To rigorously test the helper hypothesis**: see
`docs/issues/003-mixed-kernel-m4-bench.md`. A bench that runs
NEON-3 on kernel-A + QPU on kernel-B concurrently would close the
question. ~½ day of additional bench work; would update the
deployment recipe for cycles 3 + 5 if the result is positive.
## Decision per Phase 1 rules + 30fps-floor calibration
| Rule | Result | Status |
|---|---|---|
| M1''' bit-exact | 100.0000 % | ✓ PASS |
| R''' = M2'''/M3''' | 0.067 (RED) | structural mismatch |
| M4''' > pure-CPU 4-core | 19.5 % | ✗ FAIL gate |
| 30fps@1080p floor (isolation) | 1.5× | ✓ PASS (user-facing) |
| 30fps@1080p floor (mixed) | 12.6× | ✓ PASS (user-facing) |
**Engineering cycle verdict: do not deploy MC on QPU; deploy on CPU.**
**User-facing cycle verdict: 30fps floor easily met in any
configuration; either path works for daily YouTube.**
For the deployment recipe above, **MC stays on CPU**. The Phase 1
ORANGE/RED "honest close" rule applies here: cycle 3 closes as a
documented negative for this kernel without affecting the
project-level "continue" verdict (cycles 1+2 GO results stand).
## Phase 9 lessons (added to project memory)
1. **Multiply-heavy workloads expose V3D's no-DP4A deficit** in a way
that cycle 1+2 didn't. CPU SDOT/UDOT pack 4 INT8 MACs in one
instruction; V3D's SMUL24 is one scalar mult at a time. The 4×
gap shows up directly as a 6-15× per-block slowdown.
2. **Compute-bound CPU workloads make the QPU offload story collapse.**
When NEON 4-core scales near-linearly (not bandwidth-saturated),
the "freed-core" argument from cycle 1+2 doesn't apply — there
are no free cycles to free. Mixed mode is strictly worse.
3. **The 30fps@1080p user-facing test (`project_30fps_floor_is_fine.md`)
passes regardless of engineering verdict.** All three cycles pass
it in isolation. This is a project-level win to communicate
separately from per-cycle engineering R numbers.
4. **The shaderdb filter-LUT gate from phase5''' finding 2 fired
exactly as predicted** (197 uniforms > 144 threshold; 2 threads
instead of 4). This validates the cycle-discipline of running
`V3D_DEBUG=shaderdb` early and using the result as an actionable
gate. Cycle 4 (if any) should bake this in from Phase 4 §design.
## Leaves open
- Cycle 3 v2 with filter LUT escalated to SSBO (per phase5''' finding 2
trigger). Would reduce uniforms to ~30, potentially restore 4
threads. Expected upside: ~2× → R''' = 0.13. Still RED, still M4-
negative. Skipped — even doubling doesn't change the deployment
recipe.
- Vertical / hv / 4-tap / wider variants — all of cycle 3 same
multiply-shape, same structural verdict expected. Not worth Phase
1+ for those.
- Cycle 4 candidates (per phase7_M4.md §"Cycle 3 candidates"):
CDEF (AV1-only directional filter), Loop Restoration (AV1-only),
or higgs deployment plumbing.