use std::sync::Arc;
use cudarc::driver::CudaStream;
use crate::mamba_ssm::gpu::buffers::{GpuBuffer, WeightSliceDyn};
use crate::mamba_ssm::gpu::context::GpuCtx;
use crate::mamba_ssm::gpu::dtype::WeightDtype;
use crate::mamba3_siso::config::Mamba3Config;
use crate::mamba3_siso::gpu::weights::{GpuMamba3MixedWeights, GpuMamba3Weights};
use crate::mamba3_siso::weights::Mamba3Weights;
pub struct GpuMamba3TrainMixedWeights {
pub master: GpuMamba3Weights,
pub compute: GpuMamba3MixedWeights,
pub dtype: WeightDtype,
}
impl GpuMamba3TrainMixedWeights {
pub fn from_cpu(
stream: &Arc<CudaStream>,
cpu: &Mamba3Weights,
cfg: &Mamba3Config,
input_dim: usize,
dtype: WeightDtype,
) -> Result<Self, String> {
let master = GpuMamba3Weights::from_cpu(stream, cpu, cfg, input_dim)?;
let compute = GpuMamba3MixedWeights::from_cpu(stream, cpu, dtype)?;
Ok(Self {
master,
compute,
dtype,
})
}
pub fn sync_master_to_compute(&self, ctx: &GpuCtx) -> Result<(), String> {
sync_f32(ctx, &self.master.input_proj_b, &self.compute.input_proj_b)?;
for (mw, cw) in self.master.layers.iter().zip(&self.compute.layers) {
sync_f32(ctx, &mw.norm_weight, &cw.norm_weight)?;
sync_f32(ctx, &mw.dt_bias, &cw.dt_bias)?;
sync_f32(ctx, &mw.b_norm_weight, &cw.b_norm_weight)?;
sync_f32(ctx, &mw.c_norm_weight, &cw.c_norm_weight)?;
sync_f32(ctx, &mw.b_bias, &cw.b_bias)?;
sync_f32(ctx, &mw.c_bias, &cw.c_bias)?;
sync_f32(ctx, &mw.d_param, &cw.d_param)?;
sync_f32(ctx, &mw.norm_gate_weight, &cw.norm_gate_weight)?;
}
sync_f32(ctx, &self.master.norm_f_weight, &self.compute.norm_f_weight)?;
Ok(())
}
}
fn sync_f32(ctx: &GpuCtx, master: &GpuBuffer, compute: &WeightSliceDyn) -> Result<(), String> {
let n_elems = master.len();
debug_assert_eq!(n_elems, compute.len_elems());
if n_elems == 0 {
return Ok(());
}
let bytes = n_elems * 4;
let res = unsafe {
cudarc::driver::sys::cuMemcpyDtoDAsync_v2(
compute.ptr(),
master.cached_ptr(),
bytes,
ctx.stream.cu_stream(),
)
};
if res != cudarc::driver::sys::CUresult::CUDA_SUCCESS {
return Err(format!("sync_f32 D2D failed: {res:?}"));
}
Ok(())
}