Skip to content

Commit 39f9632

Browse files
committed
Merge pull request #42 from arrayfire/feature/unified
Add unified API support and fix the build mechanism appropriately.
2 parents 11fe6bf + 0b32518 commit 39f9632

File tree

9 files changed

+176
-40
lines changed

9 files changed

+176
-40
lines changed

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "arrayfire"
33
description = "ArrayFire is a high performance software library for parallel computing with an easy-to-use API. Its array based function set makes parallel programming simple. ArrayFire's multiple backends (CUDA, OpenCL and native CPU) make it platform independent and highly portable. A few lines of code in ArrayFire can replace dozens of lines of parallel computing code, saving you valuable time and lowering development costs. This crate provides Rust bindings for ArrayFire library."
4-
version = "3.0.0"
4+
version = "3.1.3"
55
documentation = "http://arrayfire.github.io/arrayfire-rust/arrayfire/index.html"
66
homepage = "https://github.com/arrayfire/arrayfire"
77
repository = "https://github.com/arrayfire/arrayfire-rust"
@@ -27,6 +27,10 @@ path = "src/lib.rs"
2727
name = "helloworld"
2828
path = "examples/helloworld.rs"
2929

30+
[[example]]
31+
name = "unified"
32+
path = "examples/unified.rs"
33+
3034
[[example]]
3135
name = "pi"
3236
path = "examples/pi.rs"

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,5 +112,4 @@ You might see something along the lines of :
112112
dyld: Library not loaded: @rpath/libafopencl.3.dylib
113113
```
114114

115-
This is related to this [Rust issue](https://github.com/rust-lang/rust/issues/25185)
116-
A workaround for now is to add the location of libaf*.dylib to your LD_LIBRARY_PATH.
115+
You need to add the location of libaf.{dylib, so, dll} to your LD_LIBRARY_PATH.

arrayfire

Submodule arrayfire updated 100 files

build.conf

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
{
2-
"use_backend": "cpu",
3-
42
"use_lib": false,
53
"lib_dir": "/usr/local/lib",
64
"inc_dir": "/usr/local/include",
75

86
"build_type": "Release",
97
"build_threads": "4",
10-
"build_cuda": "OFF",
11-
"build_opencl": "ON",
12-
"build_cpu": "ON",
138
"build_examples": "OFF",
149
"build_test": "OFF",
1510
"build_graphics": "ON",
@@ -31,5 +26,5 @@
3126

3227
"cuda_sdk": "/usr/local/cuda",
3328
"opencl_sdk": "/usr",
34-
"sdk_lib_dir": "lib"
29+
"sdk_lib_dir": "lib64"
3530
}

build.rs

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@ use std::convert::AsRef;
1313
#[allow(dead_code)]
1414
#[derive(RustcDecodable)]
1515
struct Config {
16-
// below variable dictates which
17-
// backend library is used by rust wrapper
18-
use_backend: String,
19-
2016
// Use the existing lib if it exists
2117
use_lib: bool,
2218
lib_dir: String,
@@ -25,9 +21,6 @@ struct Config {
2521
// Build related
2622
build_type: String,
2723
build_threads: String,
28-
build_cuda: String,
29-
build_opencl: String,
30-
build_cpu: String,
3124
build_examples: String,
3225
build_test: String,
3326
build_graphics: String,
@@ -66,6 +59,13 @@ fn fail(s: &str) -> ! {
6659
panic!("\n{}\n\nbuild script failed, must exit now", s)
6760
}
6861

62+
fn file_exists(location: &str) -> bool {
63+
match fs::metadata(location) {
64+
Ok(f) => f.is_file(),
65+
Err(_) => false,
66+
}
67+
}
68+
6969
fn run(cmd: &mut Command, program: &str) {
7070
println!("running: {:?}", cmd);
7171
let status = match cmd.status() {
@@ -233,9 +233,6 @@ fn run_cmake_command(conf: &Config, build_dir: &std::path::PathBuf) {
233233

234234
run(cmake_cmd.arg("..").arg("-G").arg("Visual Studio 12 2013 Win64")
235235
.args(&[format!("-DCMAKE_BUILD_TYPE:STRING={}", conf.build_type),
236-
format!("-DBUILD_CPU:BOOL={}", conf.build_cpu),
237-
format!("-DBUILD_CUDA:BOOL={}", conf.build_cuda),
238-
format!("-DBUILD_OPENCL:BOOL={}", conf.build_opencl),
239236
format!("-DBUILD_EXAMPLES:BOOL={}", conf.build_examples),
240237
format!("-DBUILD_TEST:BOOL={}", conf.build_test),
241238
format!("-DBOOST_ROOT={}", conf.boost_dir),
@@ -312,9 +309,6 @@ fn run_cmake_command(conf: &Config, build_dir: &std::path::PathBuf) {
312309

313310
run(cmake_cmd.arg("..")
314311
.args(&[format!("-DCMAKE_BUILD_TYPE:STRING={}", conf.build_type),
315-
format!("-DBUILD_CPU:BOOL={}", conf.build_cpu),
316-
format!("-DBUILD_CUDA:BOOL={}", conf.build_cuda),
317-
format!("-DBUILD_OPENCL:BOOL={}", conf.build_opencl),
318312
format!("-DBUILD_EXAMPLES:BOOL={}", conf.build_examples),
319313
format!("-DBUILD_TEST:BOOL={}", conf.build_test),
320314
format!("-DCMAKE_INSTALL_PREFIX:STRING={}", "package")])
@@ -332,6 +326,16 @@ fn run_cmake_command(conf: &Config, build_dir: &std::path::PathBuf) {
332326
.arg(format!("install")), "make");
333327
}
334328

329+
fn backend_exists(name: &str) -> bool{
330+
let win_backend = name.to_string() + ".dll";
331+
let osx_backend = name.to_string() + ".dylib";
332+
let linux_backend = name.to_string() + ".so";
333+
334+
return file_exists(&win_backend)
335+
|| file_exists(&osx_backend)
336+
|| file_exists(&linux_backend)
337+
}
338+
335339
fn blob_backends(conf: &Config, build_dir: &std::path::PathBuf) -> (Vec<String>, Vec<String>) {
336340
let mut backend_dirs :Vec<String>= Vec::new();
337341
let mut backends :Vec<String> = Vec::new();
@@ -342,20 +346,21 @@ fn blob_backends(conf: &Config, build_dir: &std::path::PathBuf) -> (Vec<String>,
342346
backend_dirs.push(build_dir.join("package/lib").to_str().to_owned().unwrap().to_string());
343347
}
344348

345-
if conf.use_backend == "cpu" {
346-
backends.push("afcpu".to_string());
347-
} else if conf.use_backend == "cuda" {
348-
backends.push("afcuda".to_string());
349-
backends.push("nvvm".to_string());
349+
let lib_dir = PathBuf::from(backend_dirs.last().unwrap());
350+
351+
// blob in cuda deps
352+
if backend_exists(&lib_dir.join("libafcuda").to_string_lossy()) {
350353
if cfg!(windows) {
351354
backend_dirs.push(format!("{}\\lib\\x64", conf.cuda_sdk));
352355
backend_dirs.push(format!("{}\\nvvm\\lib\\x64", conf.cuda_sdk));
353356
} else {
354357
backend_dirs.push(format!("{}/{}", conf.cuda_sdk, conf.sdk_lib_dir));
355358
backend_dirs.push(format!("{}/nvvm/{}", conf.cuda_sdk, conf.sdk_lib_dir));
356359
}
357-
} else if conf.use_backend == "opencl" {
358-
backends.push(("afopencl".to_string()));
360+
}
361+
362+
//blob in opencl deps
363+
if backend_exists(&lib_dir.join("libafopencl").to_string_lossy()) {
359364
if ! cfg!(target_os = "macos"){
360365
backends.push("OpenCL".to_string());
361366
}
@@ -366,6 +371,10 @@ fn blob_backends(conf: &Config, build_dir: &std::path::PathBuf) -> (Vec<String>,
366371
}
367372
}
368373

374+
if backend_exists(&lib_dir.join("libaf").to_string_lossy()) {
375+
backends.push("af".to_string());
376+
}
377+
369378
if conf.build_graphics=="ON" {
370379
backends.push("forge".to_string());
371380
if !conf.use_lib {

examples/unified.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
extern crate arrayfire as af;
2+
3+
use af::*;
4+
5+
#[allow(unused_must_use)]
6+
fn test_backend(){
7+
info();
8+
9+
let num_rows: u64 = 10;
10+
let num_cols: u64 = 10;
11+
let dims = Dim4::new(&[num_rows, num_cols, 1, 1]);
12+
13+
println!("Create a 10-by-10 matrix of random floats on the compute device");
14+
let a = match randu(dims, Aftype::F32) {
15+
Ok(value) => value,
16+
Err(error) => panic!("{}", error),
17+
};
18+
print(&a);
19+
}
20+
21+
22+
#[allow(unused_must_use)]
23+
fn main() {
24+
println!("There are {:?} available backends", get_backend_count().unwrap());
25+
let available = get_available_backends().unwrap();
26+
27+
if available.contains(&AfBackend::AF_BACKEND_CPU){
28+
println!("Evaluating CPU Backend...");
29+
let err = set_backend(AfBackend::AF_BACKEND_CPU);
30+
println!("There are {} CPU compute devices", device_count().unwrap());
31+
match err {
32+
Ok(_) => test_backend(),
33+
Err(e) => println!("CPU backend error: {}", e),
34+
};
35+
}
36+
37+
if available.contains(&AfBackend::AF_BACKEND_CUDA){
38+
println!("Evaluating CUDA Backend...");
39+
let err = set_backend(AfBackend::AF_BACKEND_CUDA);
40+
println!("There are {} CUDA compute devices", device_count().unwrap());
41+
match err {
42+
Ok(_) => test_backend(),
43+
Err(e) => println!("CUDA backend error: {}", e),
44+
};
45+
}
46+
47+
if available.contains(&AfBackend::AF_BACKEND_OPENCL){
48+
println!("Evaluating OpenCL Backend...");
49+
let err = set_backend(AfBackend::AF_BACKEND_OPENCL);
50+
println!("There are {} OpenCL compute devices", device_count().unwrap());
51+
match err {
52+
Ok(_) => test_backend(),
53+
Err(e) => println!("OpenCL backend error: {}", e),
54+
};
55+
}
56+
}

src/defines.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,31 @@ pub enum AfError {
4747
ERR_UNKNOWN = 999
4848
}
4949

50+
#[repr(C)]
51+
#[derive(Clone, Copy, Debug, PartialEq)]
52+
pub enum AfBackend {
53+
/// Default backend order: OpenCL -> CUDA -> CPU
54+
AF_BACKEND_DEFAULT = 0,
55+
/// CPU a.k.a sequential algorithms
56+
AF_BACKEND_CPU = 1,
57+
/// CUDA Compute Backend
58+
AF_BACKEND_CUDA = 2,
59+
/// OpenCL Compute Backend
60+
AF_BACKEND_OPENCL = 4
61+
}
62+
63+
impl Display for AfBackend {
64+
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
65+
let text = match *self {
66+
AfBackend::AF_BACKEND_OPENCL => "OpenCL",
67+
AfBackend::AF_BACKEND_CUDA => "Cuda",
68+
AfBackend::AF_BACKEND_CPU => "CPU",
69+
AfBackend::AF_BACKEND_DEFAULT => "Default",
70+
};
71+
write!(f, "{}", text)
72+
}
73+
}
74+
5075
impl Display for AfError {
5176
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
5277
write!(f, "{}", self.description())

src/device/mod.rs

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
extern crate libc;
22

3-
use defines::AfError;
4-
use self::libc::c_int;
3+
use defines::{AfError, AfBackend};
4+
use self::libc::{c_int, c_uint, uint8_t};
5+
56

67
extern {
78
fn af_get_version(major: *mut c_int, minor: *mut c_int, patch: *mut c_int) -> c_int;
8-
99
fn af_info() -> c_int;
10-
1110
fn af_get_device_count(nDevices: *mut c_int) -> c_int;
12-
1311
fn af_get_dbl_support(available: *mut c_int, device: c_int) -> c_int;
14-
1512
fn af_set_device(device: c_int) -> c_int;
16-
13+
fn af_set_backend(bknd: uint8_t) -> c_int;
14+
fn af_get_backend_count(num_backends: *mut c_uint) -> c_int;
15+
fn af_get_available_backends(backends: *mut c_int) -> c_int;
1716
fn af_get_device(device: *mut c_int) -> c_int;
18-
1917
fn af_sync(device: c_int) -> c_int;
2018
}
2119

@@ -135,3 +133,51 @@ pub fn sync(device: i32) -> Result<(), AfError> {
135133
}
136134
}
137135
}
136+
137+
/// Toggle backends between cuda, opencl or cpu
138+
///
139+
/// # Parameters
140+
///
141+
/// - `backend` to which to switch to
142+
pub fn set_backend(backend: AfBackend) -> Result<(), AfError> {
143+
unsafe {
144+
let err_val = af_set_backend(backend as uint8_t);
145+
match err_val {
146+
0 => Ok(()),
147+
_ => Err(AfError::from(err_val)),
148+
}
149+
}
150+
}
151+
152+
/// Get the available backend count
153+
#[allow(unused_mut)]
154+
pub fn get_backend_count() -> Result<u32, AfError> {
155+
unsafe {
156+
let mut temp: u32 = 0;
157+
let err_val = af_get_backend_count(&mut temp as *mut c_uint);
158+
match err_val {
159+
0 => Ok(temp),
160+
_ => Err(AfError::from(err_val)),
161+
}
162+
}
163+
}
164+
165+
166+
/// Get the available backends
167+
#[allow(unused_mut)]
168+
pub fn get_available_backends() -> Result<Vec<AfBackend>, AfError> {
169+
unsafe {
170+
let mut temp: i32 = 0;
171+
let err_val = af_get_available_backends(&mut temp as *mut c_int);
172+
match err_val {
173+
0 => {
174+
let mut b = Vec::new();
175+
if temp & 0b0100 == 0b0100 { b.push(AfBackend::AF_BACKEND_OPENCL); }
176+
if temp & 0b0010 == 0b0010 { b.push(AfBackend::AF_BACKEND_CUDA); }
177+
if temp & 0b0001 == 0b0001 { b.push(AfBackend::AF_BACKEND_CPU); }
178+
Ok(b)
179+
},
180+
_ => Err(AfError::from(err_val)),
181+
}
182+
}
183+
}

src/lib.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,12 @@ pub use data::{reorder, shift, moddims, flat, flip};
3434
pub use data::{select, selectl, selectr, replace, replace_scalar};
3535
mod data;
3636

37-
pub use device::{get_version, info, device_count, is_double_available, set_device, get_device, sync};
37+
pub use device::{get_version, info, device_count, is_double_available
38+
, set_device, get_device, sync, get_backend_count, set_backend
39+
, get_available_backends};
3840
mod device;
3941

40-
pub use defines::{Aftype, AfError, ColorMap, YCCStd};
42+
pub use defines::{Aftype, AfError, AfBackend, ColorMap, YCCStd};
4143
pub use defines::{InterpType, BorderType, MatchType, NormType};
4244
pub use defines::{Connectivity, ConvMode, ConvDomain, ColorSpace, MatProp};
4345
mod defines;

0 commit comments

Comments
 (0)