Generate CUDA types ahead of time

This commit is contained in:
Andrzej Janik 2024-11-17 02:12:28 +00:00
parent 6d8819f2fa
commit fa94cdfc16
13 changed files with 8311 additions and 4840 deletions

View file

@ -1,24 +1,24 @@
[workspace]
resolver = "2"
members = [
"ext/hip_runtime-sys",
"ext/amd_comgr-sys",
"comgr",
"cuda_base",
"cuda_types",
"detours-sys",
"zluda",
"zluda_dump",
"zluda_lib",
"zluda_inject",
"zluda_redirect",
"zluda_ml",
"ptx",
"ptx_parser",
"ptx_parser_macros",
"ptx_parser_macros_impl",
]
default-members = ["zluda_lib", "zluda_ml", "zluda_inject", "zluda_redirect"]
[workspace]
resolver = "2"
members = [
"ext/hip_runtime-sys",
"ext/amd_comgr-sys",
"comgr",
"cuda_base",
"cuda_types",
"detours-sys",
"zluda",
"zluda_dump",
"zluda_inject",
"zluda_redirect",
"zluda_ml",
"ptx",
"ptx_parser",
"ptx_parser_macros",
"ptx_parser_macros_impl",
"zluda_bindgen",
]
default-members = ["zluda", "zluda_ml", "zluda_inject", "zluda_redirect"]

File diff suppressed because it is too large Load diff

View file

@ -2,13 +2,15 @@
name = "zluda"
version = "0.0.0"
authors = ["Andrzej Janik <vosen@vosen.pl>"]
edition = "2018"
edition = "2021"
[lib]
name = "zluda"
name = "nvcuda"
crate-type = ["cdylib"]
[dependencies]
ptx = { path = "../ptx" }
cuda_types = { path = "../cuda_types" }
hip_runtime-sys = { path = "../ext/hip_runtime-sys" }
lazy_static = "1.4"
num_enum = "0.4"
@ -16,12 +18,5 @@ lz4-sys = "1.9"
tempfile = "3"
paste = "1.0"
[dependencies.ocl-core]
version = "0.11"
features = ["opencl_version_1_2", "opencl_version_2_0", "opencl_version_2_1"]
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["heapapi", "std"] }
[dev-dependencies]
cuda-driver-sys = "0.3.0"

View file

@ -1,20 +0,0 @@
use env::VarError;
use std::{env, path::PathBuf};
// HACK ALERT
// This is a temporary hack to to make sure that linker does not pick up
// NVIDIA OpenCL .lib using paths injected by cl-sys
fn main() -> Result<(), VarError> {
if cfg!(windows) {
let env = env::var("CARGO_CFG_TARGET_ENV")?;
if env == "msvc" {
let mut path = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?);
path.push("lib");
println!("cargo:rustc-link-search=native={}", path.display());
} else {
println!("cargo:rustc-link-search=native=C:\\Windows\\System32");
};
}
Ok(())
}

File diff suppressed because it is too large Load diff

View file

@ -1,53 +1,41 @@
use std::{ffi::c_void, mem, ptr};
use hip_runtime_sys::{hipError_t, hipMemoryType, hipPointerGetAttributes};
use crate::{
cuda::{CUdeviceptr, CUmemorytype, CUpointer_attribute},
hip_call,
};
use cuda_types::*;
use hip_runtime_sys::*;
use std::{ffi::c_void, ptr};
pub(crate) unsafe fn get_attribute(
data: *mut c_void,
attribute: CUpointer_attribute,
ptr: CUdeviceptr,
) -> Result<(), hipError_t> {
attribute: hipPointer_attribute,
ptr: hipDeviceptr_t,
) -> CUresult {
if data == ptr::null_mut() {
return Err(hipError_t::hipErrorInvalidValue);
return CUresult::ERROR_INVALID_VALUE;
}
let mut attribs = mem::zeroed();
hip_call! { hipPointerGetAttributes(&mut attribs, ptr.0 as _) };
match attribute {
CUpointer_attribute::CU_POINTER_ATTRIBUTE_CONTEXT => {
*(data as *mut _) = attribs.device;
Ok(())
}
CUpointer_attribute::CU_POINTER_ATTRIBUTE_MEMORY_TYPE => {
*(data as *mut _) = memory_type(attribs.memoryType)?;
Ok(())
}
CUpointer_attribute::CU_POINTER_ATTRIBUTE_DEVICE_POINTER => {
*(data as *mut _) = attribs.devicePointer;
Ok(())
}
CUpointer_attribute::CU_POINTER_ATTRIBUTE_HOST_POINTER => {
*(data as *mut _) = attribs.hostPointer;
Ok(())
}
CUpointer_attribute::CU_POINTER_ATTRIBUTE_IS_MANAGED => {
*(data as *mut _) = attribs.isManaged;
Ok(())
}
_ => Err(hipError_t::hipErrorNotSupported),
// TODO: implement by getting device ordinal & allocation start,
// then go through every context for that device
if attribute == hipPointer_attribute::HIP_POINTER_ATTRIBUTE_CONTEXT {
return CUresult::ERROR_NOT_SUPPORTED;
}
if attribute == hipPointer_attribute::HIP_POINTER_ATTRIBUTE_MEMORY_TYPE {
let mut hip_result = hipMemoryType(0);
hipPointerGetAttribute(
(&mut hip_result as *mut hipMemoryType).cast::<c_void>(),
attribute,
ptr,
)?;
let cuda_result = memory_type(hip_result)?;
*(data as _) = cuda_result;
} else {
hipPointerGetAttribute(data, attribute, ptr)?;
}
Ok(())
}
pub(crate) fn memory_type(cu: hipMemoryType) -> Result<CUmemorytype, hipError_t> {
fn memory_type(cu: hipMemoryType) -> Result<CUmemorytype, hipErrorCode_t> {
match cu {
hipMemoryType::hipMemoryTypeHost => Ok(CUmemorytype::CU_MEMORYTYPE_HOST),
hipMemoryType::hipMemoryTypeDevice => Ok(CUmemorytype::CU_MEMORYTYPE_DEVICE),
hipMemoryType::hipMemoryTypeArray => Ok(CUmemorytype::CU_MEMORYTYPE_ARRAY),
hipMemoryType::hipMemoryTypeUnified => Ok(CUmemorytype::CU_MEMORYTYPE_UNIFIED),
_ => Err(hipError_t::hipErrorInvalidValue),
_ => Err(hipErrorCode_t::hipErrorInvalidValue),
}
}

View file

@ -1,9 +1,7 @@
#[macro_use]
extern crate lazy_static;
#[cfg(test)]
extern crate cuda_driver_sys;
#[cfg(test)]
#[macro_use]
extern crate paste;
extern crate ptx;

11
zluda_bindgen/Cargo.toml Normal file
View file

@ -0,0 +1,11 @@
[package]
name = "zluda_bindgen"
version = "0.1.0"
edition = "2021"
[dependencies]
bindgen = "0.70"
syn = { version = "2.0", features = ["full", "visit-mut"] }
proc-macro2 = "1.0.89"
quote = "1.0"
prettyplease = "0.2.25"

View file

@ -0,0 +1,7 @@
#define __CUDA_API_VERSION_INTERNAL
#include <cuda.h>
#include <cudaProfiler.h>
#include <cudaGL.h>
#include <cudaEGL.h>
#include <vdpau/vdpau.h>
#include <cudaVDPAU.h>

156
zluda_bindgen/src/main.rs Normal file
View file

@ -0,0 +1,156 @@
use proc_macro2::Span;
use quote::{format_ident, quote};
use std::{path::PathBuf, str::FromStr};
use syn::{
parse_quote, punctuated::Punctuated, visit_mut::VisitMut, Abi, Item, ItemUse, LitStr, UseTree,
};
fn main() {
let crate_root = PathBuf::from_str(env!("CARGO_MANIFEST_DIR")).unwrap();
let cuda_header = bindgen::Builder::default()
.use_core()
.header_contents("cuda_wrapper.h", include_str!("../build/cuda_wrapper.h"))
.no_partialeq("CUDA_HOST_NODE_PARAMS_st")
.derive_eq(true)
.allowlist_type("^CU.*")
.allowlist_function("^cu.*")
.allowlist_var("^CU.*")
.default_enum_style(bindgen::EnumVariation::NewType {
is_bitfield: false,
is_global: false,
})
.layout_tests(false)
.new_type_alias(r"^CUdevice_v\d+$")
.new_type_alias(r"^CUdeviceptr_v\d+$")
.must_use_type("cudaError_enum")
.constified_enum("cudaError_enum")
.clang_args(["-I/usr/local/cuda/include"])
.generate()
.unwrap()
.to_string();
generate_types(
crate_root,
&["..", "cuda_types", "src", "lib.rs"],
cuda_header,
);
}
fn generate_types(mut output: PathBuf, path: &[&str], cuda_header: String) {
let mut module: syn::File = syn::parse_str(&cuda_header).unwrap();
module.attrs.push(parse_quote! {
#![allow(warnings)]
});
let mut converter = ConvertIntoRustResult {
type_: "CUresult",
underlying_type: "cudaError_enum",
new_error_type: "CUerror",
error_prefix: ("CUDA_ERROR", "ERROR"),
success: ("CUDA_SUCCESS", "SUCCESS"),
constants: Vec::new(),
};
module.items = module
.items
.into_iter()
.filter_map(|item| match item {
Item::ForeignMod(_) => None,
Item::Const(const_) => converter.get_const(const_).map(Item::Const),
Item::Use(use_) => converter.get_use(use_).map(Item::Use),
item => Some(item),
})
.collect::<Vec<_>>();
converter.flush(&mut module.items);
syn::visit_mut::visit_file_mut(&mut FixAbi, &mut module);
for segment in path {
output.push(segment);
}
std::fs::write(output, prettyplease::unparse(&module)).unwrap();
}
struct ConvertIntoRustResult {
type_: &'static str,
underlying_type: &'static str,
new_error_type: &'static str,
error_prefix: (&'static str, &'static str),
success: (&'static str, &'static str),
constants: Vec<syn::ItemConst>,
}
impl ConvertIntoRustResult {
fn get_const(&mut self, const_: syn::ItemConst) -> Option<syn::ItemConst> {
let name = const_.ident.to_string();
if name.starts_with(self.underlying_type) {
self.constants.push(const_);
None
} else {
Some(const_)
}
}
fn get_use(&mut self, use_: ItemUse) -> Option<ItemUse> {
if let UseTree::Path(ref path) = use_.tree {
if let UseTree::Rename(ref rename) = &*path.tree {
if rename.rename == self.type_ {
return None;
}
}
}
Some(use_)
}
fn flush(self, items: &mut Vec<Item>) {
let type_ = format_ident!("{}", self.type_);
let type_trait = format_ident!("{}Consts", self.type_);
let new_error_type = format_ident!("{}", self.new_error_type);
let success = format_ident!("{}", self.success.1);
let mut result_variants = Vec::new();
let mut error_variants = Vec::new();
for const_ in self.constants.iter() {
let ident = const_.ident.to_string();
if ident.ends_with(self.success.0) {
result_variants.push(quote! {
const #success: #type_ = #type_::Ok(());
});
} else {
let old_prefix_len = self.underlying_type.len() + 1 + self.error_prefix.0.len() + 1;
let variant_ident =
format_ident!("{}_{}", self.error_prefix.1, &ident[old_prefix_len..]);
let error_ident = format_ident!("{}", &ident[old_prefix_len..]);
let expr = &const_.expr;
result_variants.push(quote! {
const #variant_ident: #type_ = #type_::Err(#new_error_type::#error_ident);
});
error_variants.push(quote! {
pub const #error_ident: #new_error_type = #new_error_type(unsafe { ::core::num::NonZeroU32::new_unchecked(#expr) });
});
}
}
let extra_items: Punctuated<syn::Item, syn::parse::Nothing> = parse_quote! {
impl #new_error_type {
#(#error_variants)*
}
#[repr(transparent)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct #new_error_type(pub ::core::num::NonZeroU32);
pub trait #type_trait {
#(#result_variants)*
}
impl #type_trait for #type_ {}
#[must_use]
pub type #type_ = ::core::result::Result<(), #new_error_type>;
const _: fn() = || {
let _ = std::mem::transmute::<#type_, u32>;
};
};
items.extend(extra_items);
}
}
struct FixAbi;
impl VisitMut for FixAbi {
fn visit_abi_mut(&mut self, i: &mut Abi) {
if let Some(ref mut name) = i.name {
*name = LitStr::new("system", Span::call_site());
}
}
}

View file

@ -1,12 +0,0 @@
[package]
name = "zluda_lib"
version = "0.0.0"
authors = ["Andrzej Janik <vosen@vosen.pl>"]
edition = "2018"
[lib]
name = "nvcuda"
crate-type = ["cdylib"]
[dependencies]
zluda = { path = "../zluda" }

View file

@ -1 +0,0 @@
This project exist solely as a workaround, to make sure that ZLUDA-created CUDA driver does not clash with real CUDA driver when running unit tests

View file

@ -1,11 +0,0 @@
pub extern crate zluda;
pub use zluda::cuda::*;
// For some reason, on Linux linker strips out all our re-exports,
// there's probably a cleaner solution, but for now just exporting
// the function below stops it from doing so
#[no_mangle]
fn _zluda_very_bad_linker_hack() {
cuInit(0);
}