use super::transport::{TransportAdmission, TransportKernels, transport_environment_admitted};
use crate::mamba_ssm::gpu::dtype::WeightDtype;
use crate::mamba_ssm::gpu::kernels::{CudaModuleAnchors, HalfKernel, TypedKernel};
use cudarc::driver::{CudaContext, CudaFunction};
use std::sync::Arc;
pub struct Mamba3Kernels {
_modules: CudaModuleAnchors,
compiler_identity: crate::mamba_ssm::gpu::kernel_identity::CompilerIdentity,
artifact_identity: crate::mamba_ssm::gpu::kernel_identity::ArtifactIdentity,
pub module_identity: String,
pub state_cap: usize,
pub(super) transport: TransportKernels,
pub m3_step_fwd: CudaFunction,
pub m3_burnin_fwd: CudaFunction,
pub m3_burnin_fwd_by_state: [(usize, CudaFunction); 4],
pub m3_burnin_fwd_nosave: CudaFunction,
pub m3_backward_seq: CudaFunction,
pub m3_backward_seq_by_state: [(usize, CudaFunction); 4],
pub m3_reduce_d_d: CudaFunction,
pub m3_split: CudaFunction,
pub m3_split_bwd: CudaFunction,
pub bcnorm_bwd: CudaFunction,
pub bc_bias_add: CudaFunction,
pub bc_bias_add_bwd: CudaFunction,
pub m3_angle_dt_fwd_seq: CudaFunction,
pub m3_angle_chunk_sums: CudaFunction,
pub m3_angle_chunk_apply: CudaFunction,
pub m3_angle_dt_bwd_seq: CudaFunction,
pub rope_fwd: CudaFunction,
pub m3_bias_rope_fwd: CudaFunction,
pub rope_bwd: CudaFunction,
pub m3_compute_abg: CudaFunction,
pub m3_abg_bwd: CudaFunction,
pub silu_gate_fwd: CudaFunction,
pub silu_gate_bwd: CudaFunction,
pub rmsnorm_gated_fwd: CudaFunction,
pub rmsnorm_gated_bwd: CudaFunction,
pub rmsnorm_fwd: CudaFunction,
pub rmsnorm_bwd: CudaFunction,
pub colsum_accumulate: CudaFunction,
pub colsum_segments: CudaFunction,
pub reduce_sum_axis0: CudaFunction,
pub vec_add_inplace: CudaFunction,
pub elementwise_mul: CudaFunction,
pub elementwise_mul_v: CudaFunction,
pub fill_scalar: CudaFunction,
pub cast_f32_to_bf16: CudaFunction,
pub cast_f32_to_f16: CudaFunction,
pub cast_bf16_to_f32: CudaFunction,
pub cast_f16_to_f32: CudaFunction,
pub residual_add: CudaFunction,
pub gather_last_timestep: CudaFunction,
pub adamw_step_f32: CudaFunction,
pub adamw_step_f32_capturable: CudaFunction,
pub adamw_step_multi: TypedKernel,
pub m3_preprocess_chunks: CudaFunction,
pub m3_da_cumsum: CudaFunction,
pub m3_chunk_state_fwd: CudaFunction,
pub m3_state_passing_fwd: CudaFunction,
pub m3_chunk_entering_state: CudaFunction,
pub m3_writeback_parallel_states: CudaFunction,
pub m3_chunk_scan_fwd: CudaFunction,
pub m3_chunk_scan_fwd_coop: CudaFunction,
pub m3_extract_da_cs_sum: CudaFunction,
pub m3_dqkv: CudaFunction,
pub m3_dqkv_state_terms_typed: TypedKernel,
pub m3_dstate_passing_bwd: CudaFunction,
pub m3_dqktheta: CudaFunction,
pub m3_ddt_dtrap: CudaFunction,
pub m3_final_grads: CudaFunction,
pub m3_split_typed: TypedKernel,
pub bcnorm_fwd_bc_typed: TypedKernel,
pub bcnorm_fwd_bc_f32: CudaFunction,
pub m3_bias_rope_fwd_typed: TypedKernel,
pub silu_gate_fwd_typed: TypedKernel,
pub silu_gate_bwd_typed: TypedKernel,
pub rmsnorm_gated_fwd_typed: TypedKernel,
pub m3_step_fwd_typed: TypedKernel,
pub m3_burnin_fwd_typed_bf16: CudaFunction,
pub m3_burnin_fwd_typed_f16: CudaFunction,
burnin_fwd_typed_by_state: Option<HalfKernel>,
pub bcnorm_bwd_typed: TypedKernel,
pub bc_bias_add_bwd_typed: TypedKernel,
pub rope_bwd_typed: TypedKernel,
pub m3_split_bwd_typed: TypedKernel,
pub rmsnorm_gated_bwd_typed: TypedKernel,
pub m3_dqkv_typed: TypedKernel,
pub m3_dqktheta_typed: TypedKernel,
pub m3_preprocess_chunks_typed: TypedKernel,
pub m3_chunk_state_fwd_typed: TypedKernel,
pub m3_chunk_pre_state_fused_typed: TypedKernel,
pub m3_writeback_parallel_states_typed: TypedKernel,
pub m3_chunk_scan_fwd_typed: TypedKernel,
pub m3_chunk_scan_fwd_coop_typed: TypedKernel,
pub rmsnorm_fwd_f32in_typed: HalfKernel,
pub residual_add_f32_typed: HalfKernel,
pub gather_last_timestep_typed: TypedKernel,
}
impl Mamba3Kernels {
#[doc(hidden)]
pub fn compiler_identity(&self) -> crate::mamba_ssm::gpu::kernel_identity::CompilerIdentity {
self.compiler_identity
}
#[doc(hidden)]
pub fn artifact_identity(&self) -> crate::mamba_ssm::gpu::kernel_identity::ArtifactIdentity {
self.artifact_identity
}
pub fn compile(ctx: &Arc<CudaContext>, arch: &'static str) -> Result<Self, String> {
Self::compile_with_state_cap(ctx, arch, 64)
}
pub fn backward_seq_for_state(&self, d_state: usize) -> &CudaFunction {
self.m3_backward_seq_by_state
.iter()
.find(|(width, _)| *width == d_state)
.map(|(_, function)| function)
.unwrap_or(&self.m3_backward_seq)
}
pub fn burnin_fwd_for_state(&self, d_state: usize) -> &CudaFunction {
self.m3_burnin_fwd_by_state
.iter()
.find(|(width, _)| *width == d_state)
.map(|(_, function)| function)
.unwrap_or(&self.m3_burnin_fwd)
}
pub fn burnin_fwd_typed_for_state(&self, dtype: WeightDtype, d_state: usize) -> &CudaFunction {
if dtype == WeightDtype::F32 {
return self.burnin_fwd_for_state(d_state);
}
if matches!(d_state, 8 | 16 | 32 | 64)
&& d_state <= self.state_cap
&& let Some(kernels) = &self.burnin_fwd_typed_by_state
{
return kernels.get(dtype);
}
match dtype {
WeightDtype::Bf16 => &self.m3_burnin_fwd_typed_bf16,
WeightDtype::F16 => &self.m3_burnin_fwd_typed_f16,
WeightDtype::F32 | WeightDtype::Tf32 => unreachable!("F32 uses its own selector"),
}
}
pub fn compile_with_state_cap(
ctx: &Arc<CudaContext>,
arch: &'static str,
state_cap: usize,
) -> Result<Self, String> {
let sources = [
include_str!("../../../kernels/_typed_prelude.cuh"),
include_str!("../../../kernels/mamba3_siso.cu"),
include_str!("../../../kernels/mamba3_ops.cu"),
include_str!("../../../kernels/mamba3_chunked.cu"),
include_str!("../../../kernels/norms.cu"),
include_str!("../../../kernels/elementwise.cu"),
include_str!("../../../kernels/adamw.cu"),
];
let combined_body: String = sources
.iter()
.map(|s| {
s.lines()
.filter(|l| !l.trim().starts_with("#include \"_typed_prelude.cuh\""))
.collect::<Vec<_>>()
.join("\n")
})
.collect::<Vec<_>>()
.join("\n");
let combined = combined_body;
let (nv_major, nv_minor) = crate::mamba_ssm::gpu::kernels::nvrtc_version();
let mut option_strings = vec![
"--fmad=true".to_string(),
"--extra-device-vectorization".to_string(),
"-DNDEBUG".to_string(),
format!("-DMAMBA_RS_STATE_CAP={state_cap}"),
];
option_strings.extend(
crate::mamba_ssm::gpu::kernel_identity::deterministic_nvrtc_options(
(nv_major, nv_minor),
"1295203121",
),
);
let include_paths = crate::mamba_ssm::gpu::kernels::cuda_include_paths();
let opts = cudarc::nvrtc::CompileOptions {
arch: Some(arch),
options: option_strings.clone(),
include_paths: include_paths.clone(),
..Default::default()
};
let nvrtc_library_domain = crate::mamba_ssm::gpu::kernel_identity::nvrtc_library_domain();
let header_manifest = crate::mamba_ssm::gpu::kernel_identity::header_manifest(
combined.as_bytes(),
&include_paths,
);
let mut argv = vec![format!("--gpu-architecture={arch}").into_bytes()];
argv.extend(option_strings.iter().map(|value| value.as_bytes().to_vec()));
let key_material = crate::mamba_ssm::gpu::kernel_identity::CompileKeyMaterial {
module_kind: crate::mamba_ssm::gpu::kernel_identity::ModuleKind::Mamba3Combined,
source: combined.as_bytes().to_vec(),
target: arch.as_bytes().to_vec(),
argv,
header_manifest: header_manifest.clone(),
nvrtc_version: (nv_major, nv_minor),
nvrtc_library_domain: nvrtc_library_domain.clone(),
output_kind: crate::mamba_ssm::gpu::kernel_identity::ArtifactKind::Ptx,
composer_revision: crate::mamba_ssm::gpu::kernel_identity::COMPOSER_REVISION,
compiler_revision: crate::mamba_ssm::gpu::kernel_identity::COMPILER_REVISION,
numeric_abi_revision: crate::mamba_ssm::gpu::kernel_identity::NUMERIC_ABI_REVISION,
schedule_revision: crate::mamba_ssm::gpu::kernel_identity::SCHEDULE_REVISION,
};
let invocation_digest = key_material.invocation_digest();
let cache_key = key_material.digest();
let cache_path = cache_key.and_then(|key| {
crate::mamba_ssm::gpu::kernels::kernel_cache_dir().map(|directory| {
directory.join(format!(
"mamba3-kernels-v2-{}.bin",
crate::mamba_ssm::gpu::kernel_identity::digest_hex(&key)
))
})
});
let mut loaded = None;
if let (Some(path), Some(key)) = (&cache_path, cache_key)
&& let Some(hit) = crate::mamba_ssm::gpu::kernel_identity::read_cache(
path,
key,
crate::mamba_ssm::gpu::kernel_identity::ArtifactKind::Ptx,
)
&& let Ok(source) =
crate::mamba_ssm::gpu::kernel_identity::canonical_ptx_from_cache(hit.payload)
&& let Ok(module) = ctx.load_module(cudarc::nvrtc::Ptx::from_src(source))
&& crate::mamba_ssm::gpu::kernel_identity::cache_hit_header_closure_is_current(
combined.as_bytes(),
&include_paths,
&header_manifest,
)
&& nvrtc_library_domain.as_deref().is_some_and(
crate::mamba_ssm::gpu::kernel_identity::nvrtc_library_domain_is_current,
)
{
loaded = Some((module, hit.artifact_digest));
}
let (module, artifact_digest) = match loaded {
Some(value) => value,
None => {
let ptx = cudarc::nvrtc::compile_ptx_with_opts(&combined, opts).map_err(|e| {
format!(
"NVRTC M3 compile failed: {}",
format!("{e:?}").replace("\\n", "\n")
)
})?;
let ptx_image = ptx
.as_bytes()
.ok_or_else(|| "NVRTC returned M3 PTX without a raw image".to_string())?;
let ptx_source =
crate::mamba_ssm::gpu::kernel_identity::canonical_ptx_image(ptx_image)?;
if !crate::mamba_ssm::gpu::kernel_identity::header_manifest_is_current(
combined.as_bytes(),
&include_paths,
&header_manifest,
) {
return Err(
"CUDA headers changed during M3 NVRTC compilation; retry initialization"
.into(),
);
}
if let Some(domain) = nvrtc_library_domain.as_deref()
&& !crate::mamba_ssm::gpu::kernel_identity::nvrtc_library_domain_is_current(
domain,
)
{
return Err(
"NVRTC libraries changed during M3 compilation; retry initialization"
.into(),
);
}
let artifact_digest = crate::mamba_ssm::gpu::kernel_identity::FramedSha256::bytes(
ptx_source.as_bytes(),
);
if let (Some(path), Some(key)) = (&cache_path, cache_key) {
crate::mamba_ssm::gpu::kernel_identity::publish_cache(
path,
key,
crate::mamba_ssm::gpu::kernel_identity::ArtifactKind::Ptx,
ptx_source.as_bytes(),
);
}
let module = ctx
.load_module(cudarc::nvrtc::Ptx::from_src(ptx_source))
.map_err(|e| format!("M3 module load failed: {e:?}"))?;
(module, artifact_digest)
}
};
let compiler_identity = crate::mamba_ssm::gpu::kernel_identity::CompilerIdentity {
source_digest: crate::mamba_ssm::gpu::kernel_identity::FramedSha256::bytes(
combined.as_bytes(),
),
invocation_digest,
header_manifest_digest: crate::mamba_ssm::gpu::kernel_identity::FramedSha256::new(
b"cuda-header-manifest.v1",
)
.optional(b"manifest", header_manifest.as_deref())
.finish(),
target: crate::mamba_ssm::gpu::kernel_identity::CudaTarget::new(arch)?,
nvrtc_version: (nv_major, nv_minor),
nvrtc_library_domain: crate::mamba_ssm::gpu::kernel_identity::FramedSha256::new(
b"nvrtc-library-set-identity.v2",
)
.optional(b"domain", nvrtc_library_domain.as_deref())
.finish(),
nvrtc_library_known: nvrtc_library_domain.is_some(),
output_kind: crate::mamba_ssm::gpu::kernel_identity::ArtifactKind::Ptx,
composer_revision: crate::mamba_ssm::gpu::kernel_identity::COMPOSER_REVISION,
compiler_revision: crate::mamba_ssm::gpu::kernel_identity::COMPILER_REVISION,
numeric_abi_revision: crate::mamba_ssm::gpu::kernel_identity::NUMERIC_ABI_REVISION,
schedule_revision: crate::mamba_ssm::gpu::kernel_identity::SCHEDULE_REVISION,
};
let artifact_identity = crate::mamba_ssm::gpu::kernel_identity::ArtifactIdentity {
module_kind: crate::mamba_ssm::gpu::kernel_identity::ModuleKind::Mamba3Combined,
artifact_kind: crate::mamba_ssm::gpu::kernel_identity::ArtifactKind::Ptx,
compile_key: invocation_digest,
artifact_digest,
};
let module_identity =
crate::mamba_ssm::gpu::kernel_identity::digest_hex(&invocation_digest);
let get = |name: &str| -> Result<CudaFunction, String> {
module
.load_function(name)
.map_err(|e| format!("M3 kernel '{name}' not found: {e:?}"))
};
let actual_device = ctx
.compute_capability()
.map_err(|error| format!("M3 device capability: {error:?}"))?;
let transport_admission = TransportAdmission::new(
transport_environment_admitted(actual_device, arch, (nv_major, nv_minor)),
state_cap,
);
let transport = TransportKernels::load(transport_admission, get)?;
let burnin_fwd_typed_by_state = if actual_device == (8, 9)
&& matches!(arch, "sm_89" | "compute_89")
&& matches!((nv_major, nv_minor), (12, 8) | (13, 0) | (13, 2))
&& matches!(state_cap, 16 | 32 | 64)
{
Some(HalfKernel {
bf16: get("m3_burnin_fwd_bf16_by_state")?,
f16: get("m3_burnin_fwd_f16_by_state")?,
})
} else {
None
};
let kernels = Self {
transport,
burnin_fwd_typed_by_state,
module_identity,
state_cap,
compiler_identity,
artifact_identity,
m3_step_fwd: get("m3_step_fwd")?,
m3_burnin_fwd: get("m3_burnin_fwd")?,
m3_burnin_fwd_by_state: [
(8, get("m3_burnin_fwd_ds8")?),
(16, get("m3_burnin_fwd_ds16")?),
(32, get("m3_burnin_fwd_ds32")?),
(64, get("m3_burnin_fwd_ds64")?),
],
m3_burnin_fwd_nosave: get("m3_burnin_fwd_nosave")?,
m3_backward_seq: get("m3_backward_seq")?,
m3_backward_seq_by_state: [
(8, get("m3_backward_seq_ds8")?),
(16, get("m3_backward_seq_ds16")?),
(32, get("m3_backward_seq_ds32")?),
(64, get("m3_backward_seq_ds64")?),
],
m3_reduce_d_d: get("m3_reduce_d_D")?,
m3_split: get("m3_split")?,
m3_split_bwd: get("m3_split_bwd")?,
bcnorm_bwd: get("bcnorm_bwd")?,
bc_bias_add: get("bc_bias_add")?,
bc_bias_add_bwd: get("bc_bias_add_bwd")?,
m3_angle_dt_fwd_seq: get("m3_angle_dt_fwd_seq")?,
m3_angle_chunk_sums: get("m3_angle_chunk_sums")?,
m3_angle_chunk_apply: get("m3_angle_chunk_apply")?,
m3_angle_dt_bwd_seq: get("m3_angle_dt_bwd_seq")?,
rope_fwd: get("rope_fwd")?,
m3_bias_rope_fwd: get("m3_bias_rope_fwd")?,
rope_bwd: get("rope_bwd")?,
m3_compute_abg: get("m3_compute_abg")?,
m3_abg_bwd: get("m3_abg_bwd")?,
silu_gate_fwd: get("silu_gate_fwd")?,
silu_gate_bwd: get("silu_gate_bwd")?,
rmsnorm_gated_fwd: get("rmsnorm_gated_forward")?,
rmsnorm_gated_bwd: get("rmsnorm_gated_backward")?,
rmsnorm_fwd: get("rmsnorm_forward")?,
rmsnorm_bwd: get("rmsnorm_backward")?,
colsum_accumulate: get("colsum_accumulate")?,
colsum_segments: get("colsum_segments")?,
reduce_sum_axis0: get("reduce_sum_axis0")?,
vec_add_inplace: get("vec_add_inplace")?,
elementwise_mul: get("elementwise_mul")?,
elementwise_mul_v: get("elementwise_mul_v_f32")?,
fill_scalar: get("fill_scalar")?,
cast_f32_to_bf16: get("cast_f32_to_bf16")?,
cast_f32_to_f16: get("cast_f32_to_f16")?,
cast_bf16_to_f32: get("cast_bf16_to_f32")?,
cast_f16_to_f32: get("cast_f16_to_f32")?,
residual_add: get("residual_add")?,
gather_last_timestep: get("gather_last_timestep")?,
adamw_step_f32: get("adamw_step_f32")?,
adamw_step_f32_capturable: get("adamw_step_f32_capturable")?,
adamw_step_multi: TypedKernel {
f32: get("adamw_step_multi_f32")?,
bf16: get("adamw_step_multi_bf16")?,
f16: get("adamw_step_multi_f16")?,
},
m3_preprocess_chunks: get("m3_preprocess_chunks")?,
m3_da_cumsum: get("m3_dA_cumsum")?,
m3_chunk_state_fwd: get("m3_chunk_state_fwd")?,
m3_state_passing_fwd: get("m3_state_passing_fwd")?,
m3_chunk_entering_state: get("m3_chunk_entering_state")?,
m3_writeback_parallel_states: get("m3_writeback_parallel_states")?,
m3_chunk_scan_fwd: get("m3_chunk_scan_fwd")?,
m3_chunk_scan_fwd_coop: get("m3_chunk_scan_fwd_coop")?,
m3_extract_da_cs_sum: get("m3_extract_da_cs_sum")?,
m3_dqkv: get("m3_dqkv")?,
m3_dqkv_state_terms_typed: TypedKernel {
f32: get("m3_dqkv_state_terms")?,
bf16: get("m3_dqkv_state_terms_bf16")?,
f16: get("m3_dqkv_state_terms_f16")?,
},
m3_dstate_passing_bwd: get("m3_dstate_passing_bwd")?,
m3_dqktheta: get("m3_dqktheta")?,
m3_ddt_dtrap: get("m3_ddt_dtrap")?,
m3_final_grads: get("m3_final_grads")?,
m3_split_typed: TypedKernel {
f32: get("m3_split")?,
bf16: get("m3_split_bf16")?,
f16: get("m3_split_f16")?,
},
bcnorm_fwd_bc_typed: TypedKernel {
f32: get("bcnorm_fwd_bc_f32")?,
bf16: get("bcnorm_fwd_bc_bf16")?,
f16: get("bcnorm_fwd_bc_f16")?,
},
bcnorm_fwd_bc_f32: get("bcnorm_fwd_bc_f32")?,
m3_bias_rope_fwd_typed: TypedKernel {
f32: get("m3_bias_rope_fwd")?,
bf16: get("m3_bias_rope_fwd_bf16")?,
f16: get("m3_bias_rope_fwd_f16")?,
},
silu_gate_fwd_typed: TypedKernel {
f32: get("silu_gate_fwd")?,
bf16: get("silu_gate_fwd_bf16")?,
f16: get("silu_gate_fwd_f16")?,
},
silu_gate_bwd_typed: TypedKernel {
f32: get("silu_gate_bwd")?,
bf16: get("silu_gate_bwd_bf16")?,
f16: get("silu_gate_bwd_f16")?,
},
rmsnorm_gated_fwd_typed: TypedKernel {
f32: get("rmsnorm_gated_forward")?,
bf16: get("rmsnorm_gated_forward_bf16")?,
f16: get("rmsnorm_gated_forward_f16")?,
},
m3_step_fwd_typed: TypedKernel {
f32: get("m3_step_fwd")?,
bf16: get("m3_step_fwd_bf16")?,
f16: get("m3_step_fwd_f16")?,
},
m3_burnin_fwd_typed_bf16: get("m3_burnin_fwd_bf16")?,
m3_burnin_fwd_typed_f16: get("m3_burnin_fwd_f16")?,
bcnorm_bwd_typed: TypedKernel {
f32: get("bcnorm_bwd")?,
bf16: get("bcnorm_bwd_bf16")?,
f16: get("bcnorm_bwd_f16")?,
},
bc_bias_add_bwd_typed: TypedKernel {
f32: get("bc_bias_add_bwd")?,
bf16: get("bc_bias_add_bwd_bf16")?,
f16: get("bc_bias_add_bwd_f16")?,
},
rope_bwd_typed: TypedKernel {
f32: get("rope_bwd")?,
bf16: get("rope_bwd_bf16")?,
f16: get("rope_bwd_f16")?,
},
m3_split_bwd_typed: TypedKernel {
f32: get("m3_split_bwd")?,
bf16: get("m3_split_bwd_bf16")?,
f16: get("m3_split_bwd_f16")?,
},
rmsnorm_gated_bwd_typed: TypedKernel {
f32: get("rmsnorm_gated_backward")?,
bf16: get("rmsnorm_gated_backward_bf16")?,
f16: get("rmsnorm_gated_backward_f16")?,
},
m3_dqkv_typed: TypedKernel {
f32: get("m3_dqkv")?,
bf16: get("m3_dqkv_bf16")?,
f16: get("m3_dqkv_f16")?,
},
m3_dqktheta_typed: TypedKernel {
f32: get("m3_dqktheta")?,
bf16: get("m3_dqktheta_bf16")?,
f16: get("m3_dqktheta_f16")?,
},
m3_preprocess_chunks_typed: TypedKernel {
f32: get("m3_preprocess_chunks")?,
bf16: get("m3_preprocess_chunks_bf16")?,
f16: get("m3_preprocess_chunks_f16")?,
},
m3_chunk_state_fwd_typed: TypedKernel {
f32: get("m3_chunk_state_fwd")?,
bf16: get("m3_chunk_state_fwd_bf16")?,
f16: get("m3_chunk_state_fwd_f16")?,
},
m3_chunk_pre_state_fused_typed: TypedKernel {
f32: get("m3_chunk_pre_state_fused")?,
bf16: get("m3_chunk_pre_state_fused_bf16")?,
f16: get("m3_chunk_pre_state_fused_f16")?,
},
m3_writeback_parallel_states_typed: TypedKernel {
f32: get("m3_writeback_parallel_states")?,
bf16: get("m3_writeback_parallel_states_bf16")?,
f16: get("m3_writeback_parallel_states_f16")?,
},
m3_chunk_scan_fwd_coop_typed: TypedKernel {
f32: get("m3_chunk_scan_fwd_coop")?,
bf16: get("m3_chunk_scan_fwd_coop_bf16")?,
f16: get("m3_chunk_scan_fwd_coop_f16")?,
},
m3_chunk_scan_fwd_typed: TypedKernel {
f32: get("m3_chunk_scan_fwd")?,
bf16: get("m3_chunk_scan_fwd_bf16")?,
f16: get("m3_chunk_scan_fwd_f16")?,
},
rmsnorm_fwd_f32in_typed: HalfKernel {
bf16: get("rmsnorm_forward_f32in_bf16")?,
f16: get("rmsnorm_forward_f32in_f16")?,
},
residual_add_f32_typed: HalfKernel {
bf16: get("residual_add_f32_bf16")?,
f16: get("residual_add_f32_f16")?,
},
gather_last_timestep_typed: TypedKernel {
f32: get("gather_last_timestep_f32")?,
bf16: get("gather_last_timestep_bf16")?,
f16: get("gather_last_timestep_f16")?,
},
_modules: CudaModuleAnchors::new(vec![module]),
};
{
use cudarc::driver::sys::CUfunction_attribute_enum as FnAttr;
let budget: i32 = 99 * 1024;
for f in [
&kernels.m3_dqkv,
&kernels.m3_dqkv_typed.f32,
&kernels.m3_dqkv_typed.bf16,
&kernels.m3_dqkv_typed.f16,
] {
let _ = f.set_attribute(
FnAttr::CU_FUNC_ATTRIBUTE_MAX_DYNAMIC_SHARED_SIZE_BYTES,
budget,
);
}
if let Some(transport) = &kernels.transport.dqkv {
for f in [&transport.f32, &transport.bf16, &transport.f16] {
let _ = f.set_attribute(
FnAttr::CU_FUNC_ATTRIBUTE_MAX_DYNAMIC_SHARED_SIZE_BYTES,
budget,
);
}
}
}
Ok(kernels)
}
pub(crate) fn module_anchors(&self) -> CudaModuleAnchors {
self._modules.clone()
}
}
pub fn bcnorm_fwd_bc_cfg(rows: usize, d_state: usize) -> cudarc::driver::LaunchConfig {
assert!(rows > 0 && d_state > 0);
if d_state <= 32 {
let width = d_state.next_power_of_two();
let threads = if rows < 128 { 32 } else { 256 };
let rows_per_block = threads / width;
cudarc::driver::LaunchConfig {
grid_dim: (rows.div_ceil(rows_per_block) as u32, 2, 1),
block_dim: (width as u32, rows_per_block as u32, 1),
shared_mem_bytes: 0,
}
} else {
cudarc::driver::LaunchConfig {
grid_dim: (rows as u32, 2, 1),
block_dim: (d_state as u32, 1, 1),
shared_mem_bytes: (d_state * 4) as u32,
}
}
}
pub fn chunk_state_cfg(
batch: usize,
n_chunks: usize,
nh: usize,
hd: usize,
ds: usize,
chunk_size: usize,
) -> cudarc::driver::LaunchConfig {
let heads = 2usize;
let smem_bytes = heads * (chunk_size * hd + chunk_size * ds + chunk_size) * 4;
if ds.is_multiple_of(4) && hd * (ds / 4) * heads <= 1024 && smem_bytes <= 48 * 1024 {
cudarc::driver::LaunchConfig {
grid_dim: ((batch * n_chunks) as u32, nh.div_ceil(heads) as u32, 1),
block_dim: (hd as u32, (ds / 4) as u32, heads as u32),
shared_mem_bytes: smem_bytes as u32,
}
} else {
cudarc::driver::LaunchConfig {
grid_dim: ((batch * n_chunks) as u32, nh.div_ceil(2) as u32, 1),
block_dim: (hd as u32, 2, 1),
shared_mem_bytes: 0,
}
}
}
pub fn chunk_fused_cfg(
batch: usize,
n_chunks: usize,
nh: usize,
hd: usize,
ds: usize,
chunk_size: usize,
) -> Option<cudarc::driver::LaunchConfig> {
let smem_bytes = (chunk_size * (ds + 4) + chunk_size * hd + chunk_size) * 4;
if !ds.is_multiple_of(4) || chunk_size > 1024 || smem_bytes > 48 * 1024 {
return None;
}
Some(cudarc::driver::LaunchConfig {
grid_dim: ((batch * n_chunks) as u32, nh as u32, 1),
block_dim: (chunk_size as u32, 1, 1),
shared_mem_bytes: smem_bytes as u32,
})
}
pub fn chunk_scan_cfg(
batch: usize,
n_chunks: usize,
nh: usize,
hd: usize,
ds: usize,
chunk_size: usize,
) -> (bool, cudarc::driver::LaunchConfig) {
let smem_floats = chunk_size * (chunk_size - 1) / 2
+ 2 * chunk_size * (ds + 4)
+ chunk_size * hd
+ hd * (ds + 4)
+ 2 * chunk_size;
let smem_bytes = smem_floats * std::mem::size_of::<f32>();
if chunk_size <= 64 && smem_bytes <= 48 * 1024 {
(
true,
cudarc::driver::LaunchConfig {
grid_dim: ((batch * n_chunks) as u32, nh as u32, 1),
block_dim: (256, 1, 1),
shared_mem_bytes: smem_bytes as u32,
},
)
} else {
(
false,
cudarc::driver::LaunchConfig {
grid_dim: ((batch * n_chunks) as u32, nh.div_ceil(2) as u32, 1),
block_dim: (hd as u32, 2, 1),
shared_mem_bytes: 0,
},
)
}
}