cogciprocate / ocl

OpenCL for Rust
Other
721 stars 75 forks source link

Concurrent device listing #189

Open michaelmattig opened 3 years ago

michaelmattig commented 3 years ago

I'm facing the issue that concurrent access of the available OpenCL devices fails. While one call gets the correct device, a parallel call gets shown no devices at all.

If I run the following tests in parallel:

#[cfg(test)]
mod tests {
    use super::*;
    use ocl::{Platform, Device};
    use std::{thread, time};

    fn ocl(){
        let platform = Platform::default();
        println!("Platform:{:?}", platform);
        println!("Devices:{:?}", Device::list_all(platform));
        let device = Device::first(platform).unwrap();
        println!("Device:{:?}", device);
    }

    #[test]
    fn test1() {
        ocl()
    }

    #[test]
    fn test2() {
        // thread::sleep(time::Duration::from_secs(1));
        ocl()
    }
}

most of the time only one test succeeds and yields

Platform:Platform(PlatformId(0x7fc3ffff7020)) Devices:Ok([Device(DeviceId(0x7fc400001040))]) Device:Device(DeviceId(0x7fc400001040))

while the other one shows:

Platform:Platform(PlatformId(0x7fc3ffff7020)) Devices:Ok([])

called Result::unwrap() on an Err value:

################################ OPENCL ERROR ###############################

Error executing function: clGetDeviceIDs

Status error code: CL_DEVICE_NOT_FOUND (-1)

Executing only one test or adding a sleep before the first one, both tests succeed.

dmarcuse commented 3 years ago

As a temporary workaround you can also force the tests to run concurrently with cargo test -- --test-threads 1

michaelmattig commented 3 years ago

As a temporary workaround you can also force the tests to run concurrently with cargo test -- --test-threads 1

sure, but I actually need to compile and run kernels in parallel in my application.

dmarcuse commented 3 years ago

As a temporary workaround you can also force the tests to run concurrently with cargo test -- --test-threads 1

sure, but I actually need to compile and run kernels in parallel in my application.

Maybe you could use a global Mutex lock to synchronize things? This seems like an issue with the underlying OpenCL driver rather than the bindings, which makes it hard to fix.

michaelmattig commented 3 years ago

I will use a static reference to the device for now (see code below). I would very much like to see this issue fixed though, as thread-safety is stated to be a major goal of this crate.

#[cfg(test)]
mod tests {
    use super::*;
    use ocl::{Platform, Device};
    use lazy_static::lazy_static;

    lazy_static! {
        static ref DEVICE: Device = Device::first(Platform::default()).expect("Device has to exist");
    }

    fn ocl(){
        let platform = Platform::default();
        println!("Platform:{:?}", platform);
        let device = *DEVICE;
        println!("Device{:?}", device);
    }

    #[test]
    fn test1() {
        ocl()
    }

    #[test]
    fn test2() {
        ocl()
    }
}
dmarcuse commented 3 years ago

I don't think this is an issue with this library though - all the OpenCL calls involved in this example are supposed to be thread safe at the driver level; if the driver is breaking its own safety guarantees that's a problem with the driver.