use frameworks::cuda::{Device, DeviceInfo};
use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};
use super::ffi::*;
use super::{API, Error};
impl API {
pub fn load_devices() -> Result<Vec<Device>, Error> {
match API::load_device_list() {
Ok(device_list) => {
Ok(
device_list.iter().map(|device| {
device.clone()
.load_name()
.load_device_type()
.load_compute_units()
}).collect()
)
},
Err(err) => Err(err)
}
}
pub fn load_device_list() -> Result<Vec<Device>, Error> {
let mut device_counter = 0;
try!(unsafe {API::ffi_device_get_count(&mut device_counter)});
Ok((0..device_counter).collect::<Vec<i32>>().iter().map(|ordinal| {
let mut device_id: CUdevice = 0;
let _ = unsafe { API::ffi_device_get(&mut device_id, *ordinal) };
Device::from_isize(device_id as isize)
}).collect::<Vec<Device>>())
}
pub fn load_device_info(device: &Device, info: CUdevice_attribute) -> Result<DeviceInfo, Error> {
match info {
CUdevice_attribute::CU_DEVICE_NAME => {
let mut name: [i8; 1024] = [0; 1024];
try!(unsafe { API::ffi_device_get_name(name.as_mut_ptr(), 1024, device.id_c()) });
let mut buf: Vec<u8> = vec![];
for (i, char) in name.iter().enumerate() {
match *char {
0 => if i > 1 && name[i-1] != 0 { buf.push(*char as u8) },
_ => buf.push(*char as u8)
}
}
Ok(DeviceInfo::new(buf))
},
CUdevice_attribute::CU_DEVICE_MEMORY_TOTAL => {
unimplemented!()
},
_ => {
let mut value: ::libc::c_int = 0;
try!(unsafe { API::ffi_device_get_attribute(&mut value, info, device.id_c()) });
let mut buf = vec![];
buf.write_i32::<LittleEndian>(value).unwrap();
Ok(DeviceInfo::new(buf))
}
}
}
unsafe fn ffi_device_get(
device: *mut CUdevice,
ordinal: ::libc::c_int,
) -> Result<(), Error> {
match cuDeviceGet(device, ordinal) {
CUresult::CUDA_SUCCESS => Ok(()),
CUresult::CUDA_ERROR_DEINITIALIZED => Err(Error::Deinitialized("CUDA got deinitialized.")),
CUresult::CUDA_ERROR_NOT_INITIALIZED => Err(Error::NotInitialized("CUDA is not initialized.")),
CUresult::CUDA_ERROR_INVALID_CONTEXT => Err(Error::InvalidContext("No valid context available.")),
CUresult::CUDA_ERROR_INVALID_VALUE => Err(Error::InvalidValue("Invalid value provided.")),
_ => Err(Error::Unknown("Unable to get Device count.")),
}
}
unsafe fn ffi_device_get_count(
count: *mut ::libc::c_int
) -> Result<(), Error> {
match cuDeviceGetCount(count) {
CUresult::CUDA_SUCCESS => Ok(()),
CUresult::CUDA_ERROR_DEINITIALIZED => Err(Error::Deinitialized("CUDA got deinitialized.")),
CUresult::CUDA_ERROR_NOT_INITIALIZED => Err(Error::NotInitialized("CUDA is not initialized.")),
CUresult::CUDA_ERROR_INVALID_CONTEXT => Err(Error::InvalidContext("No valid context available.")),
CUresult::CUDA_ERROR_INVALID_VALUE => Err(Error::InvalidValue("Invalid value provided.")),
_ => Err(Error::Unknown("Unable to get Device count.")),
}
}
unsafe fn ffi_device_get_attribute(
pi: *mut ::libc::c_int,
attrib: CUdevice_attribute,
device: CUdevice,
) -> Result<(), Error> {
match cuDeviceGetAttribute(pi, attrib, device) {
CUresult::CUDA_SUCCESS => Ok(()),
CUresult::CUDA_ERROR_DEINITIALIZED => Err(Error::Deinitialized("CUDA got deinitialized.")),
CUresult::CUDA_ERROR_NOT_INITIALIZED => Err(Error::NotInitialized("CUDA is not initialized.")),
CUresult::CUDA_ERROR_INVALID_CONTEXT => Err(Error::InvalidContext("No valid context available.")),
CUresult::CUDA_ERROR_INVALID_VALUE => Err(Error::InvalidValue("Invalid value provided.")),
CUresult::CUDA_ERROR_INVALID_DEVICE => Err(Error::InvalidValue("Invalid value for `device` provided.")),
_ => Err(Error::Unknown("Unable to get device attribute."))
}
}
unsafe fn ffi_device_get_name(
name: *mut ::libc::c_char,
len: ::libc::c_int,
device: CUdevice,
) -> Result<(), Error> {
match cuDeviceGetName(name, len, device) {
CUresult::CUDA_SUCCESS => Ok(()),
CUresult::CUDA_ERROR_DEINITIALIZED => Err(Error::Deinitialized("CUDA got deinitialized.")),
CUresult::CUDA_ERROR_NOT_INITIALIZED => Err(Error::NotInitialized("CUDA is not initialized.")),
CUresult::CUDA_ERROR_INVALID_CONTEXT => Err(Error::InvalidContext("No valid context available.")),
CUresult::CUDA_ERROR_INVALID_VALUE => Err(Error::InvalidValue("Invalid value provided.")),
CUresult::CUDA_ERROR_INVALID_DEVICE => Err(Error::InvalidValue("Invalid value for `device` provided.")),
_ => Err(Error::Unknown("Unable to get device name."))
}
}
unsafe fn ffi_device_total_mem(
bytes: *mut size_t,
device: CUdevice,
) -> Result<(), Error> {
match cuDeviceTotalMem_v2(bytes, device) {
CUresult::CUDA_SUCCESS => Ok(()),
CUresult::CUDA_ERROR_DEINITIALIZED => Err(Error::Deinitialized("CUDA got deinitialized.")),
CUresult::CUDA_ERROR_NOT_INITIALIZED => Err(Error::NotInitialized("CUDA is not initialized.")),
CUresult::CUDA_ERROR_INVALID_CONTEXT => Err(Error::InvalidContext("No valid context available.")),
CUresult::CUDA_ERROR_INVALID_VALUE => Err(Error::InvalidValue("Invalid value provided.")),
CUresult::CUDA_ERROR_INVALID_DEVICE => Err(Error::InvalidValue("Invalid value for `device` provided.")),
_ => Err(Error::Unknown("Unable to get total mem of device."))
}
}
}