pub use super::sys;
use core::ffi::{CStr, c_int, c_uint, c_void};
pub struct HipError(pub sys::hipError_t);
impl sys::hipError_t {
#[inline]
pub fn result(self) -> Result<(), HipError> {
match self {
sys::hipError_t::hipSuccess => Ok(()),
_ => Err(HipError(self)),
}
}
}
impl HipError {
pub fn error_name(&self) -> &'static CStr {
unsafe { CStr::from_ptr(sys::hipGetErrorName(self.0)) }
}
pub fn error_string(&self) -> &'static CStr {
unsafe { CStr::from_ptr(sys::hipGetErrorString(self.0)) }
}
}
impl std::fmt::Debug for HipError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("HipError")
.field(&self.0)
.field(&self.error_string())
.finish()
}
}
impl std::fmt::Display for HipError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{self:?}")
}
}
impl std::error::Error for HipError {}
pub fn init() -> Result<(), HipError> {
unsafe { sys::hipInit(0).result() }
}
pub mod version {
use super::{
HipError,
sys::{self},
};
use core::ffi::c_int;
pub fn driver() -> Result<i32, HipError> {
let mut v: c_int = 0;
unsafe { sys::hipDriverGetVersion(&mut v).result()? };
Ok(v)
}
pub fn runtime() -> Result<i32, HipError> {
let mut v: c_int = 0;
unsafe { sys::hipRuntimeGetVersion(&mut v).result()? };
Ok(v)
}
}
pub mod device {
use super::{
HipError,
sys::{self},
};
use core::ffi::{CStr, c_int, c_uint};
use core::mem::MaybeUninit;
use std::string::String;
pub fn get(ordinal: c_int) -> Result<sys::hipDevice_t, HipError> {
let mut dev: sys::hipDevice_t = 0;
unsafe { sys::hipDeviceGet(&mut dev, ordinal).result()? };
Ok(dev)
}
pub fn get_device(ordinal: *mut i32) -> Result<(), HipError> {
unsafe { sys::hipGetDevice(ordinal).result() }
}
pub fn set_device(ordinal: c_int) -> Result<(), HipError> {
unsafe { sys::hipSetDevice(ordinal).result() }
}
pub fn synchronize() -> Result<(), HipError> {
unsafe { sys::hipDeviceSynchronize().result() }
}
pub fn get_cache_config() -> Result<sys::hipFuncCache_t, HipError> {
let mut config = sys::hipFuncCache_t::hipFuncCachePreferNone;
unsafe { sys::hipDeviceGetCacheConfig(&mut config).result()? };
Ok(config)
}
pub fn set_cache_config(config: sys::hipFuncCache_t) -> Result<(), HipError> {
unsafe { sys::hipDeviceSetCacheConfig(config).result() }
}
pub fn get_count() -> Result<c_int, HipError> {
let mut n: c_int = 0;
unsafe { sys::hipGetDeviceCount(&mut n).result()? };
Ok(n)
}
pub fn total_mem(dev: sys::hipDevice_t) -> Result<usize, HipError> {
let mut bytes: usize = 0;
unsafe { sys::hipDeviceTotalMem(&mut bytes, dev).result()? };
Ok(bytes)
}
pub fn get_attribute(
dev: sys::hipDevice_t,
attr: sys::hipDeviceAttribute_t,
) -> Result<i32, HipError> {
let mut val: c_int = 0;
unsafe { sys::hipDeviceGetAttribute(&mut val, attr, dev).result()? };
Ok(val)
}
pub fn get_name(dev: sys::hipDevice_t) -> Result<String, HipError> {
let mut buf = [0 as core::ffi::c_char; 256];
unsafe { sys::hipDeviceGetName(buf.as_mut_ptr(), buf.len() as c_int, dev).result()? };
let cstr = unsafe { CStr::from_ptr(buf.as_ptr()) };
Ok(cstr.to_string_lossy().into_owned())
}
pub fn get_uuid(dev: sys::hipDevice_t) -> Result<sys::hipUUID, HipError> {
let mut uuid = MaybeUninit::uninit();
unsafe { sys::hipDeviceGetUuid(uuid.as_mut_ptr(), dev).result()? };
Ok(unsafe { uuid.assume_init() })
}
pub fn get_default_mem_pool(dev: sys::hipDevice_t) -> Result<sys::hipMemPool_t, HipError> {
let mut mem_pool: sys::hipMemPool_t = std::ptr::null_mut();
unsafe { sys::hipDeviceGetDefaultMemPool(&mut mem_pool, dev).result()? };
Ok(mem_pool)
}
pub fn get_mem_pool(dev: sys::hipDevice_t) -> Result<sys::hipMemPool_t, HipError> {
let mut mem_pool: sys::hipMemPool_t = std::ptr::null_mut();
unsafe { sys::hipDeviceGetMemPool(&mut mem_pool, dev).result()? };
Ok(mem_pool)
}
pub fn set_mem_pool(
dev: sys::hipDevice_t,
mem_pool: sys::hipMemPool_t,
) -> Result<(), HipError> {
unsafe { sys::hipDeviceSetMemPool(dev, mem_pool).result() }
}
pub fn get_limit(limit: sys::hipLimit_t) -> Result<usize, HipError> {
let mut value: usize = 0;
unsafe { sys::hipDeviceGetLimit(&mut value, limit).result()? };
Ok(value)
}
pub fn set_limit(limit: sys::hipLimit_t, value: usize) -> Result<(), HipError> {
unsafe { sys::hipDeviceSetLimit(limit, value).result() }
}
pub fn current() -> Result<c_int, HipError> {
let mut ordinal: c_int = 0;
unsafe { sys::hipGetDevice(&mut ordinal).result()? };
Ok(ordinal)
}
pub unsafe fn reset() -> Result<(), HipError> {
unsafe { sys::hipDeviceReset().result() }
}
pub fn get_properties(ordinal: c_int) -> Result<sys::hipDeviceProp_tR0600, HipError> {
let mut prop = MaybeUninit::uninit();
unsafe { sys::hipGetDevicePropertiesR0600(prop.as_mut_ptr(), ordinal).result()? };
Ok(unsafe { prop.assume_init() })
}
pub fn enable_peer_access(peer_id: c_int, flags: c_uint) -> Result<(), HipError> {
unsafe { sys::hipDeviceEnablePeerAccess(peer_id, flags).result()? };
Ok(())
}
pub fn can_access_peer(device_id: c_int, peer_id: c_int) -> Result<bool, HipError> {
let mut can_access: i32 = 0;
unsafe { sys::hipDeviceCanAccessPeer(&mut can_access, device_id, peer_id).result()? };
Ok(can_access != 0)
}
}
pub mod function {
use super::{
HipError,
sys::{self, hipFunction_attribute},
};
use core::ffi::c_int;
pub fn get_function_attribute(
f: sys::hipFunction_t,
attribute: hipFunction_attribute,
) -> Result<i32, HipError> {
let mut value: c_int = 0;
unsafe { sys::hipFuncGetAttribute(&mut value, attribute, f).result()? };
Ok(value)
}
}
pub mod occupancy {
use super::{
HipError,
sys::{self},
};
use core::ffi::{c_int, c_uint, c_void};
pub fn max_active_blocks_per_multiprocessor(
f: sys::hipFunction_t,
block_size: c_int,
dynamic_smem_bytes: usize,
) -> Result<i32, HipError> {
let mut n: c_int = 0;
unsafe {
sys::hipModuleOccupancyMaxActiveBlocksPerMultiprocessor(
&mut n,
f,
block_size,
dynamic_smem_bytes,
)
.result()?
};
Ok(n)
}
pub fn max_active_blocks_per_multiprocessor_with_flags(
f: sys::hipFunction_t,
block_size: c_int,
dynamic_smem_bytes: usize,
flags: c_uint,
) -> Result<i32, HipError> {
let mut n: c_int = 0;
unsafe {
sys::hipModuleOccupancyMaxActiveBlocksPerMultiprocessorWithFlags(
&mut n,
f,
block_size,
dynamic_smem_bytes,
flags,
)
.result()?
};
Ok(n)
}
pub fn max_potential_block_size(
f: sys::hipFunction_t,
dynamic_smem_bytes: usize,
block_size_limit: c_int,
) -> Result<(i32, i32), HipError> {
let mut grid: c_int = 0;
let mut block: c_int = 0;
unsafe {
sys::hipModuleOccupancyMaxPotentialBlockSize(
&mut grid,
&mut block,
f,
dynamic_smem_bytes,
block_size_limit,
)
.result()?
};
Ok((grid, block))
}
pub fn max_potential_block_size_with_flags(
f: sys::hipFunction_t,
dynamic_smem_bytes: usize,
block_size_limit: c_int,
flags: c_uint,
) -> Result<(i32, i32), HipError> {
let mut grid: c_int = 0;
let mut block: c_int = 0;
unsafe {
sys::hipModuleOccupancyMaxPotentialBlockSizeWithFlags(
&mut grid,
&mut block,
f,
dynamic_smem_bytes,
block_size_limit,
flags,
)
.result()?
};
Ok((grid, block))
}
pub unsafe fn available_dynamic_shared_mem_per_block(
f: *const c_void,
num_blocks: c_int,
block_size: c_int,
) -> Result<usize, HipError> {
let mut bytes: usize = 0;
unsafe {
sys::hipOccupancyAvailableDynamicSMemPerBlock(&mut bytes, f, num_blocks, block_size)
.result()?
};
Ok(bytes)
}
}
pub mod stream {
use super::{
HipError,
sys::{self},
};
use core::ffi::{c_int, c_uint};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StreamKind {
Default,
NonBlocking,
}
impl StreamKind {
#[inline]
pub fn to_raw(self) -> c_uint {
match self {
Self::Default => 0x0,
Self::NonBlocking => 0x1,
}
}
}
pub fn create(kind: StreamKind) -> Result<sys::hipStream_t, HipError> {
let mut s: sys::hipStream_t = std::ptr::null_mut();
unsafe { sys::hipStreamCreateWithFlags(&mut s, kind.to_raw()).result()? };
Ok(s)
}
pub fn create_with_priority(
kind: StreamKind,
priority: c_int,
) -> Result<sys::hipStream_t, HipError> {
let mut s: sys::hipStream_t = std::ptr::null_mut();
unsafe { sys::hipStreamCreateWithPriority(&mut s, kind.to_raw(), priority).result()? };
Ok(s)
}
pub fn destroy(s: sys::hipStream_t) -> Result<(), HipError> {
unsafe { sys::hipStreamDestroy(s).result() }
}
pub fn synchronize(s: sys::hipStream_t) -> Result<(), HipError> {
unsafe { sys::hipStreamSynchronize(s).result() }
}
pub unsafe fn wait_event(
s: sys::hipStream_t,
event: sys::hipEvent_t,
flags: c_uint,
) -> Result<(), HipError> {
unsafe { sys::hipStreamWaitEvent(s, event, flags).result() }
}
pub fn query(s: sys::hipStream_t) -> Result<bool, HipError> {
match unsafe { sys::hipStreamQuery(s) } {
sys::hipError_t::hipSuccess => Ok(true),
sys::hipError_t::hipErrorNotReady => Ok(false),
e => Err(HipError(e)),
}
}
pub fn get_flags(s: sys::hipStream_t) -> Result<c_uint, HipError> {
let mut flags: c_uint = 0;
unsafe { sys::hipStreamGetFlags(s, &mut flags).result()? };
Ok(flags)
}
pub fn get_priority(s: sys::hipStream_t) -> Result<c_int, HipError> {
let mut p: c_int = 0;
unsafe { sys::hipStreamGetPriority(s, &mut p).result()? };
Ok(p)
}
pub unsafe fn begin_capture(
s: sys::hipStream_t,
mode: sys::hipStreamCaptureMode,
) -> Result<(), HipError> {
unsafe { sys::hipStreamBeginCapture(s, mode).result() }
}
pub unsafe fn end_capture(s: sys::hipStream_t) -> Result<sys::hipGraph_t, HipError> {
let mut graph: sys::hipGraph_t = std::ptr::null_mut();
unsafe { sys::hipStreamEndCapture(s, &mut graph).result()? };
Ok(graph)
}
pub unsafe fn is_capturing(
s: sys::hipStream_t,
) -> Result<sys::hipStreamCaptureStatus, HipError> {
let mut status = sys::hipStreamCaptureStatus::hipStreamCaptureStatusNone;
unsafe { sys::hipStreamIsCapturing(s, &mut status).result()? };
Ok(status)
}
pub unsafe fn attach_mem_async(
s: sys::hipStream_t,
dev_ptr: u64,
length: usize,
flags: c_uint,
) -> Result<(), HipError> {
unsafe {
sys::hipStreamAttachMemAsync(s, dev_ptr as *mut core::ffi::c_void, length, flags)
.result()
}
}
}
pub fn malloc_sync(num_bytes: usize) -> Result<u64, HipError> {
let mut p: *mut c_void = std::ptr::null_mut();
unsafe { sys::hipMalloc(&mut p, num_bytes).result()? };
Ok(p as u64)
}
pub fn malloc_async(num_bytes: usize, stream: sys::hipStream_t) -> Result<u64, HipError> {
let mut p: *mut c_void = std::ptr::null_mut();
unsafe { sys::hipMallocAsync(&mut p, num_bytes, stream).result()? };
Ok(p as u64)
}
pub fn malloc_managed(num_bytes: usize, flags: c_uint) -> Result<u64, HipError> {
let mut p: *mut c_void = std::ptr::null_mut();
unsafe { sys::hipMallocManaged(&mut p, num_bytes, flags).result()? };
Ok(p as u64)
}
pub fn malloc_host(num_bytes: usize, flags: c_uint) -> Result<*mut c_void, HipError> {
let mut p: *mut c_void = std::ptr::null_mut();
unsafe { sys::hipHostMalloc(&mut p, num_bytes, flags).result()? };
Ok(p)
}
pub fn free_host(ptr: *mut c_void) -> Result<(), HipError> {
unsafe { sys::hipHostFree(ptr).result() }
}
pub fn free_sync(ptr: u64) -> Result<(), HipError> {
unsafe { sys::hipFree(ptr as *mut c_void).result() }
}
pub fn free_async(ptr: u64, stream: sys::hipStream_t) -> Result<(), HipError> {
unsafe { sys::hipFreeAsync(ptr as *mut c_void, stream).result() }
}
pub unsafe fn mem_advise(
ptr: u64,
bytes: usize,
advice: sys::hipMemoryAdvise,
device: c_int,
) -> Result<(), HipError> {
unsafe { sys::hipMemAdvise(ptr as *const c_void, bytes, advice, device).result() }
}
pub unsafe fn mem_prefetch_async(
ptr: u64,
bytes: usize,
device: c_int,
stream: sys::hipStream_t,
) -> Result<(), HipError> {
unsafe { sys::hipMemPrefetchAsync(ptr as *const c_void, bytes, device, stream).result() }
}
pub fn mem_get_info() -> Result<(usize, usize), HipError> {
let mut free: usize = 0;
let mut total: usize = 0;
unsafe { sys::hipMemGetInfo(&mut free, &mut total).result()? };
Ok((free, total))
}
pub unsafe fn memset_d8_sync(ptr: u64, value: u8, bytes: usize) -> Result<(), HipError> {
unsafe { sys::hipMemsetD8(ptr as sys::hipDeviceptr_t, value, bytes).result() }
}
pub unsafe fn memset_d8_async(
ptr: u64,
value: u8,
bytes: usize,
stream: sys::hipStream_t,
) -> Result<(), HipError> {
unsafe { sys::hipMemsetD8Async(ptr as sys::hipDeviceptr_t, value, bytes, stream).result() }
}
pub unsafe fn memcpy_htod_sync(dst: u64, src: &[u8]) -> Result<(), HipError> {
unsafe {
sys::hipMemcpyHtoD(
dst as sys::hipDeviceptr_t,
src.as_ptr() as *const c_void,
src.len(),
)
.result()
}
}
pub unsafe fn memcpy_htod_async(
dst: u64,
src: &[u8],
stream: sys::hipStream_t,
) -> Result<(), HipError> {
unsafe {
sys::hipMemcpyHtoDAsync(
dst as sys::hipDeviceptr_t,
src.as_ptr() as *const c_void,
src.len(),
stream,
)
.result()
}
}
pub unsafe fn memcpy_dtoh_sync(dst: &mut [u8], src: u64) -> Result<(), HipError> {
unsafe {
sys::hipMemcpyDtoH(
dst.as_mut_ptr() as *mut c_void,
src as sys::hipDeviceptr_t,
dst.len(),
)
.result()
}
}
pub unsafe fn memcpy_dtoh_async(
dst: &mut [u8],
src: u64,
stream: sys::hipStream_t,
) -> Result<(), HipError> {
unsafe {
sys::hipMemcpyDtoHAsync(
dst.as_mut_ptr() as *mut c_void,
src as sys::hipDeviceptr_t,
dst.len(),
stream,
)
.result()
}
}
pub unsafe fn memcpy_dtod_sync(dst: u64, src: u64, bytes: usize) -> Result<(), HipError> {
unsafe {
sys::hipMemcpyDtoD(
dst as sys::hipDeviceptr_t,
src as sys::hipDeviceptr_t,
bytes,
)
.result()
}
}
pub unsafe fn memcpy_dtod_async(
dst: u64,
src: u64,
bytes: usize,
stream: sys::hipStream_t,
) -> Result<(), HipError> {
unsafe {
sys::hipMemcpyDtoDAsync(
dst as sys::hipDeviceptr_t,
src as sys::hipDeviceptr_t,
bytes,
stream,
)
.result()
}
}
pub unsafe fn memcpy_peer_async(
dst: u64,
dst_device: c_int,
src: u64,
src_device: c_int,
bytes: usize,
stream: sys::hipStream_t,
) -> Result<(), HipError> {
unsafe {
sys::hipMemcpyPeerAsync(
dst as *mut c_void,
dst_device,
src as *const c_void,
src_device,
bytes,
stream,
)
.result()
}
}
pub mod module {
use super::{
HipError,
sys::{self},
};
use core::ffi::{CStr, c_void};
pub unsafe fn load_data(image: &[u8]) -> Result<sys::hipModule_t, HipError> {
let mut m: sys::hipModule_t = std::ptr::null_mut();
unsafe { sys::hipModuleLoadData(&mut m, image.as_ptr() as *const c_void).result()? };
Ok(m)
}
pub unsafe fn unload(m: sys::hipModule_t) -> Result<(), HipError> {
unsafe { sys::hipModuleUnload(m).result() }
}
pub fn get_function(m: sys::hipModule_t, name: &CStr) -> Result<sys::hipFunction_t, HipError> {
let mut f: sys::hipFunction_t = std::ptr::null_mut();
unsafe { sys::hipModuleGetFunction(&mut f, m, name.as_ptr()).result()? };
Ok(f)
}
pub fn get_global(m: sys::hipModule_t, name: &CStr) -> Result<(u64, usize), HipError> {
let mut ptr: sys::hipDeviceptr_t = 0 as sys::hipDeviceptr_t;
let mut size: usize = 0;
unsafe { sys::hipModuleGetGlobal(&mut ptr, &mut size, m, name.as_ptr()).result()? };
Ok((ptr as u64, size))
}
}
pub mod event {
use super::{
HipError,
sys::{self},
};
use core::ffi::c_uint;
pub fn create() -> Result<sys::hipEvent_t, HipError> {
let mut e: sys::hipEvent_t = std::ptr::null_mut();
unsafe { sys::hipEventCreate(&mut e).result()? };
Ok(e)
}
pub fn create_with_flags(flags: c_uint) -> Result<sys::hipEvent_t, HipError> {
let mut e: sys::hipEvent_t = std::ptr::null_mut();
unsafe { sys::hipEventCreateWithFlags(&mut e, flags).result()? };
Ok(e)
}
pub fn destroy(e: sys::hipEvent_t) -> Result<(), HipError> {
unsafe { sys::hipEventDestroy(e).result() }
}
pub fn record(e: sys::hipEvent_t, stream: sys::hipStream_t) -> Result<(), HipError> {
unsafe { sys::hipEventRecord(e, stream).result() }
}
pub fn record_with_flags(
e: sys::hipEvent_t,
stream: sys::hipStream_t,
flags: c_uint,
) -> Result<(), HipError> {
unsafe { sys::hipEventRecordWithFlags(e, stream, flags).result() }
}
pub fn synchronize(e: sys::hipEvent_t) -> Result<(), HipError> {
unsafe { sys::hipEventSynchronize(e).result() }
}
pub fn query(e: sys::hipEvent_t) -> Result<bool, HipError> {
match unsafe { sys::hipEventQuery(e) } {
sys::hipError_t::hipSuccess => Ok(true),
sys::hipError_t::hipErrorNotReady => Ok(false),
err => Err(HipError(err)),
}
}
pub fn elapsed(start: sys::hipEvent_t, stop: sys::hipEvent_t) -> Result<f32, HipError> {
let mut ms: f32 = 0.0;
unsafe { sys::hipEventElapsedTime(&mut ms, start, stop).result()? };
Ok(ms)
}
}
pub unsafe fn launch_kernel(
f: sys::hipFunction_t,
grid: (u32, u32, u32),
block: (u32, u32, u32),
shared_mem: u32,
stream: sys::hipStream_t,
params: &mut [*mut c_void],
) -> Result<(), HipError> {
unsafe {
sys::hipModuleLaunchKernel(
f,
grid.0,
grid.1,
grid.2,
block.0,
block.1,
block.2,
shared_mem,
stream,
params.as_mut_ptr(),
std::ptr::null_mut(),
)
.result()
}
}
pub unsafe fn launch_cooperative_kernel(
f: sys::hipFunction_t,
grid: (u32, u32, u32),
block: (u32, u32, u32),
shared_mem: u32,
stream: sys::hipStream_t,
params: &mut [*mut c_void],
) -> Result<(), HipError> {
unsafe {
sys::hipModuleLaunchCooperativeKernel(
f,
grid.0,
grid.1,
grid.2,
block.0,
block.1,
block.2,
shared_mem,
stream,
params.as_mut_ptr(),
)
.result()
}
}
pub mod external_memory {
use super::{
HipError,
sys::{self},
};
use core::mem::MaybeUninit;
#[cfg(unix)]
pub unsafe fn import_external_memory_opaque_fd(
fd: std::os::fd::RawFd,
size: u64,
) -> Result<sys::hipExternalMemory_t, HipError> {
let mut external_memory = MaybeUninit::uninit();
let handle_description = sys::hipExternalMemoryHandleDesc_st {
type_: sys::hipExternalMemoryHandleType::hipExternalMemoryHandleTypeOpaqueFd,
handle: sys::hipExternalMemoryHandleDesc_st__bindgen_ty_1 { fd },
size,
flags: 0,
reserved: [0; 16],
};
unsafe {
sys::hipImportExternalMemory(external_memory.as_mut_ptr(), &handle_description)
.result()?
};
Ok(unsafe { external_memory.assume_init() })
}
#[cfg(windows)]
pub unsafe fn import_external_memory_opaque_win32(
handle: std::os::windows::io::RawHandle,
size: u64,
) -> Result<sys::hipExternalMemory_t, HipError> {
let mut external_memory = MaybeUninit::uninit();
let handle_description = sys::hipExternalMemoryHandleDesc_st {
type_: sys::hipExternalMemoryHandleType::hipExternalMemoryHandleTypeOpaqueWin32,
handle: sys::hipExternalMemoryHandleDesc_st__bindgen_ty_1 {
win32: sys::hipExternalMemoryHandleDesc_st__bindgen_ty_1__bindgen_ty_1 {
handle,
name: std::ptr::null(),
},
},
size,
flags: 0,
reserved: [0; 16],
};
unsafe {
sys::hipImportExternalMemory(external_memory.as_mut_ptr(), &handle_description)
.result()?
};
Ok(unsafe { external_memory.assume_init() })
}
pub unsafe fn destroy_external_memory(
external_memory: sys::hipExternalMemory_t,
) -> Result<(), HipError> {
unsafe { sys::hipDestroyExternalMemory(external_memory).result() }
}
pub unsafe fn get_mapped_buffer(
external_memory: sys::hipExternalMemory_t,
offset: u64,
size: u64,
) -> Result<u64, HipError> {
let mut device_ptr: *mut core::ffi::c_void = std::ptr::null_mut();
let buffer_description = sys::hipExternalMemoryBufferDesc_st {
offset,
size,
flags: 0,
reserved: [0; 16],
};
unsafe {
sys::hipExternalMemoryGetMappedBuffer(
&mut device_ptr,
external_memory,
&buffer_description,
)
.result()?
};
Ok(device_ptr as u64)
}
}
pub mod graph {
use super::{
HipError,
sys::{self},
};
use core::ffi::c_ulonglong;
pub unsafe fn destroy(graph: sys::hipGraph_t) -> Result<(), HipError> {
unsafe { sys::hipGraphDestroy(graph).result() }
}
pub unsafe fn exec_destroy(exec: sys::hipGraphExec_t) -> Result<(), HipError> {
unsafe { sys::hipGraphExecDestroy(exec).result() }
}
pub unsafe fn instantiate(
graph: sys::hipGraph_t,
flags: sys::hipGraphInstantiateFlags,
) -> Result<sys::hipGraphExec_t, HipError> {
let mut exec: sys::hipGraphExec_t = std::ptr::null_mut();
unsafe {
sys::hipGraphInstantiateWithFlags(&mut exec, graph, flags as c_ulonglong).result()?
};
Ok(exec)
}
pub unsafe fn launch(
exec: sys::hipGraphExec_t,
stream: sys::hipStream_t,
) -> Result<(), HipError> {
unsafe { sys::hipGraphLaunch(exec, stream).result() }
}
pub unsafe fn upload(
exec: sys::hipGraphExec_t,
stream: sys::hipStream_t,
) -> Result<(), HipError> {
unsafe { sys::hipGraphUpload(exec, stream).result() }
}
}
pub mod mem_pool {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn peer_transfer_self() {
init().unwrap();
device::set_device(0).unwrap();
let bytes = 1024 * std::mem::size_of::<f32>();
let src = malloc_sync(bytes).unwrap();
let dst = malloc_sync(bytes).unwrap();
let src_host: Vec<f32> = (0..1024).map(|i| i as f32).collect();
let src_bytes =
unsafe { std::slice::from_raw_parts(src_host.as_ptr() as *const u8, bytes) };
unsafe { memcpy_htod_sync(src, src_bytes).unwrap() };
unsafe { memcpy_dtod_sync(dst, src, bytes).unwrap() };
let mut dst_host = vec![0f32; 1024];
let dst_bytes =
unsafe { std::slice::from_raw_parts_mut(dst_host.as_mut_ptr() as *mut u8, bytes) };
unsafe { memcpy_dtoh_sync(dst_bytes, dst).unwrap() };
for (i, &v) in dst_host.iter().enumerate() {
assert_eq!(v, i as f32);
}
free_sync(src).unwrap();
free_sync(dst).unwrap();
}
}