- Fork cudarc locally (vendor/cudarc): add CudaContext::load_cubin() that calls cuModuleLoadData directly — zero nvrtc dependency - Remove "nvrtc" feature from ml-core, ml-dqn, ml-ppo Cargo.toml - Replace all 89 Ptx::from_binary + load_module calls with load_cubin - ml-core cuda_autograd: wire 9 stub constructors to precompiled cubins (activation, elementwise, linear, loss, reduction, dropout, layer_norm, optimizer) - ml-core build.rs: compile 8 BF16-native CUDA kernels via nvcc - cubin_loader.rs: thin wrapper around CudaContext::load_cubin() - Fix size_of::<f32> in gpu_tensor.rs, stream_ops.rs, layer_norm.rs - Fix test data: Vec<f32> → Vec<half::bf16> for memcpy_htod - Stub ml-ppo/ml-dqn runtime compile_ptx calls (dead code) - backtest_metrics_kernel.cu: full native BF16 rewrite (no float) - backtest_env_kernel.cu: shared memory → __nv_bfloat16 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
46 lines
1.7 KiB
Rust
46 lines
1.7 KiB
Rust
use cudarc::{
|
|
driver::{CudaContext, DriverError, LaunchConfig, PushKernelArg},
|
|
nvrtc::Ptx,
|
|
};
|
|
|
|
fn main() -> Result<(), DriverError> {
|
|
let ctx = CudaContext::new(0)?;
|
|
let stream = ctx.default_stream();
|
|
|
|
let module = ctx.load_module(Ptx::from_file("./examples/sin.ptx"))?;
|
|
let f = module.load_function("sin_kernel")?;
|
|
|
|
let n = 3i32;
|
|
let a_host = [1.0, 2.0, 3.0];
|
|
let a_dev = stream.clone_htod(&a_host)?;
|
|
let mut b_dev = stream.alloc_zeros::<f32>(n as usize)?;
|
|
|
|
// we can safely create a second stream using [CudaStream::fork()].
|
|
// This synchronizes with the source stream, so
|
|
// the `memcpy_vtod` & `alloc_zeros` above will complete **before**
|
|
// work on this stream can start.
|
|
let stream2 = stream.fork()?;
|
|
|
|
// now we launch this work on the other stream
|
|
let mut builder = stream2.launch_builder(&f);
|
|
builder.arg(&mut b_dev); // NOTE: tells cudarc that we are mutating this.
|
|
builder.arg(&a_dev); // NOTE: tells cudarc that we are reading from this slice
|
|
builder.arg(&n);
|
|
unsafe { builder.launch(LaunchConfig::for_num_elems(n as u32)) }?;
|
|
|
|
// cudarc automatically manages multi stream synchronization,
|
|
// so even though we launched the above on a separate stream,
|
|
// doing this device to host transfer will still properly synchronize.
|
|
// a_dev doesn't need to synchronize at all since we specified it is just
|
|
// being read from.
|
|
// b_dev DOES need to be synchronized, because it was mutated on a different stream.
|
|
let a_host_2 = stream.clone_dtoh(&a_dev)?;
|
|
let b_host = stream.clone_dtoh(&b_dev)?;
|
|
|
|
println!("Found {b_host:?}");
|
|
println!("Expected {:?}", a_host.map(f32::sin));
|
|
assert_eq!(&a_host, a_host_2.as_slice());
|
|
|
|
Ok(())
|
|
}
|