feat(alpha): phase_e_kill_criteria producer kernel (slots 539-542)
Phase E.0 Task 9. Single-block, single-thread CUDA producer that writes 4
raw scalar observations into a contiguous scratch_out[0..4] block:
scratch_out[0] → ISV[539] Q_SPREAD_EMA (kill: ≥ 0.05)
scratch_out[1] → ISV[540] ACTION_ENTROPY_EMA (kill: ≥ 0.5·ln(9) ≈ 1.10)
scratch_out[2] → ISV[541] RETURN_VS_RANDOM_EMA (kill: ≥ 0, i.e. ≥ random)
scratch_out[3] → ISV[542] EARLY_Q_MOVEMENT_EMA (kill: ≥ 0.01, learned)
Downstream `apply_pearls_ad_kernel` (n_slots=4) chained on the same stream
applies Pearl A first-observation bootstrap + Pearl D Wiener-α smoothing —
composes with the canonical val_sharpe_delta_compute_kernel pattern rather
than reimplementing Wiener math (per feedback_no_cpu_compute_strict — one
Wiener implementation in the codebase, the GPU one).
Inputs:
q_values[batch, n_actions] most-recent Q forward output (device)
action_counts[n_actions] empirical action histogram (device)
scalar_inputs[3] [rollout_R_mean, q_init_norm, q_early_norm]
via mapped-pinned (host writes between rollouts)
isv reads slots 547 + 548 (random baseline
mean/std — populated once by Task 7c,
TrainingPersist)
No atomicAdd (per feedback_no_atomicadd), no host branches
(per pearl_no_host_branches_in_captured_graph), no CPU compute
(per feedback_cpu_is_read_only). __threadfence_system() before exit for
the chained Pearls applicator's visibility guarantee.
Cubin produced: target/release/build/ml-*/out/phase_e_kill_criteria.cubin
(16.8 KB).
Launcher integration is Task 11 (separate commit so this task can stand
alone for cubin validation). Audit doc docs/isv-slots.md updated per
Invariant 7.
This commit is contained in:
@@ -547,3 +547,22 @@ Phase E Task 2 lands the registry entries + 7 dispatch arms (4 SoftReset diagnos
|
||||
- `crates/ml/src/trainers/dqn/trainer/training_loop.rs` — 7 dispatch arms in `reset_named_state` (the 3 TrainingPersist names are not dispatched)
|
||||
|
||||
All 10 registry tests + the global registry coverage test pass: `cargo test -p ml --lib state_reset_registry`.
|
||||
|
||||
## Alpha block — Phase E Task 9 producer kernel (2026-05-15)
|
||||
|
||||
Phase E.1 Task 9 lands the producer for slots 539-542 (`phase_e_kill_criteria.cu`). Single-block, single-thread kernel; writes 4 raw scalar observations into `scratch_out[0..4]`, then the existing `apply_pearls_ad_kernel` (chained on the same stream, `n_slots=4`) applies Pearl A bootstrap + Pearl D Wiener-α smoothing into the four ISV slots:
|
||||
|
||||
- `scratch_out[0]` → ISV[539] `Q_SPREAD_EMA_INDEX` — mean over batch of `std(Q, axis=action) / |mean(Q)|`
|
||||
- `scratch_out[1]` → ISV[540] `ACTION_ENTROPY_EMA_INDEX` — `H(empirical action distribution)` in nats
|
||||
- `scratch_out[2]` → ISV[541] `RETURN_VS_RANDOM_EMA_INDEX` — `(rollout_R − ISV[547]) / max(ISV[548], 1e-6)`
|
||||
- `scratch_out[3]` → ISV[542] `EARLY_Q_MOVEMENT_EMA_INDEX` — `|q_early_norm − q_init_norm| / max(|q_init_norm|, 1e-6)`
|
||||
|
||||
Kernel reads ISV[547]/ISV[548] (random baseline mean/std, populated once by Task 7c, TrainingPersist) via slot indices passed as kernel args. Composability per `val_sharpe_delta_compute_kernel` — no inline Wiener math here, the canonical `apply_pearls_ad_kernel` handles it.
|
||||
|
||||
**Files touched:**
|
||||
- `crates/ml/src/cuda_pipeline/phase_e_kill_criteria.cu` (new) — producer kernel
|
||||
- `crates/ml/build.rs` — added kernel to `kernels_with_common` list
|
||||
|
||||
**Cubin:** `target/release/build/ml-*/out/phase_e_kill_criteria.cubin` (~16.8 KB).
|
||||
|
||||
**Launcher wiring:** lands in Phase E.1 Task 11 (the DQN training loop reads `phase_e_kill_criteria_compute_kernel` from the compiled cubin and chains `apply_pearls_ad_kernel` on the same stream after it).
|
||||
|
||||
Reference in New Issue
Block a user