extern crate ocl;
extern crate rand;
#[macro_use]
extern crate colorify;
use ocl::{
Buffer, Context, Device, EventList, Kernel, Platform, Program, Queue, Result as OclResult,
};
use std::thread::{self, JoinHandle};
use std::time::Duration;
static SRC: &'static str = r#"
__kernel void add(__global float* buffer, float addend) {
buffer[get_global_id(0)] += addend;
}
"#;
fn threads() -> OclResult<()> {
let work_size = 1 << 10;
let mut threads: Vec<JoinHandle<OclResult<String>>> = Vec::new();
let platforms = Platform::list();
println!("Looping through avaliable platforms ({}):", platforms.len());
for p_idx in 0..platforms.len() {
let platform = &platforms[p_idx];
printlnc!(green: "\nPlatform[{}]: {} ({})", p_idx, platform.name()?, platform.vendor()?);
let devices = Device::list_all(platform)?;
printc!(blue: "DEVICES: {:?}", devices);
for device_idx in 0..devices.len() {
let device = devices[device_idx];
printlnc!(royal_blue: "\nDevice[{}]: {} ({})", device_idx, device.name()?, device.vendor()?);
let context = Context::builder().platform(*platform).build()?;
let program = Program::builder()
.src(SRC)
.devices(device)
.build(&context)?;
let queueball = vec![
Queue::new(&context, device, None)?,
Queue::new(&context, device, None)?,
Queue::new(&context, device, None)?,
];
printlnc!(orange: "Spawning threads... ");
for i in 0..5 {
let thread_name = format!("{}:[D{}.I{}]", threads.len(), device_idx, i);
let context_th = context.clone();
let program_th = program.clone();
let work_size_th = work_size;
let queueball_th = queueball.clone();
print!("{}, ", thread_name);
let th = thread::Builder::new()
.name(thread_name.clone())
.spawn(move || {
let _context_th = context_th;
let program_th = program_th;
let work_size_th = work_size_th;
let queueball_th = queueball_th;
let mut buffer = Buffer::<f32>::builder()
.queue(queueball_th[0].clone())
.len(work_size_th)
.build()?;
let mut vec = vec![0.0f32; buffer.len()];
let mut kernel = Kernel::builder()
.program(&program_th)
.name("add")
.queue(queueball_th[0].clone())
.global_work_size(work_size_th)
.arg(&buffer)
.arg(1000.0f32)
.build()?;
let mut event_list = EventList::new();
unsafe {
kernel.cmd().enew(&mut event_list).enq()?;
kernel.set_default_queue(queueball_th[1].clone()).enq()?;
kernel.cmd().queue(&queueball_th[2]).enq()?;
}
thread::sleep(Duration::from_millis(100));
event_list.wait_for()?;
buffer
.set_default_queue(queueball_th[2].clone())
.read(&mut vec)
.enq()?;
buffer.read(&mut vec).queue(&queueball_th[1]).enq()?;
buffer.read(&mut vec).queue(&queueball_th[0]).enq()?;
buffer.read(&mut vec).enq()?;
let check_idx = work_size / 2;
Ok(format!("{{{}}}={}, ", &thread_name, vec[check_idx]))
})
.expect("Error creating thread");
threads.push(th);
}
print!("\n");
}
}
printlnc!(orange: "\nResults: ");
for th in threads.into_iter() {
match th.join() {
Ok(r) => print!("{}", r?),
Err(e) => println!("Error joining thread: '{:?}'", e),
}
}
print!("\n");
Ok(())
}
pub fn main() {
match threads() {
Ok(_) => (),
Err(err) => println!("{}", err),
}
}