Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "arrayfire"
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."
version = "3.0.0"
version = "3.1.3"
documentation = "http://arrayfire.github.io/arrayfire-rust/arrayfire/index.html"
homepage = "https://github.com/arrayfire/arrayfire"
repository = "https://github.com/arrayfire/arrayfire-rust"
Expand All @@ -27,6 +27,10 @@ path = "src/lib.rs"
name = "helloworld"
path = "examples/helloworld.rs"

[[example]]
name = "unified"
path = "examples/unified.rs"

[[example]]
name = "pi"
path = "examples/pi.rs"
Expand Down
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,5 +112,4 @@ You might see something along the lines of :
dyld: Library not loaded: @rpath/libafopencl.3.dylib
```

This is related to this [Rust issue](https://github.com/rust-lang/rust/issues/25185)
A workaround for now is to add the location of libaf*.dylib to your LD_LIBRARY_PATH.
You need to add the location of libaf.{dylib, so, dll} to your LD_LIBRARY_PATH.
2 changes: 1 addition & 1 deletion arrayfire
Submodule arrayfire updated 100 files
7 changes: 1 addition & 6 deletions build.conf
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
{
"use_backend": "cpu",

"use_lib": false,
"lib_dir": "/usr/local/lib",
"inc_dir": "/usr/local/include",

"build_type": "Release",
"build_threads": "4",
"build_cuda": "OFF",
"build_opencl": "ON",
"build_cpu": "ON",
"build_examples": "OFF",
"build_test": "OFF",
"build_graphics": "ON",
Expand All @@ -31,5 +26,5 @@

"cuda_sdk": "/usr/local/cuda",
"opencl_sdk": "/usr",
"sdk_lib_dir": "lib"
"sdk_lib_dir": "lib64"
}
49 changes: 29 additions & 20 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@ use std::convert::AsRef;
#[allow(dead_code)]
#[derive(RustcDecodable)]
struct Config {
// below variable dictates which
// backend library is used by rust wrapper
use_backend: String,

// Use the existing lib if it exists
use_lib: bool,
lib_dir: String,
Expand All @@ -25,9 +21,6 @@ struct Config {
// Build related
build_type: String,
build_threads: String,
build_cuda: String,
build_opencl: String,
build_cpu: String,
build_examples: String,
build_test: String,
build_graphics: String,
Expand Down Expand Up @@ -66,6 +59,13 @@ fn fail(s: &str) -> ! {
panic!("\n{}\n\nbuild script failed, must exit now", s)
}

fn file_exists(location: &str) -> bool {
match fs::metadata(location) {
Ok(f) => f.is_file(),
Err(_) => false,
}
}

fn run(cmd: &mut Command, program: &str) {
println!("running: {:?}", cmd);
let status = match cmd.status() {
Expand Down Expand Up @@ -233,9 +233,6 @@ fn run_cmake_command(conf: &Config, build_dir: &std::path::PathBuf) {

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

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

fn backend_exists(name: &str) -> bool{
let win_backend = name.to_string() + ".dll";
let osx_backend = name.to_string() + ".dylib";
let linux_backend = name.to_string() + ".so";

return file_exists(&win_backend)
|| file_exists(&osx_backend)
|| file_exists(&linux_backend)
}

fn blob_backends(conf: &Config, build_dir: &std::path::PathBuf) -> (Vec<String>, Vec<String>) {
let mut backend_dirs :Vec<String>= Vec::new();
let mut backends :Vec<String> = Vec::new();
Expand All @@ -342,20 +346,21 @@ fn blob_backends(conf: &Config, build_dir: &std::path::PathBuf) -> (Vec<String>,
backend_dirs.push(build_dir.join("package/lib").to_str().to_owned().unwrap().to_string());
}

if conf.use_backend == "cpu" {
backends.push("afcpu".to_string());
} else if conf.use_backend == "cuda" {
backends.push("afcuda".to_string());
backends.push("nvvm".to_string());
let lib_dir = PathBuf::from(backend_dirs.last().unwrap());

// blob in cuda deps
if backend_exists(&lib_dir.join("libafcuda").to_string_lossy()) {
if cfg!(windows) {
backend_dirs.push(format!("{}\\lib\\x64", conf.cuda_sdk));
backend_dirs.push(format!("{}\\nvvm\\lib\\x64", conf.cuda_sdk));
} else {
backend_dirs.push(format!("{}/{}", conf.cuda_sdk, conf.sdk_lib_dir));
backend_dirs.push(format!("{}/nvvm/{}", conf.cuda_sdk, conf.sdk_lib_dir));
}
} else if conf.use_backend == "opencl" {
backends.push(("afopencl".to_string()));
}

//blob in opencl deps
if backend_exists(&lib_dir.join("libafopencl").to_string_lossy()) {
if ! cfg!(target_os = "macos"){
backends.push("OpenCL".to_string());
}
Expand All @@ -366,6 +371,10 @@ fn blob_backends(conf: &Config, build_dir: &std::path::PathBuf) -> (Vec<String>,
}
}

if backend_exists(&lib_dir.join("libaf").to_string_lossy()) {
backends.push("af".to_string());
}

if conf.build_graphics=="ON" {
backends.push("forge".to_string());
if !conf.use_lib {
Expand Down
56 changes: 56 additions & 0 deletions examples/unified.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
extern crate arrayfire as af;

use af::*;

#[allow(unused_must_use)]
fn test_backend(){
info();

let num_rows: u64 = 10;
let num_cols: u64 = 10;
let dims = Dim4::new(&[num_rows, num_cols, 1, 1]);

println!("Create a 10-by-10 matrix of random floats on the compute device");
let a = match randu(dims, Aftype::F32) {
Ok(value) => value,
Err(error) => panic!("{}", error),
};
print(&a);
}


#[allow(unused_must_use)]
fn main() {
println!("There are {:?} available backends", get_backend_count().unwrap());
let available = get_available_backends().unwrap();

if available.contains(&AfBackend::AF_BACKEND_CPU){
println!("Evaluating CPU Backend...");
let err = set_backend(AfBackend::AF_BACKEND_CPU);
println!("There are {} CPU compute devices", device_count().unwrap());
match err {
Ok(_) => test_backend(),
Err(e) => println!("CPU backend error: {}", e),
};
}

if available.contains(&AfBackend::AF_BACKEND_CUDA){
println!("Evaluating CUDA Backend...");
let err = set_backend(AfBackend::AF_BACKEND_CUDA);
println!("There are {} CUDA compute devices", device_count().unwrap());
match err {
Ok(_) => test_backend(),
Err(e) => println!("CUDA backend error: {}", e),
};
}

if available.contains(&AfBackend::AF_BACKEND_OPENCL){
println!("Evaluating OpenCL Backend...");
let err = set_backend(AfBackend::AF_BACKEND_OPENCL);
println!("There are {} OpenCL compute devices", device_count().unwrap());
match err {
Ok(_) => test_backend(),
Err(e) => println!("OpenCL backend error: {}", e),
};
}
}
25 changes: 25 additions & 0 deletions src/defines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,31 @@ pub enum AfError {
ERR_UNKNOWN = 999
}

#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum AfBackend {
/// Default backend order: OpenCL -> CUDA -> CPU
AF_BACKEND_DEFAULT = 0,
/// CPU a.k.a sequential algorithms
AF_BACKEND_CPU = 1,
/// CUDA Compute Backend
AF_BACKEND_CUDA = 2,
/// OpenCL Compute Backend
AF_BACKEND_OPENCL = 4
}

impl Display for AfBackend {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
let text = match *self {
AfBackend::AF_BACKEND_OPENCL => "OpenCL",
AfBackend::AF_BACKEND_CUDA => "Cuda",
AfBackend::AF_BACKEND_CPU => "CPU",
AfBackend::AF_BACKEND_DEFAULT => "Default",
};
write!(f, "{}", text)
}
}

impl Display for AfError {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(f, "{}", self.description())
Expand Down
62 changes: 54 additions & 8 deletions src/device/mod.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
extern crate libc;

use defines::AfError;
use self::libc::c_int;
use defines::{AfError, AfBackend};
use self::libc::{c_int, c_uint, uint8_t};


extern {
fn af_get_version(major: *mut c_int, minor: *mut c_int, patch: *mut c_int) -> c_int;

fn af_info() -> c_int;

fn af_get_device_count(nDevices: *mut c_int) -> c_int;

fn af_get_dbl_support(available: *mut c_int, device: c_int) -> c_int;

fn af_set_device(device: c_int) -> c_int;

fn af_set_backend(bknd: uint8_t) -> c_int;
fn af_get_backend_count(num_backends: *mut c_uint) -> c_int;
fn af_get_available_backends(backends: *mut c_int) -> c_int;
fn af_get_device(device: *mut c_int) -> c_int;

fn af_sync(device: c_int) -> c_int;
}

Expand Down Expand Up @@ -135,3 +133,51 @@ pub fn sync(device: i32) -> Result<(), AfError> {
}
}
}

/// Toggle backends between cuda, opencl or cpu
///
/// # Parameters
///
/// - `backend` to which to switch to
pub fn set_backend(backend: AfBackend) -> Result<(), AfError> {
unsafe {
let err_val = af_set_backend(backend as uint8_t);
match err_val {
0 => Ok(()),
_ => Err(AfError::from(err_val)),
}
}
}

/// Get the available backend count
#[allow(unused_mut)]
pub fn get_backend_count() -> Result<u32, AfError> {
unsafe {
let mut temp: u32 = 0;
let err_val = af_get_backend_count(&mut temp as *mut c_uint);
match err_val {
0 => Ok(temp),
_ => Err(AfError::from(err_val)),
}
}
}


/// Get the available backends
#[allow(unused_mut)]
pub fn get_available_backends() -> Result<Vec<AfBackend>, AfError> {
unsafe {
let mut temp: i32 = 0;
let err_val = af_get_available_backends(&mut temp as *mut c_int);
match err_val {
0 => {
let mut b = Vec::new();
if temp & 0b0100 == 0b0100 { b.push(AfBackend::AF_BACKEND_OPENCL); }
if temp & 0b0010 == 0b0010 { b.push(AfBackend::AF_BACKEND_CUDA); }
if temp & 0b0001 == 0b0001 { b.push(AfBackend::AF_BACKEND_CPU); }
Ok(b)
},
_ => Err(AfError::from(err_val)),
}
}
}
6 changes: 4 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@ pub use data::{reorder, shift, moddims, flat, flip};
pub use data::{select, selectl, selectr, replace, replace_scalar};
mod data;

pub use device::{get_version, info, device_count, is_double_available, set_device, get_device, sync};
pub use device::{get_version, info, device_count, is_double_available
, set_device, get_device, sync, get_backend_count, set_backend
, get_available_backends};
mod device;

pub use defines::{Aftype, AfError, ColorMap, YCCStd};
pub use defines::{Aftype, AfError, AfBackend, ColorMap, YCCStd};
pub use defines::{InterpType, BorderType, MatchType, NormType};
pub use defines::{Connectivity, ConvMode, ConvDomain, ColorSpace, MatProp};
mod defines;
Expand Down