CI / Build (ubuntu-latest) (push) Failing after 8s
Performance Benchmarks / Run Benchmarks (push) Successful in 8s
CI / Clippy Check (push) Failing after 8s
CI / Build CPU-Only (Explicit) (push) Failing after 8s
Documentation / Build API Documentation (push) Failing after 7s
CI / Format Check (push) Failing after 9s
GPU Tests / Check GPU Availability (push) Successful in 0s
Documentation / Build User Guide (push) Successful in 7s
GPU Tests / CUDA Tests (11.8) (push) Has been skipped
GPU Tests / CUDA Tests (12.1) (push) Has been skipped
CI / Build (macos-latest) (push) Failing after 14s
CI / Test (macos-latest) (push) Has been skipped
CI / Test (ubuntu-latest) (push) Has been skipped
CI / Python Bindings (maturin) (macos-latest) (push) Has been skipped
CI / Python Bindings (maturin) (ubuntu-latest) (push) Has been skipped
CI / WASM Build + Size Check (push) Has been skipped
CI / Distributed Training Tests (push) Has been skipped
CI / CI Success (push) Failing after 0s
GPU Tests / Metal Tests (push) Has been skipped
FP8 GPU FFI (rtx-tensor) - `fp8_cast.rs`: replaced `not_implemented` stubs with real cudarc 0.18.2 PTX launches; `cast_bf16_to_fp8_e4m3` and `cast_fp8_e4m3_to_bf16` now dispatch to NVCC-compiled `fp8_cast.ptx` via `LazyLock` module cache, matching the `inplace_ops` pattern - `build.rs`: `create_dummy_ptx` now emits `fp8_cast.ptx` alongside `element_wise.ptx` so `include_str!` resolves cleanly when NVCC is absent FlashAttention-3 typed kernel launch (rtx-flash-attention) - `flash_v3_forward.rs`: `forward()` now takes typed `CudaSlice<bf16>` Q/K/V/O + `CudaSlice<f32>` LSE buffer; dispatches via `stream.launch_builder` with block_dim=(128,1,1), grid_dim=(ceil(seq_len/64), batch*heads, 1), shared_mem_bytes=0 (PTX metadata-resolved) - `simple.rs`: added `has_flash_v3()` + `flash_attention_v3_forward_raw()` dispatch - `Cargo.toml`: `half` added as optional cuda-gated dependency CUDA Graphs stream threading (rtx-transformers) - `training_loop.rs`: added `cuda_stream: Option<CudaStreamHandle>` field; `set_cuda_backend()` now creates a non-default capture stream; capture step calls real `begin_capture(stream)` + `end_capture(stream)`; added `set_cuda_stream()` override; replay unchanged (no stream needed) SnapKV + prefix cache BatchScheduler wiring (rtx-inference) - `scheduler.rs`: added `prefix_hit_pages: Option<Vec<PageId>>` + `evicted_positions: Vec<usize>` to `SchedulerRequest`; `BatchScheduler` gains `kv_cache` + `snapkv_eviction` fields; `submit_request` does non-blocking `try_lock` prefix lookup; added `notify_prefill_complete` (registers prefix + runs `select_evict_positions`), `set_kv_cache`, `set_snapkv_eviction`, `get_evicted_positions`, `get_prefix_hit_pages` — +5 new integration tests Test results: 22 + 42 + 75 + 102 = 241 tests, 0 failures Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
220 lines
7.0 KiB
Rust
220 lines
7.0 KiB
Rust
//! Build script for RTX-Tensor CUDA kernels
|
|
//!
|
|
//! Compiles CUDA kernels to PTX and embeds them in the binary
|
|
//! for runtime kernel loading and execution.
|
|
|
|
#[allow(unused_imports)]
|
|
use std::env;
|
|
#[allow(unused_imports)]
|
|
use std::fs;
|
|
#[allow(unused_imports)]
|
|
use std::path::Path;
|
|
#[allow(unused_imports)]
|
|
use std::process::Command;
|
|
|
|
fn main() {
|
|
// Only link OpenBLAS if the feature is enabled
|
|
#[cfg(feature = "openblas")]
|
|
{
|
|
// Force proper OpenBLAS linking configuration
|
|
// The openblas-src crate builds the library but linking may fail
|
|
// We need to explicitly tell the linker where to find it
|
|
|
|
// Get the OpenBLAS library path from the build output
|
|
if let Ok(out_dir) = env::var("DEP_OPENBLAS_LIB") {
|
|
println!("cargo:rustc-link-search=native={out_dir}");
|
|
println!("cargo:rustc-link-lib=static=openblas");
|
|
} else {
|
|
// Fallback: let openblas-src handle linking automatically
|
|
println!("cargo:rustc-link-lib=openblas");
|
|
}
|
|
|
|
// Ensure CBLAS symbols are available
|
|
println!("cargo:rustc-link-lib=gfortran"); // OpenBLAS may need Fortran runtime
|
|
}
|
|
|
|
// Only compile CUDA kernels if CUDA feature is enabled
|
|
#[cfg(feature = "cuda")]
|
|
compile_cuda_kernels();
|
|
|
|
// Link cuSPARSELt if the feature is enabled
|
|
#[cfg(feature = "cusparselt_link")]
|
|
link_cusparselt();
|
|
}
|
|
|
|
/// Configure cuSPARSELt library linking
|
|
#[cfg(feature = "cusparselt_link")]
|
|
fn link_cusparselt() {
|
|
// Check common paths for libcusparseLt
|
|
let lib_paths = [
|
|
"/usr/lib/x86_64-linux-gnu/libcusparseLt/13",
|
|
"/usr/lib/x86_64-linux-gnu",
|
|
"/usr/local/cuda/lib64",
|
|
"/usr/local/cuda-13.0/lib64",
|
|
"/usr/local/cuda-13.1/lib64",
|
|
];
|
|
|
|
let mut found = false;
|
|
for path in lib_paths {
|
|
let lib_path = Path::new(path);
|
|
if lib_path.join("libcusparseLt.so").exists() {
|
|
println!("cargo:rustc-link-search=native={}", path);
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Also check CUSPARSELT_PATH environment variable
|
|
if !found {
|
|
if let Ok(path) = env::var("CUSPARSELT_PATH") {
|
|
println!("cargo:rustc-link-search=native={}", path);
|
|
found = true;
|
|
}
|
|
}
|
|
|
|
// Also check LD_LIBRARY_PATH
|
|
if !found {
|
|
if let Ok(ld_path) = env::var("LD_LIBRARY_PATH") {
|
|
for dir in ld_path.split(':') {
|
|
if Path::new(dir).join("libcusparseLt.so").exists() {
|
|
println!("cargo:rustc-link-search=native={}", dir);
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if found {
|
|
println!("cargo:rustc-link-lib=dylib=cusparseLt");
|
|
println!("cargo:warning=cuSPARSELt library found and linked for 2:4 sparsity acceleration");
|
|
} else {
|
|
println!("cargo:warning=cuSPARSELt library not found - 2:4 sparsity will fall back to CPU");
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "cuda")]
|
|
fn compile_cuda_kernels() {
|
|
let out_dir = env::var("OUT_DIR").unwrap();
|
|
let cuda_kernels_dir = Path::new("src/cuda_kernels");
|
|
|
|
println!("cargo:rerun-if-changed=src/cuda_kernels/element_wise.cu");
|
|
println!("cargo:rerun-if-changed=src/cuda_kernels/fp8_cast.cu");
|
|
|
|
// Check if NVCC is available
|
|
if !is_nvcc_available() {
|
|
println!("cargo:warning=NVCC not found - CUDA kernels will not be compiled");
|
|
println!("cargo:warning=GPU acceleration will not be available");
|
|
create_dummy_ptx(&out_dir);
|
|
return;
|
|
}
|
|
|
|
println!("cargo:warning=Compiling CUDA kernels for RTX-Tensor GPU acceleration");
|
|
|
|
// Compile element-wise kernels
|
|
compile_kernel(
|
|
cuda_kernels_dir.join("element_wise.cu"),
|
|
Path::new(&out_dir).join("element_wise.ptx"),
|
|
)
|
|
.expect("Failed to compile element-wise CUDA kernels");
|
|
|
|
// Compile FP8 cast kernels (SM_89+ hardware path; software fallback for older GPUs)
|
|
compile_kernel(
|
|
cuda_kernels_dir.join("fp8_cast.cu"),
|
|
Path::new(&out_dir).join("fp8_cast.ptx"),
|
|
)
|
|
.expect("Failed to compile FP8 cast CUDA kernels");
|
|
|
|
println!("cargo:warning=CUDA kernels compiled successfully");
|
|
}
|
|
|
|
#[cfg(feature = "cuda")]
|
|
fn is_nvcc_available() -> bool {
|
|
Command::new("nvcc")
|
|
.arg("--version")
|
|
.output()
|
|
.map(|output| output.status.success())
|
|
.unwrap_or(false)
|
|
}
|
|
|
|
#[cfg(feature = "cuda")]
|
|
fn compile_kernel<P: AsRef<Path>>(
|
|
cu_file: P,
|
|
ptx_file: P,
|
|
) -> Result<(), Box<dyn std::error::Error>> {
|
|
let cu_path = cu_file.as_ref();
|
|
let ptx_path = ptx_file.as_ref();
|
|
|
|
// Ensure output directory exists
|
|
if let Some(parent) = ptx_path.parent() {
|
|
fs::create_dir_all(parent)?;
|
|
}
|
|
|
|
// Compile CUDA to PTX with RTX 3050/3090 (Ampere) optimizations
|
|
let output = Command::new("nvcc")
|
|
.arg("--ptx") // Generate PTX intermediate representation
|
|
.arg("--gpu-architecture=sm_86") // RTX 3050/3090 (Ampere) compute capability
|
|
.arg("--allow-unsupported-compiler") // Allow GCC 13+ (needed for Ubuntu 24.04)
|
|
.arg("--optimize=2") // Maximum optimization
|
|
.arg("--use_fast_math") // Fast math for performance
|
|
.arg("--maxrregcount=64") // Register optimization
|
|
.arg("-o")
|
|
.arg(ptx_path) // Output PTX file
|
|
.arg(cu_path) // Input CUDA source
|
|
.output()?;
|
|
|
|
if !output.status.success() {
|
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
eprintln!("NVCC compilation failed:");
|
|
eprintln!("{stderr}");
|
|
return Err(format!("NVCC failed with: {stderr}").into());
|
|
}
|
|
|
|
println!(
|
|
"cargo:warning=Compiled {} -> {}",
|
|
cu_path.display(),
|
|
ptx_path.display()
|
|
);
|
|
Ok(())
|
|
}
|
|
|
|
#[cfg(feature = "cuda")]
|
|
fn create_dummy_ptx(out_dir: &str) {
|
|
// Create dummy PTX file when NVCC is not available
|
|
let dummy_ptx = r#"
|
|
.version 7.0
|
|
.target sm_50
|
|
.address_size 64
|
|
|
|
.visible .entry dummy_kernel(.param .u64 dummy_param) {
|
|
ret;
|
|
}
|
|
"#;
|
|
|
|
fs::write(Path::new(out_dir).join("element_wise.ptx"), dummy_ptx)
|
|
.expect("Failed to create dummy element_wise PTX file");
|
|
|
|
// Also create a dummy fp8_cast.ptx so that `include_str!` in fp8_cast.rs
|
|
// compiles cleanly even when NVCC is unavailable.
|
|
fs::write(Path::new(out_dir).join("fp8_cast.ptx"), dummy_ptx)
|
|
.expect("Failed to create dummy fp8_cast PTX file");
|
|
}
|
|
|
|
/// Helper to embed PTX as string literal at compile time
|
|
#[cfg(feature = "cuda")]
|
|
pub fn generate_ptx_include() {
|
|
let out_dir = env::var("OUT_DIR").unwrap();
|
|
let ptx_path = Path::new(&out_dir).join("element_wise.ptx");
|
|
|
|
if ptx_path.exists() {
|
|
let ptx_content = fs::read_to_string(&ptx_path).expect("Failed to read compiled PTX file");
|
|
|
|
let include_code = format!(
|
|
"/// Compiled CUDA kernels as PTX strings\npub mod ptx_kernels {{\n pub const ELEMENT_WISE_PTX: &str = r#\"{ptx_content}\"#;\n}}"
|
|
);
|
|
|
|
let include_path = Path::new(&out_dir).join("ptx_include.rs");
|
|
fs::write(include_path, include_code).expect("Failed to generate PTX include file");
|
|
}
|
|
}
|