style: rustfmt formatting pass on rtx-tensor and rtx-flash-attention
Performance Benchmarks / Run Benchmarks (push) Successful in 8m13s
CI / Format Check (push) Failing after 13s
CI / Clippy Check (push) Failing after 11s
CI / Build (ubuntu-latest) (push) Failing after 7m37s
GPU Tests / Check GPU Availability (push) Successful in 0s
Documentation / Build User Guide (push) Successful in 15s
Documentation / Build API Documentation (push) Failing after 17s
CI / Build CPU-Only (Explicit) (push) Failing after 3m21s
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 9s
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 1s
GPU Tests / Metal Tests (push) Has been skipped

Import reordering, long-line reformatting — no logic changes.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
Omar Sobh
2026-06-26 18:11:10 +00:00
co-authored by Claude Sonnet 4.6
parent 39b7ef12f4
commit c82d26d6e7
18 changed files with 242 additions and 303 deletions
+1 -1
View File
@@ -3,9 +3,9 @@
//! Complete implementation following strict TDD principles. //! Complete implementation following strict TDD principles.
//! No placeholders, full implementation only. //! No placeholders, full implementation only.
use crate::BackendType;
#[cfg(feature = "cuda")] #[cfg(feature = "cuda")]
use crate::cuda_backend::CudaStreamHandle; use crate::cuda_backend::CudaStreamHandle;
use crate::BackendType;
use crate::device::{Stream, StreamId}; use crate::device::{Stream, StreamId};
use crate::error::{Result, RuntimeError}; use crate::error::{Result, RuntimeError};
use std::sync::Arc; use std::sync::Arc;
+1 -5
View File
@@ -185,11 +185,7 @@ impl<T: ComplexFloat> ComplexTensor<T> {
} }
/// Build a complex tensor from f64 nalgebra parts. /// Build a complex tensor from f64 nalgebra parts.
fn from_nalgebra( fn from_nalgebra(re: &DMatrix<f64>, im: &DMatrix<f64>, device: &crate::Device) -> Result<Self> {
re: &DMatrix<f64>,
im: &DMatrix<f64>,
device: &crate::Device,
) -> Result<Self> {
let (rows, cols) = (re.nrows(), re.ncols()); let (rows, cols) = (re.nrows(), re.ncols());
let mut re_data = Vec::with_capacity(rows * cols); let mut re_data = Vec::with_capacity(rows * cols);
let mut im_data = Vec::with_capacity(rows * cols); let mut im_data = Vec::with_capacity(rows * cols);
@@ -3,12 +3,7 @@
use crate::complex::ComplexTensor; use crate::complex::ComplexTensor;
use crate::{Device, Tensor}; use crate::{Device, Tensor};
fn complex_from_rows( fn complex_from_rows(re: Vec<f32>, im: Vec<f32>, n: usize, device: &Device) -> ComplexTensor<f32> {
re: Vec<f32>,
im: Vec<f32>,
n: usize,
device: &Device,
) -> ComplexTensor<f32> {
let real = Tensor::from_data(re, vec![n, n], device).unwrap(); let real = Tensor::from_data(re, vec![n, n], device).unwrap();
let imag = Tensor::from_data(im, vec![n, n], device).unwrap(); let imag = Tensor::from_data(im, vec![n, n], device).unwrap();
ComplexTensor::from_real_imag(real, imag).unwrap() ComplexTensor::from_real_imag(real, imag).unwrap()
@@ -154,12 +149,7 @@ fn matrix_exp_of_skew_hermitian_is_unitary() {
// verify the general property U†U = I instead of a specific matrix. // verify the general property U†U = I instead of a specific matrix.
let theta = 0.7_f32; let theta = 0.7_f32;
// iθY = [[0, −θ], [θ, 0]] (purely real skew-symmetric here). // iθY = [[0, −θ], [θ, 0]] (purely real skew-symmetric here).
let a = complex_from_rows( let a = complex_from_rows(vec![0.0, -theta, theta, 0.0], vec![0.0; 4], 2, &device);
vec![0.0, -theta, theta, 0.0],
vec![0.0; 4],
2,
&device,
);
let u = a.matrix_exp().unwrap(); let u = a.matrix_exp().unwrap();
let gram = u.adjoint().unwrap().matmul(&u).unwrap(); let gram = u.adjoint().unwrap().matmul(&u).unwrap();
let (g_re, g_im) = (gram.real().to_vec().unwrap(), gram.imag().to_vec().unwrap()); let (g_re, g_im) = (gram.real().to_vec().unwrap(), gram.imag().to_vec().unwrap());
+2 -4
View File
@@ -15,8 +15,7 @@ use objc2::rc::Retained;
use objc2::runtime::ProtocolObject; use objc2::runtime::ProtocolObject;
#[cfg(all(target_os = "macos", feature = "metal"))] #[cfg(all(target_os = "macos", feature = "metal"))]
use objc2_metal::{ use objc2_metal::{
MTLComputeCommandEncoder, MTLComputePipelineState, MTLDevice, MTLComputeCommandEncoder, MTLComputePipelineState, MTLDevice, MTLLibrary, MTLSize,
MTLLibrary, MTLSize,
}; };
#[cfg(all(target_os = "macos", feature = "metal"))] #[cfg(all(target_os = "macos", feature = "metal"))]
use std::collections::HashMap; use std::collections::HashMap;
@@ -341,8 +340,7 @@ impl<'a> KernelDispatcher<'a> {
// Pass numel as constant buffer parameter // Pass numel as constant buffer parameter
let numel_u32 = numel as u32; let numel_u32 = numel as u32;
let numel_ptr = let numel_ptr = NonNull::new_unchecked(&raw const numel_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const numel_u32 as *mut std::ffi::c_void);
self.encoder self.encoder
.setBytes_length_atIndex(numel_ptr, std::mem::size_of::<u32>(), 2); .setBytes_length_atIndex(numel_ptr, std::mem::size_of::<u32>(), 2);
+18 -36
View File
@@ -9,8 +9,7 @@ use objc2::rc::Retained;
use objc2::runtime::ProtocolObject; use objc2::runtime::ProtocolObject;
#[cfg(all(target_os = "macos", feature = "metal"))] #[cfg(all(target_os = "macos", feature = "metal"))]
use objc2_metal::{ use objc2_metal::{
MTLBuffer, MTLCommandBuffer, MTLCommandEncoder, MTLCommandQueue, MTLBuffer, MTLCommandBuffer, MTLCommandEncoder, MTLCommandQueue, MTLDevice, MTLSize,
MTLDevice, MTLSize,
}; };
#[cfg(all(target_os = "macos", feature = "metal"))] #[cfg(all(target_os = "macos", feature = "metal"))]
use std::ptr::NonNull; use std::ptr::NonNull;
@@ -301,15 +300,13 @@ impl MetalFusionOps {
encoder.setBuffer_offset_atIndex(Some(w_up), 0, 2); encoder.setBuffer_offset_atIndex(Some(w_up), 0, 2);
encoder.setBuffer_offset_atIndex(Some(output), 0, 3); encoder.setBuffer_offset_atIndex(Some(output), 0, 3);
let batch_ptr = let batch_ptr = NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(batch_ptr, std::mem::size_of::<u32>(), 4); encoder.setBytes_length_atIndex(batch_ptr, std::mem::size_of::<u32>(), 4);
let in_ptr = NonNull::new_unchecked(&raw const in_u32 as *mut std::ffi::c_void); let in_ptr = NonNull::new_unchecked(&raw const in_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(in_ptr, std::mem::size_of::<u32>(), 5); encoder.setBytes_length_atIndex(in_ptr, std::mem::size_of::<u32>(), 5);
let hidden_ptr = let hidden_ptr = NonNull::new_unchecked(&raw const hidden_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const hidden_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(hidden_ptr, std::mem::size_of::<u32>(), 6); encoder.setBytes_length_atIndex(hidden_ptr, std::mem::size_of::<u32>(), 6);
let grid_size = MTLSize { let grid_size = MTLSize {
@@ -374,15 +371,13 @@ impl MetalFusionOps {
encoder.setBuffer_offset_atIndex(Some(w_up), 0, 2); encoder.setBuffer_offset_atIndex(Some(w_up), 0, 2);
encoder.setBuffer_offset_atIndex(Some(output), 0, 3); encoder.setBuffer_offset_atIndex(Some(output), 0, 3);
let batch_ptr = let batch_ptr = NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(batch_ptr, std::mem::size_of::<u32>(), 4); encoder.setBytes_length_atIndex(batch_ptr, std::mem::size_of::<u32>(), 4);
let in_ptr = NonNull::new_unchecked(&raw const in_u32 as *mut std::ffi::c_void); let in_ptr = NonNull::new_unchecked(&raw const in_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(in_ptr, std::mem::size_of::<u32>(), 5); encoder.setBytes_length_atIndex(in_ptr, std::mem::size_of::<u32>(), 5);
let hidden_ptr = let hidden_ptr = NonNull::new_unchecked(&raw const hidden_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const hidden_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(hidden_ptr, std::mem::size_of::<u32>(), 6); encoder.setBytes_length_atIndex(hidden_ptr, std::mem::size_of::<u32>(), 6);
let grid_size = MTLSize { let grid_size = MTLSize {
@@ -448,12 +443,10 @@ impl MetalFusionOps {
encoder.setBuffer_offset_atIndex(Some(weight), 0, 1); encoder.setBuffer_offset_atIndex(Some(weight), 0, 1);
encoder.setBuffer_offset_atIndex(Some(output), 0, 2); encoder.setBuffer_offset_atIndex(Some(output), 0, 2);
let batch_ptr = let batch_ptr = NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(batch_ptr, std::mem::size_of::<u32>(), 3); encoder.setBytes_length_atIndex(batch_ptr, std::mem::size_of::<u32>(), 3);
let hidden_ptr = let hidden_ptr = NonNull::new_unchecked(&raw const hidden_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const hidden_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(hidden_ptr, std::mem::size_of::<u32>(), 4); encoder.setBytes_length_atIndex(hidden_ptr, std::mem::size_of::<u32>(), 4);
let eps_ptr = NonNull::new_unchecked(&raw const epsilon as *mut std::ffi::c_void); let eps_ptr = NonNull::new_unchecked(&raw const epsilon as *mut std::ffi::c_void);
@@ -534,12 +527,10 @@ impl MetalFusionOps {
encoder.setBuffer_offset_atIndex(Some(weight), 0, 2); encoder.setBuffer_offset_atIndex(Some(weight), 0, 2);
encoder.setBuffer_offset_atIndex(Some(output), 0, 3); encoder.setBuffer_offset_atIndex(Some(output), 0, 3);
let batch_ptr = let batch_ptr = NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(batch_ptr, std::mem::size_of::<u32>(), 4); encoder.setBytes_length_atIndex(batch_ptr, std::mem::size_of::<u32>(), 4);
let hidden_ptr = let hidden_ptr = NonNull::new_unchecked(&raw const hidden_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const hidden_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(hidden_ptr, std::mem::size_of::<u32>(), 5); encoder.setBytes_length_atIndex(hidden_ptr, std::mem::size_of::<u32>(), 5);
let eps_ptr = NonNull::new_unchecked(&raw const epsilon as *mut std::ffi::c_void); let eps_ptr = NonNull::new_unchecked(&raw const epsilon as *mut std::ffi::c_void);
@@ -616,8 +607,7 @@ impl MetalFusionOps {
encoder.setBuffer_offset_atIndex(Some(b), 0, 1); encoder.setBuffer_offset_atIndex(Some(b), 0, 1);
encoder.setBuffer_offset_atIndex(Some(output), 0, 2); encoder.setBuffer_offset_atIndex(Some(output), 0, 2);
let numel_ptr = let numel_ptr = NonNull::new_unchecked(&raw const numel_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const numel_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(numel_ptr, std::mem::size_of::<u32>(), 3); encoder.setBytes_length_atIndex(numel_ptr, std::mem::size_of::<u32>(), 3);
let grid_size = self.compute.grid_size_1d(numel); let grid_size = self.compute.grid_size_1d(numel);
@@ -681,8 +671,7 @@ impl MetalFusionOps {
encoder.setBuffer_offset_atIndex(Some(c), 0, 2); encoder.setBuffer_offset_atIndex(Some(c), 0, 2);
encoder.setBuffer_offset_atIndex(Some(output), 0, 3); encoder.setBuffer_offset_atIndex(Some(output), 0, 3);
let numel_ptr = let numel_ptr = NonNull::new_unchecked(&raw const numel_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const numel_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(numel_ptr, std::mem::size_of::<u32>(), 4); encoder.setBytes_length_atIndex(numel_ptr, std::mem::size_of::<u32>(), 4);
let grid_size = self.compute.grid_size_1d(numel); let grid_size = self.compute.grid_size_1d(numel);
@@ -743,23 +732,20 @@ impl MetalFusionOps {
encoder.setBuffer_offset_atIndex(Some(cos_cache), 0, 1); encoder.setBuffer_offset_atIndex(Some(cos_cache), 0, 1);
encoder.setBuffer_offset_atIndex(Some(sin_cache), 0, 2); encoder.setBuffer_offset_atIndex(Some(sin_cache), 0, 2);
let batch_ptr = let batch_ptr = NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(batch_ptr, std::mem::size_of::<u32>(), 3); encoder.setBytes_length_atIndex(batch_ptr, std::mem::size_of::<u32>(), 3);
let seq_ptr = NonNull::new_unchecked(&raw const seq_u32 as *mut std::ffi::c_void); let seq_ptr = NonNull::new_unchecked(&raw const seq_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(seq_ptr, std::mem::size_of::<u32>(), 4); encoder.setBytes_length_atIndex(seq_ptr, std::mem::size_of::<u32>(), 4);
let heads_ptr = let heads_ptr = NonNull::new_unchecked(&raw const heads_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const heads_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(heads_ptr, std::mem::size_of::<u32>(), 5); encoder.setBytes_length_atIndex(heads_ptr, std::mem::size_of::<u32>(), 5);
let head_dim_ptr = let head_dim_ptr =
NonNull::new_unchecked(&raw const head_dim_u32 as *mut std::ffi::c_void); NonNull::new_unchecked(&raw const head_dim_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(head_dim_ptr, std::mem::size_of::<u32>(), 6); encoder.setBytes_length_atIndex(head_dim_ptr, std::mem::size_of::<u32>(), 6);
let offset_ptr = let offset_ptr = NonNull::new_unchecked(&raw const offset_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const offset_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(offset_ptr, std::mem::size_of::<u32>(), 7); encoder.setBytes_length_atIndex(offset_ptr, std::mem::size_of::<u32>(), 7);
let grid_size = MTLSize { let grid_size = MTLSize {
@@ -833,20 +819,16 @@ impl MetalFusionOps {
encoder.setBuffer_offset_atIndex(Some(k), 0, 1); encoder.setBuffer_offset_atIndex(Some(k), 0, 1);
encoder.setBuffer_offset_atIndex(Some(scores), 0, 2); encoder.setBuffer_offset_atIndex(Some(scores), 0, 2);
let batch_ptr = let batch_ptr = NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(batch_ptr, std::mem::size_of::<u32>(), 3); encoder.setBytes_length_atIndex(batch_ptr, std::mem::size_of::<u32>(), 3);
let heads_ptr = let heads_ptr = NonNull::new_unchecked(&raw const heads_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const heads_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(heads_ptr, std::mem::size_of::<u32>(), 4); encoder.setBytes_length_atIndex(heads_ptr, std::mem::size_of::<u32>(), 4);
let seq_q_ptr = let seq_q_ptr = NonNull::new_unchecked(&raw const seq_q_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const seq_q_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(seq_q_ptr, std::mem::size_of::<u32>(), 5); encoder.setBytes_length_atIndex(seq_q_ptr, std::mem::size_of::<u32>(), 5);
let seq_k_ptr = let seq_k_ptr = NonNull::new_unchecked(&raw const seq_k_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const seq_k_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(seq_k_ptr, std::mem::size_of::<u32>(), 6); encoder.setBytes_length_atIndex(seq_k_ptr, std::mem::size_of::<u32>(), 6);
let head_dim_ptr = let head_dim_ptr =
+9 -18
View File
@@ -162,8 +162,7 @@ impl MetalMambaOps {
let d_state_u32 = d_state as u32; let d_state_u32 = d_state as u32;
let has_skip: u32 = u32::from(D.is_some()); let has_skip: u32 = u32::from(D.is_some());
let batch_ptr = let batch_ptr = NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(batch_ptr, 4, 7); encoder.setBytes_length_atIndex(batch_ptr, 4, 7);
let seq_ptr = NonNull::new_unchecked(&raw const seq_u32 as *mut std::ffi::c_void); let seq_ptr = NonNull::new_unchecked(&raw const seq_u32 as *mut std::ffi::c_void);
@@ -177,8 +176,7 @@ impl MetalMambaOps {
NonNull::new_unchecked(&raw const d_state_u32 as *mut std::ffi::c_void); NonNull::new_unchecked(&raw const d_state_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(d_state_ptr, 4, 10); encoder.setBytes_length_atIndex(d_state_ptr, 4, 10);
let has_skip_ptr = let has_skip_ptr = NonNull::new_unchecked(&raw const has_skip as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const has_skip as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(has_skip_ptr, 4, 11); encoder.setBytes_length_atIndex(has_skip_ptr, 4, 11);
// Configure threadgroup memory for state caching // Configure threadgroup memory for state caching
@@ -265,8 +263,7 @@ impl MetalMambaOps {
let d_state_u32 = d_state as u32; let d_state_u32 = d_state as u32;
let has_skip: u32 = u32::from(D.is_some()); let has_skip: u32 = u32::from(D.is_some());
let batch_ptr = let batch_ptr = NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(batch_ptr, 4, 8); encoder.setBytes_length_atIndex(batch_ptr, 4, 8);
let d_model_ptr = let d_model_ptr =
@@ -277,8 +274,7 @@ impl MetalMambaOps {
NonNull::new_unchecked(&raw const d_state_u32 as *mut std::ffi::c_void); NonNull::new_unchecked(&raw const d_state_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(d_state_ptr, 4, 10); encoder.setBytes_length_atIndex(d_state_ptr, 4, 10);
let has_skip_ptr = let has_skip_ptr = NonNull::new_unchecked(&raw const has_skip as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const has_skip as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(has_skip_ptr, 4, 11); encoder.setBytes_length_atIndex(has_skip_ptr, 4, 11);
let grid = MTLSize { let grid = MTLSize {
@@ -358,8 +354,7 @@ impl MetalMambaOps {
let kernel_u32 = kernel_size as u32; let kernel_u32 = kernel_size as u32;
let has_bias: u32 = u32::from(bias.is_some()); let has_bias: u32 = u32::from(bias.is_some());
let batch_ptr = let batch_ptr = NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(batch_ptr, 4, 4); encoder.setBytes_length_atIndex(batch_ptr, 4, 4);
let seq_ptr = NonNull::new_unchecked(&raw const seq_u32 as *mut std::ffi::c_void); let seq_ptr = NonNull::new_unchecked(&raw const seq_u32 as *mut std::ffi::c_void);
@@ -369,12 +364,10 @@ impl MetalMambaOps {
NonNull::new_unchecked(&raw const d_model_u32 as *mut std::ffi::c_void); NonNull::new_unchecked(&raw const d_model_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(d_model_ptr, 4, 6); encoder.setBytes_length_atIndex(d_model_ptr, 4, 6);
let kernel_ptr = let kernel_ptr = NonNull::new_unchecked(&raw const kernel_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const kernel_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(kernel_ptr, 4, 7); encoder.setBytes_length_atIndex(kernel_ptr, 4, 7);
let has_bias_ptr = let has_bias_ptr = NonNull::new_unchecked(&raw const has_bias as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const has_bias as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(has_bias_ptr, 4, 8); encoder.setBytes_length_atIndex(has_bias_ptr, 4, 8);
let grid = MTLSize { let grid = MTLSize {
@@ -428,8 +421,7 @@ impl MetalMambaOps {
encoder.setBuffer_offset_atIndex(Some(state), 0, 0); encoder.setBuffer_offset_atIndex(Some(state), 0, 0);
let numel_u32 = numel as u32; let numel_u32 = numel as u32;
let numel_ptr = let numel_ptr = NonNull::new_unchecked(&raw const numel_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const numel_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(numel_ptr, 4, 1); encoder.setBytes_length_atIndex(numel_ptr, 4, 1);
let grid = MTLSize { let grid = MTLSize {
@@ -483,8 +475,7 @@ impl MetalMambaOps {
encoder.setBuffer_offset_atIndex(Some(output), 0, 2); encoder.setBuffer_offset_atIndex(Some(output), 0, 2);
let numel_u32 = numel as u32; let numel_u32 = numel as u32;
let numel_ptr = let numel_ptr = NonNull::new_unchecked(&raw const numel_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const numel_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(numel_ptr, 4, 3); encoder.setBytes_length_atIndex(numel_ptr, 4, 3);
let grid = MTLSize { let grid = MTLSize {
+2 -4
View File
@@ -492,12 +492,10 @@ impl MetalMoEOps {
let numel_u32 = numel as u32; let numel_u32 = numel as u32;
let numel_ptr = let numel_ptr = NonNull::new_unchecked(&raw const numel_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const numel_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(numel_ptr, 4, 2); encoder.setBytes_length_atIndex(numel_ptr, 4, 2);
let jitter_ptr = let jitter_ptr = NonNull::new_unchecked(&raw const jitter_eps as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const jitter_eps as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(jitter_ptr, 4, 3); encoder.setBytes_length_atIndex(jitter_ptr, 4, 3);
let grid = MTLSize { let grid = MTLSize {
+1 -4
View File
@@ -15,10 +15,7 @@ use crate::metal_compute::MetalCompute;
#[cfg(all(target_os = "macos", feature = "metal"))] #[cfg(all(target_os = "macos", feature = "metal"))]
use objc2::runtime::ProtocolObject; use objc2::runtime::ProtocolObject;
#[cfg(all(target_os = "macos", feature = "metal"))] #[cfg(all(target_os = "macos", feature = "metal"))]
use objc2_metal::{ use objc2_metal::{MTLBuffer, MTLCommandBuffer, MTLCommandEncoder, MTLCommandQueue, MTLDevice};
MTLBuffer, MTLCommandBuffer, MTLCommandEncoder, MTLCommandQueue,
MTLDevice,
};
#[cfg(all(target_os = "macos", feature = "metal"))] #[cfg(all(target_os = "macos", feature = "metal"))]
use std::sync::{LazyLock, RwLock}; use std::sync::{LazyLock, RwLock};
@@ -138,16 +138,13 @@ impl MetalSpeculativeOps {
let batch_u32 = batch_size as u32; let batch_u32 = batch_size as u32;
let vocab_u32 = vocab_size as u32; let vocab_u32 = vocab_size as u32;
let batch_ptr = let batch_ptr = NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(batch_ptr, 4, 2); encoder.setBytes_length_atIndex(batch_ptr, 4, 2);
let vocab_ptr = let vocab_ptr = NonNull::new_unchecked(&raw const vocab_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const vocab_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(vocab_ptr, 4, 3); encoder.setBytes_length_atIndex(vocab_ptr, 4, 3);
let temp_ptr = let temp_ptr = NonNull::new_unchecked(&raw const temperature as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const temperature as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(temp_ptr, 4, 4); encoder.setBytes_length_atIndex(temp_ptr, 4, 4);
// Allocate threadgroup memory for reduction // Allocate threadgroup memory for reduction
@@ -214,12 +211,10 @@ impl MetalSpeculativeOps {
let vocab_u32 = vocab_size as u32; let vocab_u32 = vocab_size as u32;
let k_u32 = k as u32; let k_u32 = k as u32;
let batch_ptr = let batch_ptr = NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(batch_ptr, 4, 3); encoder.setBytes_length_atIndex(batch_ptr, 4, 3);
let vocab_ptr = let vocab_ptr = NonNull::new_unchecked(&raw const vocab_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const vocab_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(vocab_ptr, 4, 4); encoder.setBytes_length_atIndex(vocab_ptr, 4, 4);
let k_ptr = NonNull::new_unchecked(&raw const k_u32 as *mut std::ffi::c_void); let k_ptr = NonNull::new_unchecked(&raw const k_u32 as *mut std::ffi::c_void);
@@ -294,8 +289,7 @@ impl MetalSpeculativeOps {
NonNull::new_unchecked(&raw const num_draft_u32 as *mut std::ffi::c_void); NonNull::new_unchecked(&raw const num_draft_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(num_draft_ptr, 4, 4); encoder.setBytes_length_atIndex(num_draft_ptr, 4, 4);
let vocab_ptr = let vocab_ptr = NonNull::new_unchecked(&raw const vocab_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const vocab_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(vocab_ptr, 4, 5); encoder.setBytes_length_atIndex(vocab_ptr, 4, 5);
let grid = MTLSize { let grid = MTLSize {
@@ -418,12 +412,10 @@ impl MetalSpeculativeOps {
let start_pos_u32 = start_pos as u32; let start_pos_u32 = start_pos as u32;
let new_seq_u32 = new_seq_len as u32; let new_seq_u32 = new_seq_len as u32;
let layer_ptr = let layer_ptr = NonNull::new_unchecked(&raw const layer_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const layer_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(layer_ptr, 4, 4); encoder.setBytes_length_atIndex(layer_ptr, 4, 4);
let batch_ptr = let batch_ptr = NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(batch_ptr, 4, 5); encoder.setBytes_length_atIndex(batch_ptr, 4, 5);
let num_heads_ptr = let num_heads_ptr =
@@ -515,12 +507,10 @@ impl MetalSpeculativeOps {
let rollback_u32 = rollback_to as u32; let rollback_u32 = rollback_to as u32;
let current_u32 = current_pos as u32; let current_u32 = current_pos as u32;
let layer_ptr = let layer_ptr = NonNull::new_unchecked(&raw const layer_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const layer_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(layer_ptr, 4, 2); encoder.setBytes_length_atIndex(layer_ptr, 4, 2);
let batch_ptr = let batch_ptr = NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(batch_ptr, 4, 3); encoder.setBytes_length_atIndex(batch_ptr, 4, 3);
let num_heads_ptr = let num_heads_ptr =
@@ -599,12 +589,10 @@ impl MetalSpeculativeOps {
let batch_u32 = batch_size as u32; let batch_u32 = batch_size as u32;
let vocab_u32 = vocab_size as u32; let vocab_u32 = vocab_size as u32;
let batch_ptr = let batch_ptr = NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(batch_ptr, 4, 2); encoder.setBytes_length_atIndex(batch_ptr, 4, 2);
let vocab_ptr = let vocab_ptr = NonNull::new_unchecked(&raw const vocab_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const vocab_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(vocab_ptr, 4, 3); encoder.setBytes_length_atIndex(vocab_ptr, 4, 3);
let threadgroup_size = 256usize; let threadgroup_size = 256usize;
@@ -669,12 +657,10 @@ impl MetalSpeculativeOps {
let batch_u32 = batch_size as u32; let batch_u32 = batch_size as u32;
let vocab_u32 = vocab_size as u32; let vocab_u32 = vocab_size as u32;
let batch_ptr = let batch_ptr = NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const batch_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(batch_ptr, 4, 3); encoder.setBytes_length_atIndex(batch_ptr, 4, 3);
let vocab_ptr = let vocab_ptr = NonNull::new_unchecked(&raw const vocab_u32 as *mut std::ffi::c_void);
NonNull::new_unchecked(&raw const vocab_u32 as *mut std::ffi::c_void);
encoder.setBytes_length_atIndex(vocab_ptr, 4, 4); encoder.setBytes_length_atIndex(vocab_ptr, 4, 4);
let grid = MTLSize { let grid = MTLSize {
@@ -306,10 +306,7 @@ fn validate_batched_tensor_dimensions(
// Track batch dimensions separately // Track batch dimensions separately
if equation.batch_dims.contains(&dim_char) { if equation.batch_dims.contains(&dim_char) {
batch_sizes batch_sizes.entry(dim_char).or_default().push(dim_size);
.entry(dim_char)
.or_default()
.push(dim_size);
} }
} }
} }
@@ -14,9 +14,9 @@ use crate::cusparse::{
use crate::sparse::{SparseCOO, SparseCSR}; use crate::sparse::{SparseCOO, SparseCSR};
use crate::{Device, Result, Shape, Tensor, TensorError}; use crate::{Device, Result, Shape, Tensor, TensorError};
#[cfg(feature = "cuda")] #[cfg(feature = "cuda")]
use cudarc::driver::safe::CudaContext as CudaDevice;
#[cfg(feature = "cuda")]
use cudarc::driver::DevicePtr; use cudarc::driver::DevicePtr;
#[cfg(feature = "cuda")]
use cudarc::driver::safe::CudaContext as CudaDevice;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
@@ -768,20 +768,12 @@ impl CuSparseKernels {
// Convert back to sparse (with some sparsity threshold) // Convert back to sparse (with some sparsity threshold)
let shape = Shape::new(dense_c.shape().dims().to_vec())?; let shape = Shape::new(dense_c.shape().dims().to_vec())?;
SparseCOO::from_triplets( SparseCOO::from_triplets(vec![], vec![], vec![] as Vec<f32>, shape, &self.device)
vec![],
vec![],
vec![] as Vec<f32>,
shape,
&self.device,
)
} }
fn record_performance(&self, operation: &str, time_ms: f64, nnz: usize) { fn record_performance(&self, operation: &str, time_ms: f64, nnz: usize) {
let mut stats = self.perf_stats.lock().unwrap(); let mut stats = self.perf_stats.lock().unwrap();
let entry = stats let entry = stats.entry(operation.to_string()).or_default();
.entry(operation.to_string())
.or_default();
entry.total_calls += 1; entry.total_calls += 1;
entry.total_time_ms += time_ms; entry.total_time_ms += time_ms;
@@ -8,7 +8,6 @@ use std::sync::Arc;
#[cfg(feature = "cuda")] #[cfg(feature = "cuda")]
use super::types::StorageData; use super::types::StorageData;
impl Storage { impl Storage {
#[cfg(feature = "cuda")] #[cfg(feature = "cuda")]
pub fn prefetch(&self) -> Result<()> { pub fn prefetch(&self) -> Result<()> {
@@ -1,20 +1,18 @@
//! Raw pointer access methods //! Raw pointer access methods
use super::types::{
Storage, StorageData,
};
#[cfg(feature = "cuda")] #[cfg(feature = "cuda")]
use super::types::{ use super::types::{
GPU_CPU_BUFFERS, GPU_CPU_BUFFERS_F16, GPU_CPU_BUFFERS_F64, GPU_CPU_BUFFERS, GPU_CPU_BUFFERS_F16, GPU_CPU_BUFFERS_F64, GPU_CPU_MUT_BUFFERS,
GPU_CPU_MUT_BUFFERS, GPU_CPU_MUT_BUFFERS_F16, GPU_CPU_MUT_BUFFERS_F64, GPU_CPU_MUT_BUFFERS_F16, GPU_CPU_MUT_BUFFERS_F64, SendPtr,
SendPtr,
}; };
use super::types::{Storage, StorageData};
#[cfg(all(target_os = "macos", feature = "metal"))] #[cfg(all(target_os = "macos", feature = "metal"))]
use objc2_metal::MTLBuffer; use objc2_metal::MTLBuffer;
impl Storage { impl Storage {
pub unsafe fn data_ptr(&self) -> *const u8 { unsafe { pub unsafe fn data_ptr(&self) -> *const u8 {
unsafe {
// SAFETY: Pointer access for tensor data interfacing: // SAFETY: Pointer access for tensor data interfacing:
// - Caller guarantees proper lifetime and synchronization per API contract // - Caller guarantees proper lifetime and synchronization per API contract
// - Pointer arithmetic is bounds-checked against numel and offset // - Pointer arithmetic is bounds-checked against numel and offset
@@ -94,9 +92,11 @@ impl Storage {
)))] )))]
_ => unreachable!("No storage backend"), _ => unreachable!("No storage backend"),
} }
}} }
}
pub unsafe fn data_ptr_mut(&mut self) -> *mut u8 { unsafe { pub unsafe fn data_ptr_mut(&mut self) -> *mut u8 {
unsafe {
let mut inner = self.inner.lock().unwrap(); let mut inner = self.inner.lock().unwrap();
let dtype_size = inner.dtype.size_bytes(); let dtype_size = inner.dtype.size_bytes();
match &mut inner.data { match &mut inner.data {
@@ -165,5 +165,6 @@ impl Storage {
)))] )))]
_ => unreachable!("No storage backend"), _ => unreachable!("No storage backend"),
} }
}} }
}
} }
@@ -48,22 +48,31 @@ impl Tensor {
for tensor in tensors { for tensor in tensors {
// Check device compatibility // Check device compatibility
if &tensor.device != device { if &tensor.device != device {
return Err(TensorError::device("All tensors must be on the same device for concatenation".to_string())); return Err(TensorError::device(
"All tensors must be on the same device for concatenation".to_string(),
));
} }
// Check dtype compatibility // Check dtype compatibility
if tensor.dtype != dtype { if tensor.dtype != dtype {
return Err(TensorError::type_error("All tensors must have the same dtype for concatenation".to_string())); return Err(TensorError::type_error(
"All tensors must have the same dtype for concatenation".to_string(),
));
} }
// Check shape compatibility (all dimensions except concatenation dimension must match) // Check shape compatibility (all dimensions except concatenation dimension must match)
if tensor.ndim() != first.ndim() { if tensor.ndim() != first.ndim() {
return Err(TensorError::shape("All tensors must have the same number of dimensions".to_string())); return Err(TensorError::shape(
"All tensors must have the same number of dimensions".to_string(),
));
} }
for i in 0..tensor.ndim() { for i in 0..tensor.ndim() {
if i != actual_dim && tensor.shape().dims()[i] != first.shape().dims()[i] { if i != actual_dim && tensor.shape().dims()[i] != first.shape().dims()[i] {
return Err(TensorError::shape("All tensors must have the same shape except in concatenation dimension".to_string())); return Err(TensorError::shape(
"All tensors must have the same shape except in concatenation dimension"
.to_string(),
));
} }
} }
@@ -467,13 +476,19 @@ impl Tensor {
for tensor in tensors.iter().skip(1) { for tensor in tensors.iter().skip(1) {
if tensor.shape() != shape { if tensor.shape() != shape {
return Err(TensorError::shape("All tensors must have the same shape for stacking".to_string())); return Err(TensorError::shape(
"All tensors must have the same shape for stacking".to_string(),
));
} }
if &tensor.device != device { if &tensor.device != device {
return Err(TensorError::device("All tensors must be on the same device for stacking".to_string())); return Err(TensorError::device(
"All tensors must be on the same device for stacking".to_string(),
));
} }
if tensor.dtype != dtype { if tensor.dtype != dtype {
return Err(TensorError::type_error("All tensors must have the same dtype for stacking".to_string())); return Err(TensorError::type_error(
"All tensors must have the same dtype for stacking".to_string(),
));
} }
} }
+3 -12
View File
@@ -833,14 +833,8 @@ impl Tensor {
.collect(), .collect(),
// Quantized types (experimental - just clamp to valid ranges) // Quantized types (experimental - just clamp to valid ranges)
(_, DType::I4) => data (_, DType::I4) => data.iter().map(|&x| x.round().clamp(-8.0, 7.0)).collect(),
.iter() (_, DType::I2) => data.iter().map(|&x| x.round().clamp(-2.0, 1.0)).collect(),
.map(|&x| x.round().clamp(-8.0, 7.0))
.collect(),
(_, DType::I2) => data
.iter()
.map(|&x| x.round().clamp(-2.0, 1.0))
.collect(),
(_, DType::I1) => data (_, DType::I1) => data
.iter() .iter()
.map(|&x| if x > 0.0 { 1.0 } else { -1.0 }) .map(|&x| if x > 0.0 { 1.0 } else { -1.0 })
@@ -850,10 +844,7 @@ impl Tensor {
(_, DType::FP8E4M3 | DType::FP8E5M2) => data, (_, DType::FP8E4M3 | DType::FP8E5M2) => data,
(_, DType::MXFP8 | DType::MXFP6 | DType::MXFP4) => data, (_, DType::MXFP8 | DType::MXFP6 | DType::MXFP4) => data,
(_, DType::MXInt8) => data.iter().map(|&x| x.round()).collect(), (_, DType::MXInt8) => data.iter().map(|&x| x.round()).collect(),
(_, DType::MXInt4) => data (_, DType::MXInt4) => data.iter().map(|&x| x.round().clamp(-8.0, 7.0)).collect(),
.iter()
.map(|&x| x.round().clamp(-8.0, 7.0))
.collect(),
}; };
// Create new tensor with converted data and new dtype // Create new tensor with converted data and new dtype
@@ -10,5 +10,4 @@
mod cuda_kernels; mod cuda_kernels;
mod ops; mod ops;
// CUDA kernels are used internally by ops.rs via impl blocks on Tensor // CUDA kernels are used internally by ops.rs via impl blocks on Tensor
+10 -3
View File
@@ -25,7 +25,9 @@ fn main() {
compile_cuda_kernels(&nvcc); compile_cuda_kernels(&nvcc);
link_cuda_libraries(); link_cuda_libraries();
} else { } else {
println!("cargo:warning=CUDA feature enabled but nvcc not found. Set CUDA_PATH=/path/to/cuda"); println!(
"cargo:warning=CUDA feature enabled but nvcc not found. Set CUDA_PATH=/path/to/cuda"
);
} }
} }
@@ -110,7 +112,10 @@ fn compile_cuda_kernels(nvcc: &Path) {
let output_path = Path::new(&out_dir).join(&output_name); let output_path = Path::new(&out_dir).join(&output_name);
let mut cmd = Command::new(nvcc); let mut cmd = Command::new(nvcc);
cmd.arg("--ptx").arg(&input_path).arg("-o").arg(&output_path); cmd.arg("--ptx")
.arg(&input_path)
.arg("-o")
.arg(&output_path);
for flag in &cuda_flags { for flag in &cuda_flags {
cmd.arg(flag); cmd.arg(flag);
} }
@@ -123,7 +128,9 @@ fn compile_cuda_kernels(nvcc: &Path) {
} }
} }
let output = cmd.output().unwrap_or_else(|e| panic!("nvcc exec failed for {kernel}: {e}")); let output = cmd
.output()
.unwrap_or_else(|e| panic!("nvcc exec failed for {kernel}: {e}"));
if !output.status.success() { if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr); let stderr = String::from_utf8_lossy(&output.stderr);
panic!("CUDA kernel compilation failed for {kernel}:\n{stderr}"); panic!("CUDA kernel compilation failed for {kernel}:\n{stderr}");