#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
include!(concat!(env!("OUT_DIR"), "/types.rs"));
#[inline]
pub fn set_mem_location_id(loc: &mut CUmemLocation, id: ::core::ffi::c_int) {
#[cfg(cu_mem_location_anon_union)]
{
loc.__bindgen_anon_1.id = id;
}
#[cfg(not(cu_mem_location_anon_union))]
{
loc.id = id;
}
}
#[allow(dead_code)]
mod generated_cuda {
use super::*;
include!(concat!(env!("OUT_DIR"), "/cuda_driver_api.rs"));
}
#[allow(dead_code)]
mod generated_curand {
use super::*;
include!(concat!(env!("OUT_DIR"), "/curand_api.rs"));
}
mod dyn_load;
pub use dyn_load::*;
pub fn cuda_toolkit_dir() -> String {
env!("CUTILE_RESOLVED_CUDA_TOOLKIT_PATH").to_string()
}
pub const CU_HOST_TASK_BLOCKING: ::core::ffi::c_uint = 0;
pub const CU_HOST_TASK_SPINWAIT: ::core::ffi::c_uint = 1;
pub unsafe fn cu_launch_host_func(
stream: CUstream,
func: ::core::option::Option<unsafe extern "C" fn(*mut ::core::ffi::c_void)>,
arg: *mut ::core::ffi::c_void,
sync_mode: ::core::ffi::c_uint,
) -> CUresult {
#[cfg(cuda_has_cuLaunchHostFunc_v2)]
{
let v2_result = unsafe { cuLaunchHostFunc_v2(stream, func, arg, sync_mode) };
match host_func_v2_outcome(v2_result, sync_mode) {
HostFuncV2Outcome::Done(result) => result,
HostFuncV2Outcome::FallBackToV1 => unsafe { cuLaunchHostFunc(stream, func, arg) },
HostFuncV2Outcome::Unsupported => cudaError_enum_CUDA_ERROR_NOT_SUPPORTED,
}
}
#[cfg(not(cuda_has_cuLaunchHostFunc_v2))]
{
let _ = sync_mode;
unsafe { cuLaunchHostFunc(stream, func, arg) }
}
}
#[cfg_attr(not(cuda_has_cuLaunchHostFunc_v2), allow(dead_code))]
#[derive(Debug, PartialEq, Eq)]
enum HostFuncV2Outcome {
Done(CUresult),
FallBackToV1,
Unsupported,
}
#[cfg_attr(not(cuda_has_cuLaunchHostFunc_v2), allow(dead_code))]
fn host_func_v2_outcome(v2_result: CUresult, sync_mode: ::core::ffi::c_uint) -> HostFuncV2Outcome {
if v2_result != cudaError_enum_CUDA_ERROR_NOT_FOUND {
HostFuncV2Outcome::Done(v2_result)
} else if sync_mode == CU_HOST_TASK_BLOCKING {
HostFuncV2Outcome::FallBackToV1
} else {
HostFuncV2Outcome::Unsupported
}
}
#[cfg(test)]
mod host_func_dispatch_tests {
use super::*;
#[test]
fn driver_result_stands_when_the_v2_entry_point_exists() {
for code in [
cudaError_enum_CUDA_SUCCESS,
cudaError_enum_CUDA_ERROR_INVALID_HANDLE,
cudaError_enum_CUDA_ERROR_NOT_SUPPORTED,
] {
for mode in [CU_HOST_TASK_BLOCKING, CU_HOST_TASK_SPINWAIT] {
assert_eq!(
host_func_v2_outcome(code, mode),
HostFuncV2Outcome::Done(code),
"code {code} in mode {mode} must pass through untouched"
);
}
}
}
#[test]
fn missing_v2_symbol_falls_back_for_blocking_and_refuses_spinwait() {
assert_eq!(
host_func_v2_outcome(cudaError_enum_CUDA_ERROR_NOT_FOUND, CU_HOST_TASK_BLOCKING),
HostFuncV2Outcome::FallBackToV1
);
assert_eq!(
host_func_v2_outcome(cudaError_enum_CUDA_ERROR_NOT_FOUND, CU_HOST_TASK_SPINWAIT),
HostFuncV2Outcome::Unsupported
);
assert_eq!(
host_func_v2_outcome(cudaError_enum_CUDA_ERROR_NOT_FOUND, 7),
HostFuncV2Outcome::Unsupported
);
}
}
pub unsafe fn cu_event_elapsed_time(
elapsed_ms: *mut f32,
start: CUevent,
end: CUevent,
) -> CUresult {
#[cfg(cuda_has_cuEventElapsedTime_v2)]
{
unsafe { cuEventElapsedTime_v2(elapsed_ms, start, end) }
}
#[cfg(not(cuda_has_cuEventElapsedTime_v2))]
{
unsafe { cuEventElapsedTime(elapsed_ms, start, end) }
}
}
#[cfg(test)]
mod cuda_tests {
use super::*;
use std::ffi::{c_int, c_ulonglong};
use std::mem::MaybeUninit;
fn init() -> (CUdevice, CUcontext) {
unsafe {
let init_res = crate::cuInit(0);
assert_eq!(init_res, 0, "init failed");
let mut dev: MaybeUninit<crate::CUdevice> = MaybeUninit::uninit();
let dev_result = crate::cuDeviceGet(dev.as_mut_ptr(), 0 as c_int);
assert_eq!(dev_result, 0, "get device failed");
let dev = dev.assume_init();
let mut ctx = MaybeUninit::uninit();
let ctx_res = crate::cuDevicePrimaryCtxRetain(ctx.as_mut_ptr(), dev);
assert_eq!(ctx_res, 0, "retain context failed");
let ctx = ctx.assume_init();
assert_eq!(
crate::cuCtxSetCurrent(ctx),
0,
"failed to set current context"
);
(dev, ctx)
}
}
unsafe fn get_dptr(bytesize: usize) -> CUdeviceptr {
let mut dptr: MaybeUninit<CUdeviceptr> = MaybeUninit::uninit();
assert!(cuMemAlloc_v2(dptr.as_mut_ptr(), bytesize) == 0);
dptr.assume_init()
}
unsafe fn get_rng() -> curandGenerator_t {
let mut curand_gen_uninited: MaybeUninit<curandGenerator_t> = MaybeUninit::uninit();
let curand_rng_type = curandRngType_CURAND_RNG_PSEUDO_DEFAULT;
assert!(curandCreateGenerator(curand_gen_uninited.as_mut_ptr(), curand_rng_type) == 0);
curand_gen_uninited.assume_init()
}
unsafe fn set_seed(gen: curandGenerator_t, seed: u64) {
assert!(curandSetPseudoRandomGeneratorSeed(gen, c_ulonglong::from(seed)) == 0);
}
#[test]
fn cu_event_elapsed_time_helper_signature() {
let _: unsafe fn(*mut f32, CUevent, CUevent) -> CUresult = cu_event_elapsed_time;
}
#[test]
fn test_curand() {
unsafe {
let (_dev, _ctx) = init();
let curand_gen = get_rng();
set_seed(curand_gen, 123);
let num_elements = 32;
let bytesize = num_elements * size_of::<f32>();
let dptr = get_dptr(bytesize);
assert!(
curandGenerateNormal(curand_gen, dptr as *mut f32, num_elements, 0.0, 1.0) == 0
);
assert!(curandDestroyGenerator(curand_gen) == 0);
assert!(cuMemFree_v2(dptr) == 0);
}
}
}