Skip to content

Commit 0621759

Browse files
committed
Add unified API support and fix the build mechanism appropriately. Also add a unified example
1 parent 11fe6bf commit 0621759

File tree

9 files changed

+127
-40
lines changed

9 files changed

+127
-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 80 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: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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 5-by-3 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 err = set_backend(AfBackend::AF_BACKEND_CPU);
26+
match err {
27+
Ok(_) => test_backend(),
28+
Err(e) => println!("CPU backend not available: {}", e),
29+
};
30+
31+
let err = set_backend(AfBackend::AF_BACKEND_CUDA);
32+
match err {
33+
Ok(_) => test_backend(),
34+
Err(e) => println!("CUDA backend not available: {}", e),
35+
};
36+
37+
let err = set_backend(AfBackend::AF_BACKEND_OPENCL);
38+
match err {
39+
Ok(_) => test_backend(),
40+
Err(e) => println!("OpenCL backend not available: {}", e),
41+
};
42+
}

src/defines.rs

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

50+
#[repr(C)]
51+
#[derive(Clone, Copy, Debug)]
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 = 3
61+
}
62+
5063
impl Display for AfError {
5164
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
5265
write!(f, "{}", self.description())

src/device/mod.rs

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,18 @@
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;
1715
fn af_get_device(device: *mut c_int) -> c_int;
18-
1916
fn af_sync(device: c_int) -> c_int;
2017
}
2118

@@ -135,3 +132,31 @@ pub fn sync(device: i32) -> Result<(), AfError> {
135132
}
136133
}
137134
}
135+
136+
/// Toggle backends between cuda, opencl or cpu
137+
///
138+
/// # Parameters
139+
///
140+
/// - `backend` to which to switch to
141+
pub fn set_backend(backend: AfBackend) -> Result<(), AfError> {
142+
unsafe {
143+
let err_val = af_set_backend(backend as uint8_t);
144+
match err_val {
145+
0 => Ok(()),
146+
_ => Err(AfError::from(err_val)),
147+
}
148+
}
149+
}
150+
151+
/// Get the available backend count
152+
#[allow(unused_mut)]
153+
pub fn get_backend_count() -> Result<u32, AfError> {
154+
unsafe {
155+
let mut temp: u32 = 0;
156+
let err_val = af_get_backend_count(&mut temp as *mut c_uint);
157+
match err_val {
158+
0 => Ok(temp),
159+
_ => Err(AfError::from(err_val)),
160+
}
161+
}
162+
}

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ 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, set_device, get_device, sync, get_backend_count, set_backend};
3838
mod device;
3939

40-
pub use defines::{Aftype, AfError, ColorMap, YCCStd};
40+
pub use defines::{Aftype, AfError, AfBackend, ColorMap, YCCStd};
4141
pub use defines::{InterpType, BorderType, MatchType, NormType};
4242
pub use defines::{Connectivity, ConvMode, ConvDomain, ColorSpace, MatProp};
4343
mod defines;

0 commit comments

Comments
 (0)