From 8a7a5b45be6b83f5caccf9f2d6e6ddb8c0a3b921 Mon Sep 17 00:00:00 2001 From: Andrzej Janik Date: Wed, 3 Sep 2025 21:22:07 +0200 Subject: [PATCH] Reorganize driver host tests, fix bugs around pointer host code (#492) --- Cargo.lock | 17 +----- Cargo.toml | 1 - cuda_macros/src/lib.rs | 57 +++++++------------- cuda_tests/Cargo.toml | 16 ------ cuda_tests/src/cuda/mod.rs | 8 --- cuda_tests/src/lib.rs | 24 --------- zluda/Cargo.toml | 4 +- zluda/src/impl/driver.rs | 7 +++ zluda/src/impl/pointer.rs | 108 ++++++++++++++++++++++++++++++++++--- zluda/src/tests.rs | 51 ++++++++++++++++++ zluda/src/tests/mod.rs | 8 --- 11 files changed, 182 insertions(+), 119 deletions(-) delete mode 100644 cuda_tests/Cargo.toml delete mode 100644 cuda_tests/src/cuda/mod.rs delete mode 100644 cuda_tests/src/lib.rs create mode 100644 zluda/src/tests.rs delete mode 100644 zluda/src/tests/mod.rs diff --git a/Cargo.lock b/Cargo.lock index c0efe2c..56b79c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -447,21 +447,6 @@ dependencies = [ "syn 2.0.89", ] -[[package]] -name = "cuda_tests" -version = "0.0.0" -dependencies = [ - "cuda_macros", - "cuda_types", - "dtor 0.0.6", - "lazy_static", - "lz4-sys", - "num_enum", - "paste", - "rustc-hash 1.1.0", - "tempfile", -] - [[package]] name = "cuda_types" version = "0.0.0" @@ -3729,13 +3714,13 @@ dependencies = [ "blake3", "comgr", "cuda_macros", - "cuda_tests", "cuda_types", "dark_api", "dtor 0.0.7", "hip_runtime-sys", "lazy_static", "libc", + "libloading", "lz4-sys", "num_enum", "paste", diff --git a/Cargo.toml b/Cargo.toml index db4f75b..9415c8f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,6 @@ members = [ "comgr", "cuda_macros", "cuda_types", - "cuda_tests", "dark_api", "detours-sys", "ext/amd_comgr-sys", diff --git a/cuda_macros/src/lib.rs b/cuda_macros/src/lib.rs index 58b4d0f..483ba75 100644 --- a/cuda_macros/src/lib.rs +++ b/cuda_macros/src/lib.rs @@ -2,7 +2,7 @@ extern crate proc_macro; use proc_macro::TokenStream; use proc_macro2::Span; -use quote::{quote, ToTokens}; +use quote::{format_ident, quote, ToTokens}; use rustc_hash::FxHashMap; use std::iter; use syn::parse::{Parse, ParseStream}; @@ -10,7 +10,7 @@ use syn::punctuated::Punctuated; use syn::visit_mut::VisitMut; use syn::{ bracketed, parse_macro_input, File, ForeignItem, ForeignItemFn, Ident, Item, Path, Signature, - Token, token + Token }; const CUDA_RS: &'static str = include_str! {"cuda.rs"}; @@ -309,39 +309,22 @@ fn join( } -#[proc_macro] -pub fn generate_api_macro(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as ApiMacroInput); - let ApiMacroInput(_, trait_name, _, type_name, _, macro_name) = input; - let expanded = quote! { - struct #type_name; - macro_rules! #macro_name { - ($($abi:literal fn $fn_name:ident( $( $arg_id:ident : $arg_type:ty ),* ) -> $ret_type:ty;)*) => { - impl #trait_name for #type_name { - fn new() -> Self { Self } - $( - #[inline(always)] - fn $fn_name(&self, $( $arg_id : $arg_type ),* ) -> $ret_type { - unsafe { super::$fn_name( $( $arg_id ),* ) } - } - )* - } - }; +#[proc_macro_attribute] +pub fn test_cuda(_attr: TokenStream, item: TokenStream) -> TokenStream { + let fn_ = parse_macro_input!(item as syn::ItemFn); + let cuda_fn = format_ident!("{}{}", fn_.sig.ident, "_nvidia"); + let zluda_fn = format_ident!("{}{}", fn_.sig.ident, "_amdgpu"); + let fn_name = fn_.sig.ident.clone(); + quote! { + #[test] + fn #cuda_fn() { + unsafe { #fn_name(::new()) } } - }; - TokenStream::from(expanded) -} -#[allow(dead_code)] -struct ApiMacroInput(token::Impl, Path, token::For, Path, token::Use, Ident); -impl syn::parse::Parse for ApiMacroInput { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - Ok(ApiMacroInput( - input.parse()?, // impl - input.parse()?, // trait - input.parse()?, // for - input.parse()?, // type - input.parse()?, // using - input.parse()? // macro - )) - } -} + #[test] + fn #zluda_fn() { + unsafe { #fn_name(::new()) } + } + + #fn_ + }.into() +} \ No newline at end of file diff --git a/cuda_tests/Cargo.toml b/cuda_tests/Cargo.toml deleted file mode 100644 index 2ff6700..0000000 --- a/cuda_tests/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "cuda_tests" -version = "0.0.0" -authors = ["Andrzej Janik "] -edition = "2021" - -[dependencies] -cuda_types = { path = "../cuda_types" } -cuda_macros = { path = "../cuda_macros" } -lazy_static = "1.4" -num_enum = "0.4" -lz4-sys = "1.9" -tempfile = "3" -paste = "1.0" -rustc-hash = "1.1" -dtor = "0.0.6" diff --git a/cuda_tests/src/cuda/mod.rs b/cuda_tests/src/cuda/mod.rs deleted file mode 100644 index a512158..0000000 --- a/cuda_tests/src/cuda/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -use crate::api_trait; -use cuda_types::cuda::*; - -cuda_macros::cuda_function_declarations!(api_trait); - -pub unsafe fn init_check(api: T) { - assert_eq!(api.cuInit(0), CUresult::SUCCESS); -} diff --git a/cuda_tests/src/lib.rs b/cuda_tests/src/lib.rs deleted file mode 100644 index 5141eb3..0000000 --- a/cuda_tests/src/lib.rs +++ /dev/null @@ -1,24 +0,0 @@ -#[macro_export] -macro_rules! api_trait { - ($($abi:literal fn $fn_name:ident( $($arg_id:ident : $arg_type:ty),* ) -> $ret_type:ty;)*) => { - pub trait Api { - fn new() -> Self; - $(fn $fn_name(&self, $( $arg_id : $arg_type ),* ) -> $ret_type;)* - } - }; -} - -#[macro_export] -macro_rules! api_test { - ($func:ident, $type:ty) => { - paste::paste! { - #[test] - #[allow(non_snake_case)] - fn [<$func _test>]() { - unsafe { $func::<$type>(<$type>::new()) } - } - } - }; -} - -pub mod cuda; diff --git a/zluda/Cargo.toml b/zluda/Cargo.toml index 923227d..d0a65f4 100644 --- a/zluda/Cargo.toml +++ b/zluda/Cargo.toml @@ -27,7 +27,6 @@ zluda_common = { path = "../zluda_common" } blake3 = "1.8.2" serde = "1.0.219" serde_json = "1.0.142" -cuda_tests = { path = "../cuda_tests" } [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["heapapi", "std"] } @@ -39,6 +38,9 @@ dtor = "0.0.7" [build-dependencies] vergen-gix = "1.0.9" +[dev-dependencies] +libloading = "0.8" + [package.metadata.zluda] linux_symlinks = [ "libcuda.so", diff --git a/zluda/src/impl/driver.rs b/zluda/src/impl/driver.rs index bc885ea..3a54ac7 100644 --- a/zluda/src/impl/driver.rs +++ b/zluda/src/impl/driver.rs @@ -528,8 +528,15 @@ pub(crate) unsafe fn launch_kernel_ex( #[cfg(test)] mod tests { use crate::r#impl::driver::AllocationInfo; + use crate::tests::CudaApi; + use cuda_macros::test_cuda; use cuda_types::cuda::CUcontext; + #[test_cuda] + fn init(api: impl CudaApi) { + api.cuInit(0); + } + #[test] fn get_allocation() { let ctx1 = CUcontext(0x1234 as _); diff --git a/zluda/src/impl/pointer.rs b/zluda/src/impl/pointer.rs index 050f8f0..8eda15e 100644 --- a/zluda/src/impl/pointer.rs +++ b/zluda/src/impl/pointer.rs @@ -27,12 +27,8 @@ pub(crate) unsafe fn get_attribute( } match attribute { hipPointer_attribute::HIP_POINTER_ATTRIBUTE_CONTEXT => { - let globals = driver::global_state()?; - let allocations = globals.allocations.lock().map_err(|_| CUerror::UNKNOWN)?; - let (_, alloc) = allocations - .get_offset_and_info(ptr.0 as usize) - .ok_or(CUerror::INVALID_VALUE)?; - unsafe { *(data.cast()) = alloc.context }; + let context = get_context(ptr)?; + unsafe { *(data.cast()) = context }; Ok(()) } hipPointer_attribute::HIP_POINTER_ATTRIBUTE_MEMORY_TYPE => { @@ -48,6 +44,15 @@ pub(crate) unsafe fn get_attribute( } } +fn get_context(ptr: hipDeviceptr_t) -> Result { + let globals = driver::global_state()?; + let allocations = globals.allocations.lock().map_err(|_| CUerror::UNKNOWN)?; + let (_, alloc) = allocations + .get_offset_and_info(ptr.0 as usize) + .ok_or(CUerror::INVALID_VALUE)?; + Ok(alloc.context) +} + pub(crate) unsafe fn get_attributes( num_attributes: ::core::ffi::c_uint, attributes: &mut hipPointer_attribute, @@ -59,15 +64,102 @@ pub(crate) unsafe fn get_attributes( let data = std::slice::from_raw_parts_mut(data, num_attributes as usize); for (attr, data_ptr) in attributes.iter().copied().zip(data.iter().copied()) { match attr { + hipPointer_attribute::HIP_POINTER_ATTRIBUTE_HOST_POINTER => { + if (*(data_ptr.cast::())).0.is_null() { + *(data_ptr.cast::()) = ptr; + } + } hipPointer_attribute::HIP_POINTER_ATTRIBUTE_CONTEXT => { - get_attribute(data_ptr, attr, ptr).ok(); + *(data_ptr.cast::()) = + get_context(ptr).unwrap_or(CUcontext(ptr::null_mut())); } hipPointer_attribute::HIP_POINTER_ATTRIBUTE_MEMORY_TYPE => { *(data_ptr.cast::()) = - to_cu_memory_type(*data_ptr.cast::())?; + to_cu_memory_type(*data_ptr.cast::()).unwrap_or(CUmemorytype(0)); } _ => {} } } Ok(()) } + +#[cfg(test)] +mod tests { + use crate::tests::CudaApi; + use cuda_macros::test_cuda; + use cuda_types::cuda::*; + use std::{ffi::c_void, mem, ptr}; + + #[test_cuda] + pub unsafe fn unknown_ptr_attribute(api: impl CudaApi) { + api.cuInit(0); + api.cuCtxCreate_v2(&mut mem::zeroed(), 0, 0); + let mut ctx = mem::zeroed::(); + assert_eq!( + CUresult::ERROR_INVALID_VALUE, + api.cuPointerGetAttribute_unchecked( + std::ptr::from_mut(&mut ctx).cast(), + CUpointer_attribute::CU_POINTER_ATTRIBUTE_CONTEXT, + CUdeviceptr_v2(0xDEAD as _) + ) + ); + } + + #[test_cuda] + pub unsafe fn unknown_ptr_attributes(api: impl CudaApi) { + api.cuInit(0); + api.cuCtxCreate_v2(&mut mem::zeroed(), 0, 0); + let mut mem_type = mem::zeroed::(); + let mut host_ptr = mem::zeroed::<*mut c_void>(); + let mut dev_ptr = mem::zeroed::<*mut c_void>(); + let mut is_managed = mem::zeroed::(); + let mut ordinal = mem::zeroed::(); + let mut attrs = [ + CUpointer_attribute::CU_POINTER_ATTRIBUTE_MEMORY_TYPE, + CUpointer_attribute::CU_POINTER_ATTRIBUTE_DEVICE_POINTER, + CUpointer_attribute::CU_POINTER_ATTRIBUTE_HOST_POINTER, + CUpointer_attribute::CU_POINTER_ATTRIBUTE_IS_MANAGED, + CUpointer_attribute::CU_POINTER_ATTRIBUTE_DEVICE_ORDINAL, + ]; + let mut values = [ + std::ptr::from_mut(&mut mem_type).cast::(), + std::ptr::from_mut(&mut dev_ptr).cast(), + std::ptr::from_mut(&mut host_ptr).cast(), + std::ptr::from_mut(&mut is_managed).cast(), + std::ptr::from_mut(&mut ordinal).cast(), + ]; + assert_eq!( + CUresult::SUCCESS, + api.cuPointerGetAttributes_unchecked( + attrs.len() as u32, + attrs.as_mut_ptr(), + values.as_mut_ptr(), + CUdeviceptr_v2(0xDEAD as _) + ) + ); + assert_eq!(mem_type, CUmemorytype(0)); + assert_eq!(host_ptr, 0xDEAD as _); + assert_eq!(dev_ptr, ptr::null_mut()); + assert_eq!(is_managed, false); + assert_eq!(ordinal, -2); + } + + #[test_cuda] + pub unsafe fn unknown_ptr_attributes_no_context(api: impl CudaApi) { + api.cuInit(0); + api.cuCtxCreate_v2(&mut mem::zeroed(), 0, 0); + let mut context = CUcontext(1 as _); + let mut attrs = [CUpointer_attribute::CU_POINTER_ATTRIBUTE_CONTEXT]; + let mut values = [std::ptr::from_mut(&mut context).cast::()]; + assert_eq!( + CUresult::SUCCESS, + api.cuPointerGetAttributes_unchecked( + attrs.len() as u32, + attrs.as_mut_ptr(), + values.as_mut_ptr(), + CUdeviceptr_v2(0xDEAD as _) + ) + ); + assert_eq!(context, CUcontext(ptr::null_mut())); + } +} diff --git a/zluda/src/tests.rs b/zluda/src/tests.rs new file mode 100644 index 0000000..8781e8f --- /dev/null +++ b/zluda/src/tests.rs @@ -0,0 +1,51 @@ +pub(crate) struct Zluda; + +pub(crate) struct Cuda(libloading::Library); + +impl Cuda { + #[cfg(not(windows))] + const CUDA_PATH: &'static str = "/usr/lib/x86_64-linux-gnu/libcuda.so.1"; + #[cfg(windows)] + const CUDA_PATH: &'static str = "C:\\Windows\\System32\\nvcuda.dll"; + + fn load() -> Self { + unsafe { Self(libloading::Library::new(Self::CUDA_PATH).unwrap()) } + } +} + +macro_rules! implemented_test { + ($($abi:literal fn $fn_name:ident( $( $arg_id:ident : $arg_type:ty ),* ) -> $ret_type:ty;)* ) => { + pub(crate) trait CudaApi { + fn new() -> Self; + $( + #[allow(non_snake_case, dead_code)] + fn $fn_name(&self, $( $arg_id : $arg_type ),* ) { + paste::paste!{ self.[< $fn_name _unchecked >]( $( $arg_id ),* ) }.unwrap() + } + paste::paste!{ #[allow(non_snake_case, dead_code)] fn [< $fn_name _unchecked>](&self, $( $arg_id : $arg_type ),* ) -> $ret_type; } + )* + } + + + + impl CudaApi for Cuda { + fn new() -> Self { Self::load() } + $( + paste::paste!{ fn [< $fn_name _unchecked >](&self, $( $arg_id : $arg_type ),* ) -> $ret_type { + let func = unsafe { self.0.get:: $ret_type>(concat!(stringify!($fn_name), "\0").as_bytes()) }.unwrap(); + unsafe { (func)( $( $arg_id ),* ) } + }} + )* + } + + impl CudaApi for Zluda { + fn new() -> Self { Self } + $( + paste::paste!{ fn [< $fn_name _unchecked >](&self, $( $arg_id : $arg_type ),* ) -> $ret_type { + unsafe { super::$fn_name( $( $arg_id ),* ) } + }} + )* + } + }; +} +cuda_macros::cuda_function_declarations!(implemented_test); diff --git a/zluda/src/tests/mod.rs b/zluda/src/tests/mod.rs deleted file mode 100644 index 3f32c70..0000000 --- a/zluda/src/tests/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -use cuda_macros::generate_api_macro; -use cuda_tests::api_test; -use cuda_tests::cuda::*; - -generate_api_macro!(impl cuda_tests::cuda::Api for TestApi use implemented_test); -cuda_macros::cuda_function_declarations!(implemented_test); - -api_test!(init_check, TestApi);