Skip to main content

arrayfire/core/
device.rs

1use super::defines::AfError;
2use super::error::HANDLE_ERROR;
3use super::util::{dim_t, free_host, void_ptr};
4
5use libc::{c_char, c_int, size_t};
6use std::borrow::Cow;
7use std::ffi::{CStr, CString};
8
9extern "C" {
10    fn af_get_version(major: *mut c_int, minor: *mut c_int, patch: *mut c_int) -> c_int;
11    fn af_get_revision() -> *const c_char;
12    fn af_info() -> c_int;
13    fn af_info_string(str: *mut *mut c_char, verbose: bool) -> c_int;
14    fn af_device_info(
15        d_name: *mut c_char,
16        d_platform: *mut c_char,
17        d_toolkit: *mut c_char,
18        d_compute: *mut c_char,
19    ) -> c_int;
20    fn af_init() -> c_int;
21    fn af_get_device_count(nDevices: *mut c_int) -> c_int;
22    fn af_get_dbl_support(available: *mut c_int, device: c_int) -> c_int;
23    fn af_set_device(device: c_int) -> c_int;
24    fn af_get_device(device: *mut c_int) -> c_int;
25    fn af_device_mem_info(
26        alloc_bytes: *mut size_t,
27        alloc_buffers: *mut size_t,
28        lock_bytes: *mut size_t,
29        lock_buffers: *mut size_t,
30    ) -> c_int;
31    fn af_print_mem_info(msg: *const c_char, device_id: c_int) -> c_int;
32    fn af_set_mem_step_size(step_bytes: size_t) -> c_int;
33    fn af_get_mem_step_size(step_bytes: *mut size_t) -> c_int;
34    fn af_device_gc() -> c_int;
35    fn af_sync(device: c_int) -> c_int;
36
37    fn af_alloc_pinned(non_pagable_ptr: *mut void_ptr, bytes: dim_t) -> c_int;
38    fn af_free_pinned(non_pagable_ptr: void_ptr) -> c_int;
39    fn af_get_half_support(available: *mut c_int, device: c_int) -> c_int;
40}
41
42/// Get ArrayFire Version Number
43///
44/// # Return Values
45/// A triplet of integers indicating major, minor & fix release version numbers.
46pub fn get_version() -> (i32, i32, i32) {
47    unsafe {
48        let mut maj: i32 = 0;
49        let mut min: i32 = 0;
50        let mut pat: i32 = 0;
51        let err_val = af_get_version(
52            &mut maj as *mut c_int,
53            &mut min as *mut c_int,
54            &mut pat as *mut c_int,
55        );
56        HANDLE_ERROR(AfError::from(err_val));
57        (maj, min, pat)
58    }
59}
60
61/// Get ArrayFire Revision (commit) information of the library.
62///
63/// # Return Values
64/// This returns a `Cow<'static, str>` as the string is constructed at compile time.
65pub fn get_revision() -> Cow<'static, str> {
66    unsafe { CStr::from_ptr(af_get_revision()).to_string_lossy() }
67}
68
69/// Print library meta-info
70///
71/// # Examples
72///
73/// An example output of `af::info` call looks like below
74///
75/// ```text
76/// ArrayFire v3.0.0 (CUDA, 64-bit Mac OSX, build d8d4b38)
77/// Platform: CUDA Toolkit 7, Driver: CUDA Driver Version: 7000
78/// [0] GeForce GT 750M, 2048 MB, CUDA Compute 3.0
79/// ```
80pub fn info() {
81    unsafe {
82        let err_val = af_info();
83        HANDLE_ERROR(AfError::from(err_val));
84    }
85}
86
87/// Return library meta-info as `String`
88///
89/// # Examples
90///
91/// An example output of `af::info_string` call looks like below
92///
93/// ```text
94/// ArrayFire v3.0.0 (CUDA, 64-bit Mac OSX, build d8d4b38)
95/// Platform: CUDA Toolkit 7, Driver: CUDA Driver Version: 7000
96/// [0] GeForce GT 750M, 2048 MB, CUDA Compute 3.0
97/// ```
98pub fn info_string(verbose: bool) -> String {
99    let result: String;
100    unsafe {
101        let mut tmp: *mut c_char = ::std::ptr::null_mut();
102        let err_val = af_info_string(&mut tmp, verbose);
103        HANDLE_ERROR(AfError::from(err_val));
104        result = CStr::from_ptr(tmp).to_string_lossy().into_owned();
105        free_host(tmp);
106    }
107    result
108}
109
110/// Gets the information about device and platform as strings.
111///
112/// # Return Values
113/// A tuple of `String` indicating the name, platform, toolkit and compute.
114pub fn device_info() -> (String, String, String, String) {
115    let mut name = [0 as c_char; 64];
116    let mut platform = [0 as c_char; 10];
117    let mut toolkit = [0 as c_char; 64];
118    let mut compute = [0 as c_char; 10];
119    unsafe {
120        let err_val = af_device_info(
121            &mut name[0],
122            &mut platform[0],
123            &mut toolkit[0],
124            &mut compute[0],
125        );
126        HANDLE_ERROR(AfError::from(err_val));
127        (
128            CStr::from_ptr(name.as_mut_ptr())
129                .to_string_lossy()
130                .into_owned(),
131            CStr::from_ptr(platform.as_mut_ptr())
132                .to_string_lossy()
133                .into_owned(),
134            CStr::from_ptr(toolkit.as_mut_ptr())
135                .to_string_lossy()
136                .into_owned(),
137            CStr::from_ptr(compute.as_mut_ptr())
138                .to_string_lossy()
139                .into_owned(),
140        )
141    }
142}
143
144/// Initialize ArrayFire library
145///
146/// 0th device will be the default device unless init call
147/// is followed by set_device
148pub fn init() {
149    unsafe {
150        let err_val = af_init();
151        HANDLE_ERROR(AfError::from(err_val));
152    }
153}
154
155/// Get total number of available devices
156pub fn device_count() -> i32 {
157    unsafe {
158        let mut temp: i32 = 0;
159        let err_val = af_get_device_count(&mut temp as *mut c_int);
160        HANDLE_ERROR(AfError::from(err_val));
161        temp
162    }
163}
164
165/// Check if a device has double support
166///
167/// # Parameters
168///
169/// - `device` is the device for which double support is checked for
170///
171/// # Return Values
172///
173/// `True` if `device` device has double support, `False` otherwise.
174pub fn is_double_available(device: i32) -> bool {
175    unsafe {
176        let mut temp: i32 = 0;
177        let err_val = af_get_dbl_support(&mut temp as *mut c_int, device as c_int);
178        HANDLE_ERROR(AfError::from(err_val));
179        temp > 0
180    }
181}
182
183/// Set active device
184///
185/// # Parameters
186///
187/// - `device` is the value of the device identifier which has to be set as active
188pub fn set_device(device: i32) {
189    unsafe {
190        let err_val = af_set_device(device as c_int);
191        HANDLE_ERROR(AfError::from(err_val));
192    }
193}
194
195/// Get the current active device id
196pub fn get_device() -> i32 {
197    unsafe {
198        let mut temp: i32 = 0;
199        let err_val = af_get_device(&mut temp as *mut c_int);
200        HANDLE_ERROR(AfError::from(err_val));
201        temp
202    }
203}
204
205/// Get memory information from the memory manager for the current active device
206///
207/// # Parameters
208///
209/// This function doesn't take any input parameters
210///
211/// # Return Values
212///
213/// A quadruple of values regarding the following information.
214///
215/// * Number of bytes allocated
216/// * Number of buffers allocated
217/// * Number of bytes locked
218/// * Number of buffers locked
219pub fn device_mem_info() -> (usize, usize, usize, usize) {
220    unsafe {
221        let mut o0: usize = 0;
222        let mut o1: usize = 0;
223        let mut o2: usize = 0;
224        let mut o3: usize = 0;
225        let err_val = af_device_mem_info(
226            &mut o0 as *mut size_t,
227            &mut o1 as *mut size_t,
228            &mut o2 as *mut size_t,
229            &mut o3 as *mut size_t,
230        );
231        HANDLE_ERROR(AfError::from(err_val));
232        (o0, o1, o2, o3)
233    }
234}
235
236/// Print buffer details from the ArrayFire device manager
237///
238/// This information is printed in the form of a table.
239///
240/// # Parameters
241///
242/// - `msg` is a message to print before the table
243/// - `device` is the id of the device for which buffer details are to be printed
244///
245/// # Return Values
246///
247/// None
248pub fn print_mem_info(msg: String, device: i32) {
249    unsafe {
250        let cmsg = CString::new(msg.as_bytes());
251        match cmsg {
252            Ok(v) => {
253                let err_val = af_print_mem_info(
254                    v.to_bytes_with_nul().as_ptr() as *const c_char,
255                    device as c_int,
256                );
257                HANDLE_ERROR(AfError::from(err_val));
258            }
259            Err(_) => HANDLE_ERROR(AfError::ERR_INTERNAL),
260        }
261    }
262}
263
264/// Set the minimum memory chunk size
265///
266/// # Parameters
267///
268/// - `step_bytes` is the size of minimum memory chunk in bytes
269///
270/// # Return Values
271///
272/// None
273pub fn set_mem_step_size(step_bytes: usize) {
274    unsafe {
275        let err_val = af_set_mem_step_size(step_bytes as size_t);
276        HANDLE_ERROR(AfError::from(err_val));
277    }
278}
279
280/// Get the minimum memory chunk size
281///
282/// # Parameters
283///
284/// None
285///
286/// # Return Values
287///
288/// Returns is the size of minimum memory chunk in bytes
289pub fn get_mem_step_size() -> usize {
290    unsafe {
291        let mut temp: usize = 0;
292        let err_val = af_get_mem_step_size(&mut temp as *mut size_t);
293        HANDLE_ERROR(AfError::from(err_val));
294        temp
295    }
296}
297
298/// Call the garbage collection routine
299pub fn device_gc() {
300    unsafe {
301        let err_val = af_device_gc();
302        HANDLE_ERROR(AfError::from(err_val));
303    }
304}
305
306/// Sync all operations on given device
307///
308/// # Parameters
309///
310/// - `device` on which the operations are to be synced
311///
312/// # Return Values
313///
314/// None
315pub fn sync(device: i32) {
316    unsafe {
317        let err_val = af_sync(device as c_int);
318        HANDLE_ERROR(AfError::from(err_val));
319    }
320}
321
322/// Allocate non-pageable memory on HOST memory
323pub unsafe fn alloc_pinned(bytes: usize) -> void_ptr {
324    let mut out: void_ptr = std::ptr::null_mut();
325    let err_val = af_alloc_pinned(&mut out as *mut void_ptr, bytes as dim_t);
326    HANDLE_ERROR(AfError::from(err_val));
327    out
328}
329
330/// Free the pointer returned by [alloc_pinned](./fn.alloc_pinned.html)
331pub unsafe fn free_pinned(ptr: void_ptr) {
332    let err_val = af_free_pinned(ptr);
333    HANDLE_ERROR(AfError::from(err_val));
334}
335
336/// Check if a device has half support
337///
338/// # Parameters
339///
340/// - `device` is the device for which half precision support is checked for
341///
342/// # Return Values
343///
344/// `True` if `device` device has half support, `False` otherwise.
345pub fn is_half_available(device: i32) -> bool {
346    unsafe {
347        let mut temp: i32 = 0;
348        let err_val = af_get_half_support(&mut temp as *mut c_int, device as c_int);
349        HANDLE_ERROR(AfError::from(err_val));
350        temp > 0
351    }
352}