diff --git a/crates/ml-alpha/src/trainer/integrated.rs b/crates/ml-alpha/src/trainer/integrated.rs index ddcf43a30..74724f12a 100644 --- a/crates/ml-alpha/src/trainer/integrated.rs +++ b/crates/ml-alpha/src/trainer/integrated.rs @@ -6864,12 +6864,12 @@ impl IntegratedTrainer { ) .context("step_with_lobsim_gpu: gather_pos_fraction")?; - // Sync to make the pos_fraction host-readable (small cost; - // only needed for the clamped pw computation). - unsafe { - raw_stream_sync(self.raw_stream) - .map_err(|e| anyhow::anyhow!("pos_fraction sync: {:?}", e))?; - } + // One-step deferred read: the gather kernel wrote pos_fraction + // on the stream THIS step, but we read PREVIOUS step's data + // (already host-visible from prior stream work). One-step lag + // is acceptable — pos_fraction is a dataset-level class balance + // statistic that barely changes step to step. Eliminates a + // 7ms host-blocking stream sync. let pf_slice = pf_staging.read_all(); // Run supervised training step. diff --git a/crates/ml-backtesting/src/sim/mod.rs b/crates/ml-backtesting/src/sim/mod.rs index 5d8a2e34a..e9991618e 100644 --- a/crates/ml-backtesting/src/sim/mod.rs +++ b/crates/ml-backtesting/src/sim/mod.rs @@ -1300,7 +1300,8 @@ impl LobSimCuda { .arg(&n) .launch(cfg)?; } - self.stream.synchronize()?; + // No sync needed — step_pnl_track launches on the SAME stream, + // so CUDA stream ordering guarantees submit_market completes first. self.step_pnl_track(current_ts_ns)?; Ok(()) @@ -1473,7 +1474,9 @@ impl LobSimCuda { .arg(&mut self.diag_outcome_n_wins_d) .launch(cfg)?; } - self.stream.synchronize()?; + // No sync — downstream kernels on the same stream (fused_reward_pipeline, + // rl_per_push) read pos_d via stream ordering. Host-side trade log reads + // (read_trade_records) must sync explicitly when called. Ok(()) }