Commit Graph

1858 Commits

Author SHA1 Message Date
jgrusewski
f8f1147de7 fix: attention kernel load from wrong cubin + build.rs bf16 label
attn_sdp_fwd and attn_layer_norm_fwd were loaded from attention_kernel.cubin
(which only contains the legacy multihead_feature_attention) instead of
attention_backward_kernel.cubin where they actually live. This caused
CUDA_ERROR_NOT_FOUND on H100, silently disabling attention.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 12:07:13 +02:00
jgrusewski
69ace546aa fix: eliminate cuStreamSynchronize in IQN loss readback — was serializing every step
IQN read_total_loss() called cuStreamSynchronize + cuMemcpyDtoH every training
step, blocking the CPU until all GPU work completed. This serialized the entire
async pipeline, causing 3537ms/step instead of <10ms.

Fix: pinned device-mapped memory for IQN total_loss (same pattern as DQN trainer).
GPU writes via device pointer, CPU reads via host pointer, zero sync.

Also re-applies the cuGraphClone elimination (was lost when agents modified
fused_training.rs) and adds recursive_confidence_reduce for deterministic
gradient accumulation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 11:35:10 +02:00
jgrusewski
6960a02af4 fix: eliminate cuGraphClone + recursive_confidence atomicAdd — deterministic graph replay
- capture_child_graph: use std::mem::forget to take ownership of cudarc's
  CudaGraph handles directly. cuGraphClone corrupts cublasLtMatmul HMMA tile
  scheduling state on Hopper, causing graph replay to hang with temporal ops.
- create_eval_forward_exec: instantiate directly from original graph (no clone).
  Multiple execs from the same CUgraph is safe per NVIDIA docs.
- recursive_confidence_backward: replace atomicAdd into grad_buf with per-block
  partial output + deterministic reduce kernel. Zero atomicAdd on gradient path.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 10:50:46 +02:00
jgrusewski
80769abb9c cleanup: purge all bf16 naming remnants — pure f32/TF32 pipeline
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 10:30:04 +02:00
jgrusewski
c80a253557 fix: rewrite curiosity inference to cuBLAS GEMMs — eliminates per-sample matmul inside graph
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 10:27:21 +02:00
jgrusewski
a230ad5979 fix: kan_gate_backward — eliminate atomicAdd with per-element output + deterministic reduce
Split into two kernels: kan_gate_backward writes per-element basis
contributions to intermediate buffers (no cross-element reduction),
then kan_grad_reduce deterministically accumulates them with one
thread per output parameter — fully eliminating atomicAdd from the
KAN spline gradient path.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 10:25:22 +02:00
jgrusewski
661e1304a0 cleanup: rename all _bf16 kernel functions and variables — pure f32 pipeline
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 10:19:12 +02:00
jgrusewski
3065ae1f3b fix: DT kernels — eliminate atomicAdd, deterministic gradient reduction
Three atomicAdd anti-patterns removed from Decision Transformer kernels:

1. dt_linear_backward_kernel (critical): Split into dt_linear_backward_kernel
   (input gradient only, per-sample deterministic) + dt_linear_grad_kernel
   (one thread per weight, loop over samples — zero atomics).

2. dt_causal_attention_kernel: Replace cross-head atomicAdd output projection
   with per-head output buffer [B, H, T, E] + separate dt_sum_heads_kernel
   that sums heads in fixed order.

3. dt_cross_entropy_kernel: Remove atomicAdd for total_loss, add
   dt_reduce_loss_kernel (single-thread sequential sum for full determinism).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 10:05:05 +02:00
jgrusewski
020e9ba460 fix: rewrite curiosity training to per-block reduce — eliminates non-deterministic atomicAdd
Replace warp-reduced atomicAdd gradient accumulation in the curiosity
forward model with a two-kernel deterministic pipeline:

1. curiosity_fwd_bwd_per_block: each block reduces its threads' gradient
   contributions via shared memory tree reduction, writes one partial
   gradient vector [CUR_TOTAL_PARAMS] per block.

2. curiosity_grad_reduce: one thread per parameter sums block partials
   in fixed order (block 0, 1, 2, ...). Fully deterministic.

Deleted kernels: curiosity_forward_backward (atomicAdd path),
curiosity_fused_zero_fwd_bwd_adam (grid-wide atomic barrier),
curiosity_adam_step_fused (dead code), warp_sum_cur helper.

Rust side: removed block_counter, adam_fused_func,
fused_zero_fwd_bwd_adam_func. Added partial_grads buffer
[max_blocks * CUR_TOTAL_PARAMS] (~2.8 MB for 64 blocks).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 09:59:11 +02:00
jgrusewski
29d7a7bd60 fix: replace cuMemcpyHtoDAsync with pinned device-mapped memory in IQN/IQL/Attention — graph capture safe
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 09:51:55 +02:00
jgrusewski
5b90ebe9e9 fix: curiosity wiring + cleanup dead attention kernels + stale comments
- gpu_experience_collector: add curiosity_weight param to new(); conditionally
  initialize GpuCuriosityTrainer when weight > 0.001 (was always None)
- training_loop: pass hyperparams.curiosity_weight to GpuExperienceCollector::new()
- gpu_experience_collector: replace misleading 'curiosity disabled' log with
  weight-conditional message; zero-init comment explains trainer populates weights
- attention_backward_kernel.cu: remove dead per-sample attention_backward_kernel
  and attn_weight_grad_reduce (not loaded by any Rust code since cuBLAS rewrite);
  remove helpers (f32_shfl, f32_block_max/sum_bwd) and defines only used by them;
  update file header to describe current cuBLAS element-wise kernel contents
- c51_loss_kernel.cu: fix stale 'atomicAdd accumulator' comment on q_divergence
  param — it is written by the reduction kernel, not via atomicAdd

Audit (task 4): curiosity_training_kernel.cu uses warp-reduced atomicAdd in
curiosity_forward_backward and curiosity_fused_zero_fwd_bwd_adam. These run
outside CUDA graphs (experience collection between epochs), so atomicAdd is
acceptable; existing DETERMINISM NOTE comments document this accurately.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 08:47:58 +02:00
jgrusewski
5c759aa621 fix: make temporal ops graph-safe — replace raw FFI with captured kernels
mamba2_step: replace memcpy_dtod_async (not captured in CUDA Graph) with
a mamba2_copy_enriched kernel that IS captured — fixes stale data on replay.

predictive_coding_loss: replace cuMemsetD8Async + atomicAdd with per-sample
output + c51_loss_reduce — eliminates both the uncaptured memset and the
non-deterministic atomicAdd, matching the existing loss pipeline pattern.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 08:35:19 +02:00
jgrusewski
18cc9ff5ce fix: skip parent graph composition — launch children individually
cuGraphAddChildGraphNode may invalidate child graph handles on Hopper,
causing individual child launches to hang. Skip compose entirely.
5 cuGraphLaunch calls per step (~10µs overhead).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 08:15:29 +02:00
jgrusewski
defc663f29 fix: launch child graphs individually — parent composition hangs on Hopper
cudaGraphAddChildGraphNode parent replay hangs on sm_90.
Individual child launches (5 per step, ~10µs overhead) work.
Each child is instantiated (cuGraphInstantiateWithFlags) and
launched (cuGraphLaunch) sequentially on the training stream.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 01:43:22 +02:00
jgrusewski
5461915a97 fix: update test assertions for state_dim=65 (42 market + 20 OFI + 3 portfolio)
Tests had hardcoded state_dim=45/53 from before OFI was always enabled.
PPO tests use raw 45-dim data (no OFI), DQN tests use 65-dim.
899 unit tests pass, 20 GPU smoke tests pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 01:27:07 +02:00
jgrusewski
bc4c9f33fc feat: Q-spread opportunity cost — penalizes flat when model predicts edge
Adds opportunity cost to experience_env_step reward: when the model is
flat, subtract |q_gap| * opp_cost_scale from the reward. q_gap is the
model's own conviction signal (max_long_Q - max_short_Q), already
computed by experience_action_select and stored in q_gaps_buf[N].

- experience_kernels.cu: new opp_cost_scale kernel param; apply penalty
  after churn penalty, before plan conviction scaling
- backtest_env_kernel.cu: matching opp_cost_scale param in both kernels;
  set to 0.0 during backtest (no Q-gap available post-hoc)
- DQNHyperparameters: opportunity_cost_scale field, default 0.001
- ExperienceCollectorConfig: opportunity_cost_scale field, wired through
  training_loop.rs; backtest configs default to 0.0

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 01:09:13 +02:00
jgrusewski
108bb63fce feat: cost-driven hold timing — replace min_hold_bars with learned cost signals
Removed: enforce_hold(), min_hold_bars from config/kernels/backtest.
Added: holding_cost_rate (inventory penalty), churn_threshold_bars +
churn_penalty_scale (graduated flip penalty) to reward in
experience_env_step and backtest kernels.

The model learns optimal hold timing from cost signals:
- Per-trade tx cost prevents churning (existing)
- Inventory penalty makes large positions expensive to hold
- Churn penalty graduates cost for rapid flips
- Temporal attention learns when holding cost > expected profit

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 01:04:11 +02:00
jgrusewski
a24fd7c9bd cleanup: remove dead code, aux_frequency, hardcoded dimensions
- iql_value_kernel.cu: remove old per-sample kernels (iql_forward_loss_kernel,
  iql_backward_per_sample, iql_weight_grad_reduce) replaced by cuBLAS path
- gpu_experience_collector.rs: delete _portfolio_dim dead variable
- metrics.rs: replace hardcoded feature_dim=62 with market_dim+OFI_DIM
- config.rs: bars_per_day default 390.0→0.0, add validation at training start
- training_loop.rs: fail fast if bars_per_day==0 (uninitialized)
- common_device_functions.cuh: remove unused PORTFOLIO_DIM define, update comments
  to "42 market + 14 portfolio", keep STATE_DIM (used in TILE_LAYER_WARP_CLEAN)
- experience_kernels.cu: remove unused PORTFOLIO_DIM define
- dqn.rs, config.rs: update stale "42 market + 8 portfolio" comments to 14

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 00:47:34 +02:00
jgrusewski
0f8395450f feat: child graph architecture — 5 composable sub-graphs in single parent launch
Replaces 6 separate CUDA graphs (graph_forward, graph_forward_ddqn,
graph_adam, graph_aux, graph_spectral, graph_mega) with composable
child sub-graphs assembled into a single parent graph.

Architecture:
  parent_graph (single cuGraphLaunch per step)
    ├── spectral_child (spectral norm)
    ├── forward_child (cuBLAS trunk + temporal + ISV + loss + backward)
    ├── ddqn_child (Double DQN Pass 3)
    ├── aux_child (HER + EMA + IQL + IQN + attention + CQL)
    └── adam_child (mamba2 bwd + pruning + grad_norm + adam + ISV update)

Each child captured independently via cudarc begin/end_capture,
composed via cudaGraphAddChildGraphNode with sequential dependencies.
Only parent is instantiated and launched.

Removed: SendSyncGraph, RawCudaGraph, capture_training_graphs,
replay_forward, replay_adam, aux_frequency, all old graph fields.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 00:40:10 +02:00
jgrusewski
74bdc58536 feat: wire temporal pipeline + ISV signal update into training path
Temporal ops (mamba2, predictive coding, regime dropout, ISV temporal
routing, risk budget) now run inside submit_forward_ops_main() as step
1c, captured in the cuBLAS training graph. Previously these only ran in
monitoring via reduce_current_q_stats. Also adds submit_isv_signal_update
wrapper for graph-capturable ISV signal updates.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 00:15:49 +02:00
jgrusewski
01204d471b feat: rewrite IQN head to batched cuBLAS GEMMs
Replace per-sample forward_loss_kernel, backward_kernel, and
weight_grad_reduce_kernel with batched cublasLtMatmul (TF32 FAST_TF32).
Forward/backward matmuls use pre-cached IqnGemmDesc descriptors
(same pattern as CachedGemmDesc in batched_forward/backward).

Element-wise ops (ReLU, sigmoid-hadamard, quantile Huber loss, bias
add/reduce, h_s2 tiling, d_h_s2 reduction) use cubin kernels.

- Constructor: new(stream, config) -> new(shared_handle, config)
- 13 GEMM descriptors: 1 embed fwd, 4 branch fwd, 1 embed dW,
  4 branch dW, 4 branch dX (backward accumulates with beta=1.0)
- 10 new cubin kernels: relu_fwd/bwd, hadamard_sigmoid/bwd,
  quantile_huber_loss, bias_add/grad_reduce, h_s2_tile,
  d_h_s2_reduce, cos_tile
- Zero atomicAdd, fully deterministic, CUDA Graph compatible

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 00:12:07 +02:00
jgrusewski
f388a4a9ce feat: rewrite Attention to batched cuBLAS GEMMs
Replace per-sample CUDA kernels (multihead_feature_attention forward,
attention_backward_kernel + tiled weight_grad_reduce) with 12 cached
cublasLtMatmul descriptors for Q/K/V/O projections.

Forward: 4 cuBLAS GEMMs + bias_add + attn_sdp_fwd cubin + attn_layer_norm_fwd cubin
Backward: 8 cuBLAS GEMMs (4 dW + 4 dX) + attn_sdp_bwd + attn_layer_norm_bwd cubins
         + 4 bias_grad_reduce kernels

Eliminates: d_params_per_sample tiling buffer (was 26MB at B=16384),
per-sample backward kernel, weight_grad_reduce kernel, forward_kernel,
backward_kernel, saved_qkv buffer.

Adds: 15 intermediate D*B buffers for projection/gradient flow, SDP scores,
LayerNorm save state. Constructor takes Arc<SharedCublasHandle> instead of
Arc<CudaStream>. CUBLAS_COMPUTE_32F_FAST_TF32. Zero atomicAdd.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 00:02:34 +02:00
jgrusewski
d77faca885 feat: add Attention cuBLAS element-wise cubin kernels
Add 6 new CUDA kernel functions to attention_backward_kernel.cu for the
batched cuBLAS attention path: attn_sdp_fwd, attn_sdp_bwd (sigmoid-gated
feature attention), attn_layer_norm_fwd, attn_layer_norm_bwd (per-sample
LayerNorm with residual), attn_bias_add, and attn_bias_grad_reduce.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 23:46:25 +02:00
jgrusewski
0e13fd1b82 feat: add IQN cuBLAS element-wise cubin kernels
Append 7 new CUDA kernels to iqn_dual_head_kernel.cu for the batched
cuBLAS IQN rewrite: iqn_hadamard_sigmoid, iqn_relu_fwd, iqn_relu_bwd,
iqn_quantile_huber_loss, iqn_hadamard_sigmoid_bwd, iqn_bias_add,
iqn_bias_grad_reduce.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 23:45:51 +02:00
jgrusewski
d799bfafbe feat: rewrite IQL trainer to batched cuBLAS GEMMs
Replace per-sample CUDA kernels (16,384 launches per GEMM) with batched
cublasLtMatmul — ONE call per GEMM layer. Forward pass uses 3 GEMMs +
SiLU + bias_add + expectile_loss. Backward pass uses 5 GEMMs + SiLU
backward + bias_grad_reduce. Eliminates grads_per_sample buffer (was
27MB), tiled backward loop, and weight_grad_reduce kernel.

Constructor now accepts Arc<SharedCublasHandle> instead of bare stream,
sharing the cuBLAS handle with the trunk forward/backward pipeline.
Eight IqlGemmDesc descriptors are cached at init with heuristic algo
selection for CUDA Graph compatibility.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 23:38:00 +02:00
jgrusewski
196c390946 feat: add IQL cuBLAS element-wise cubin kernels (silu, expectile_loss, bias)
Appends 5 new kernels to iql_value_kernel.cu for the cuBLAS batched GEMM
rewrite: iql_silu_fwd, iql_silu_bwd, iql_expectile_loss, iql_bias_add,
iql_bias_grad_reduce. Zero atomicAdd, fully deterministic, extern "C" for
cubin export.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 23:21:22 +02:00
jgrusewski
b215976a73 fix: disable temporal ops until cuBLAS aux rewrite — corrupts graph_aux
Temporal ops (mamba2, regime_dropout, isv_temporal_route, risk_budget)
between graph_forward and graph_aux replay corrupt graph_aux on Hopper.
ISV signal update + hold enforcement + aux_frequency still active.
Temporal pipeline will be properly addressed in the cuBLAS aux rewrite.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 22:50:23 +02:00
jgrusewski
6252e93bac fix: disable event tracking around temporal ops — prevents graph_aux corruption
Temporal ops between graph_forward and graph_aux replay use shared
buffers (h_s2). cudarc event recording on these buffers corrupts
the graph_aux replay state on Hopper.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 22:44:09 +02:00
jgrusewski
387ce136d7 fix: temporal ops outside graph_forward — ungraphed per-step
Adding mamba2/predictive_coding/regime_dropout/isv_temporal_route/
risk_budget to submit_forward_ops_main broke graph_forward replay
on Hopper (same graph structure issue). Moved to run_full_step
between graph_forward replay and aux ops — ungraphed but still
runs every step, enriching h_s2 before IQL/IQN/attention.

graph_forward keeps the working kernel set (cuBLAS + ISV + plan).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 22:31:22 +02:00
jgrusewski
6d58eaa24e fix: min_hold_bars 10→50 + adaptive hold scales with base
min_hold=10 allowed ~1200 trades/day — costs destroyed the edge.
min_hold=50 (~6.5 min) limits to ~230 trades/day max.

Adaptive extension now scales 0-2× base (was hardcoded 0-8 bars).
With base=50: range is 50-150 bars depending on ISV stability.
Losing positions (negative reward_ema) get base only (50 bars).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 22:20:10 +02:00
jgrusewski
8499b4ee1b feat: wire temporal pipeline + fix hold + add aux_frequency
1. Temporal pipeline in training forward (submit_forward_ops_main):
   - mamba2_step: temporal scan enriches h_s2 with history
   - compute_predictive_coding_loss: temporal smoothness
   - apply_regime_dropout: regime-conditioned dropout
   - launch_isv_temporal_route: per-feature temporal weights
   - risk_budget_forward: risk budget from h_s2
   These were only in the monitoring path (reduce_current_q_stats),
   never in the actual training forward. The model trained without
   any temporal context.

2. ISV signal update after each adam step:
   update_isv_signals() called after mamba2 backward, reads pinned
   loss/grad_norm/Q-mean and updates the 12-element ISV vector.
   Was never called during training — ISV signals stayed at zero.

3. Backtest min_hold fixed:
   eval_min_hold was hardcoded 0 — no hold enforcement in validation.
   Now uses config.min_hold_bars.

4. Backtest ISV signals:
   Passes frozen ISV signals from last training step to validation
   backtest for adaptive hold enforcement.

5. aux_frequency parameter (default 4):
   IQL, IQN, attention, CQL run every 4th step instead of every step.
   ~4x faster epochs. graph_forward still runs every step.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 22:15:57 +02:00
jgrusewski
f9aedb1b05 fix: use split graphs (graph_forward + graph_aux) — graph_mega replay hangs
graph_mega captures spectral+forward+aux in one graph. Replay hangs
on Hopper even with cudarc wrapper. Split graphs work: graph_forward
(from GpuDqnTrainer) + graph_aux (cudarc wrapper). Both graphed,
2 launches per step instead of 1.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 21:15:39 +02:00
jgrusewski
1aadf7c8d3 feat: graph_mega re-enabled via cudarc wrapper — full single-launch pipeline
Rewrote capture_graph_mega to use cudarc's begin_capture/end_capture
instead of raw cuda_sys. Same fix that resolved graph_aux hang.
All graph types (graph_mega, graph_aux, graph_spectral) now use
cudarc wrapper consistently. Falls back to split graphs if mega fails.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 20:56:39 +02:00
jgrusewski
2aa955f0dd feat: log full validation backtest metrics — Sharpe + Sortino + WinRate + MaxDD + Trades + Calmar
compute_validation_loss only returned Sharpe, discarding all other
backtest metrics. Now logs the complete picture on every epoch so we
can verify if the learning system actually works on out-of-sample data.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 20:48:35 +02:00
jgrusewski
30e94446cd fix: compute bars_per_day from fxcache timestamps — correct annualization
bars_per_day was hardcoded 390 (1-minute candles) but we use MBP-10
imbalance bars (~7500/day). All Sharpe/Sortino/return annualization
was off by sqrt(7500/390) ≈ 4.4×.

Now computed from actual fxcache timestamps:
  bars_per_day = total_bars / (trading_days from timestamp span)

Propagates to: val_Sharpe, train_Sharpe, financials, backtest evaluator.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 20:46:04 +02:00
jgrusewski
0c06aeca5a fix: replace raw cuda_sys graph capture with cudarc wrapper
Root cause: capture_graph_aux and capture_graph_spectral used raw
cuda_sys::cuStreamBeginCapture_v2 / cuStreamEndCapture, bypassing
cudarc's internal state tracking. Mixing raw FFI with cudarc's
managed context corrupts the captured graph, causing replay hangs.

capture_training_graphs (GpuDqnTrainer) always used cudarc's
stream.begin_capture() / stream.end_capture() and worked. Now all
graph captures use the same cudarc wrapper.

All graphs re-enabled: graph_forward, graph_forward_ddqn, graph_adam,
graph_spectral, graph_aux. Full graphed pipeline.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 19:37:32 +02:00
jgrusewski
8f2f72430e fix: also skip graph_aux CAPTURE — capture itself corrupts stream state
graph_aux was still being captured (then not replayed). The capture
process uses cuStreamBeginCapture which corrupts cudarc's internal
state, causing the NEXT graph_forward replay to hang on step 2.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 19:25:31 +02:00
jgrusewski
e03da19051 fix: run aux ops ungraphed — graph_aux replay hangs on Hopper
graph_forward replays fine (step 1 completes in 3.8s).
graph_aux replay hangs on step 2. All aux ops work ungraphed
(confirmed by diagnostic run). Keep graph_forward graphed for
speed, run aux ops directly on stream until root cause found.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 19:11:29 +02:00
jgrusewski
92b61c5d96 fix: disable_event_tracking in capture_graph_aux and capture_graph_spectral
Root cause: cudarc's device_ptr() records CudaEvents during graph
capture, silently corrupting the graph. capture_training_graphs
(GpuDqnTrainer) already disabled event tracking, but capture_graph_aux
and capture_graph_spectral (FusedTrainingCtx) did not.

With state_dim=88 this was harmless. With state_dim=96, different
buffer layouts trigger event recording paths in IQL/IQN/attention,
producing a corrupted graph that hangs on replay.

Diagnostic confirmed: all ops complete ungraphed, graph_aux capture
returned CUDA_ERROR_STREAM_CAPTURE_INVALIDATED.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 18:54:33 +02:00
jgrusewski
cb3c282188 diag: sync after every aux op to find exact hanging kernel
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 18:24:32 +02:00
jgrusewski
0fb4c6803f test: run ungraphed to isolate graph vs kernel bug
Skip all CUDA Graph capture — run cuBLAS + kernels directly on stream.
If this works, the hang is graph replay. If not, it's a kernel bug.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 17:14:16 +02:00
jgrusewski
9c6c516d21 Revert "test: revert experience_kernels.cu to working SHA — cubin isolation test (PUSHED)"
This reverts commit 3201123ae3.
2026-04-17 17:05:34 +02:00
jgrusewski
3201123ae3 test: revert experience_kernels.cu to working SHA — cubin isolation test (PUSHED)
If graph_forward works with the working SHA cubin but hangs with
current cubin, nvcc register allocation changes from new/modified
kernels in the same compilation unit affect graph-captured kernels.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 17:03:23 +02:00
jgrusewski
f0ec0a74d1 fix: use CU_STREAM_CAPTURE_MODE_GLOBAL for cuBLAS graph capture on Hopper
NVIDIA docs: cuBLAS with cublasLtMatmul requires GLOBAL capture mode,
not THREAD_LOCAL. THREAD_LOCAL allows cuBLAS internal cudaMallocAsync
to escape the capture scope on sm_90, corrupting the graph.

Also reverts all previous workaround attempts (workspace=0, ldb padding,
bn_concat stride) — the capture mode was the root cause.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 16:48:37 +02:00
jgrusewski
ab8145875c fix: cuBLAS workspace=0 forces graph-safe algorithms on Hopper
Workspace-using cublasLt algorithms on sm_90 employ TMA (Tensor Memory
Accelerator) internally. TMA state is not captured by CUDA Graphs,
causing replay hangs. Setting MAX_WORKSPACE_BYTES=0 in the algorithm
heuristic forces workspace-free algorithms guaranteed graph-compatible.

Applied to all 4 GEMM descriptor creation paths:
- batched_forward.rs: cached + uncached + relu_bias
- batched_backward.rs: cached

Removed ws_size parameter from descriptor creation functions — no
longer needed. ~5-10% GEMM perf cost vs full workspace, negligible
vs total step time.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 16:20:56 +02:00
jgrusewski
3462743c59 fix: disable graph_mega — use split graphs (graph_forward + graph_aux)
graph_mega uses raw cuda_sys FFI for capture which hangs on Hopper
with state_dim=96. Split graphs use cudarc's begin/end_capture which
handles event tracking correctly. 3 launches vs 1 per step — ~2µs
overhead, negligible vs ~160ms step time.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 15:53:53 +02:00
jgrusewski
0c247535b9 fix: pad bn_concat stride to 128 — forces graph-compatible cuBLAS algo on Hopper
state_dim 88→96 changed s1_input_dim (62→70), causing cuBLAS
heuristic to pick a CUDA Graph-incompatible algorithm on sm_90.
Padding bn_concat's leading dimension to 128 (CUTLASS K-tile)
forces tile-aligned algorithms that work in graph replay.

Changes:
- batched_forward.rs: s1_ldb always pad128 when bottleneck active
- gpu_dqn_trainer.rs: bn_concat_buf allocated with padded stride
- dqn_utility_kernels.cu: bn_tanh_concat_kernel takes concat_stride param

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 15:42:56 +02:00
jgrusewski
4483bf0f93 fix: disable event tracking during graph_mega capture — fixes H100 hang
capture_graph_mega was missing disable_event_tracking() that
capture_training_graphs already had. With state_dim=96, cudarc's
device_ptr() calls inside cuBLAS record CudaEvents during graph
capture, which are disallowed and corrupt the graph on Hopper.

Also reverts c51_grad/c51_loss/dqn_utility kernel files to working
SHA — removes all symptom-chasing changes that were red herrings.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 15:25:06 +02:00
jgrusewski
996be07a54 Revert "test: revert experience_kernels.cu to working SHA — cubin isolation test"
This reverts commit 18c0107ce5.
2026-04-17 15:22:49 +02:00
jgrusewski
18c0107ce5 test: revert experience_kernels.cu to working SHA — cubin isolation test
Temporarily reverts ALL experience_kernels.cu changes to match 11b1a1ca9
exactly. If graph_mega works, the cubin-level changes (new plan_noise_inject
kernel + modified experience_state_gather/env_step bodies) are affecting
register allocation for graph_mega kernels on Hopper.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 15:13:15 +02:00