perf(htod): migrate PPO trainer + hyperopt adapters to mapped-pinned (6 sites)

- trainers/ppo.rs: 2 sites (features, targets in set_raw_market_data)
- hyperopt/adapters/ppo.rs: 3 sites (features, targets in upload path;
  action_indices in run_gpu_backtest forward closure)
- hyperopt/adapters/mamba2.rs: 1 site (gpu_to_stream)

All clone_htod_f32 and bare stream.clone_htod calls rewritten to
mapped_pinned::clone_to_device_{f32,i32}_via_pinned.

Audit row appended (Fix 7) in docs/dqn-gpu-hot-path-audit.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2026-04-28 20:58:48 +02:00
parent d9fe85ac6b
commit ae4ece7805
4 changed files with 16 additions and 11 deletions

View File

@@ -745,7 +745,8 @@ fn gpu_to_stream(
stream: &Arc<cudarc::driver::CudaStream>,
) -> Result<StreamTensor, MLError> {
let host = t.to_host(stream)?;
let data = crate::cuda_pipeline::clone_htod_f32(stream, &host)?;
let data = crate::cuda_pipeline::mapped_pinned::clone_to_device_f32_via_pinned(stream, &host)
.map_err(|e| MLError::ModelError(format!("gpu_to_stream upload via pinned: {e}")))?;
Ok(StreamTensor {
data,
shape: t.shape().to_vec(), // cpu-side shape clone

View File

@@ -580,14 +580,14 @@ impl PPOTrainer {
for (features, _) in training_data {
flat_features.extend_from_slice(features);
}
match crate::cuda_pipeline::clone_htod_f32(&stream, &flat_features) {
match crate::cuda_pipeline::mapped_pinned::clone_to_device_f32_via_pinned(&stream, &flat_features) {
Ok(buf) => {
info!("PPO CUDA features uploaded: {} bars × 42 ({:.1} MB)",
num_bars, (num_bars * 42 * 4) as f64 / 1_048_576.0);
self.features_cuda = Some(buf);
}
Err(e) => {
return Err(MLError::TrainingError(format!("PPO CUDA features upload FAILED (no CPU fallback): {e}")));
return Err(MLError::TrainingError(format!("PPO CUDA features upload via pinned FAILED (no CPU fallback): {e}")));
}
}
@@ -604,7 +604,7 @@ impl PPOTrainer {
flat_targets.push(close);
flat_targets.push(next_close);
}
match crate::cuda_pipeline::clone_htod_f32(&stream, &flat_targets) {
match crate::cuda_pipeline::mapped_pinned::clone_to_device_f32_via_pinned(&stream, &flat_targets) {
Ok(buf) => {
info!("PPO CUDA targets uploaded: {} bars × 4 ({:.1} MB)",
num_bars, (num_bars * 4 * 4) as f64 / 1_048_576.0);
@@ -612,7 +612,7 @@ impl PPOTrainer {
}
Err(e) => {
self.features_cuda = None;
return Err(MLError::TrainingError(format!("PPO CUDA targets upload FAILED (no CPU fallback): {e}")));
return Err(MLError::TrainingError(format!("PPO CUDA targets upload via pinned FAILED (no CPU fallback): {e}")));
}
}
@@ -1326,10 +1326,9 @@ impl PPOTrainer {
}
}
// Upload action indices to GPU
stream.clone_htod(&action_indices).map_err(|e| {
MLError::ModelError(format!("PPO backtest action upload: {e}"))
})
// Upload action indices to GPU via mapped-pinned staging (no explicit HtoD)
crate::cuda_pipeline::mapped_pinned::clone_to_device_i32_via_pinned(stream, &action_indices)
.map_err(|e| MLError::ModelError(format!("PPO backtest action upload via pinned: {e}")))
},
24, // portfolio_dim: 8 portfolio + 16 multi-timeframe (matches training state layout)
)?;

View File

@@ -395,7 +395,8 @@ impl PpoTrainer {
flat_features.push(v as f32);
}
}
let features_buf = crate::cuda_pipeline::clone_htod_f32(&stream, &flat_features)?;
let features_buf = crate::cuda_pipeline::mapped_pinned::clone_to_device_f32_via_pinned(&stream, &flat_features)
.map_err(|e| MLError::ModelError(format!("PPO features upload via pinned: {e}")))?;
self.features_raw_cuda = Some(features_buf);
// Upload targets [num_bars * 4]
@@ -405,7 +406,8 @@ impl PpoTrainer {
flat_targets.push(targets.get(i).copied().unwrap_or(0.0) as f32);
}
}
let targets_buf = crate::cuda_pipeline::clone_htod_f32(&stream, &flat_targets)?;
let targets_buf = crate::cuda_pipeline::mapped_pinned::clone_to_device_f32_via_pinned(&stream, &flat_targets)
.map_err(|e| MLError::ModelError(format!("PPO targets upload via pinned: {e}")))?;
self.targets_raw_cuda = Some(targets_buf);
self.raw_data_num_bars = num_bars;

View File

@@ -103,3 +103,6 @@
### Fix 6 — Migrate `gpu_walk_forward.rs` to mapped-pinned (3 sites)
`gpu_walk_forward.rs`: 3 `clone_htod_f32` calls in the walk-forward GPU data upload (features, targets, OFI) rewritten to `mapped_pinned::clone_to_device_f32_via_pinned`.
### Fix 7 — Migrate PPO trainer + hyperopt adapters to mapped-pinned (6 sites)
`trainers/ppo.rs` (2 sites: features, targets in `set_raw_market_data`), `hyperopt/adapters/ppo.rs` (3 sites: features, targets in upload path; action_indices in backtest forward closure), `hyperopt/adapters/mamba2.rs` (1 site: `gpu_to_stream`). All `clone_htod_f32` and bare `stream.clone_htod` calls rewritten to `mapped_pinned::clone_to_device_{f32,i32}_via_pinned`.