使用多个openmp主机线程和opencl

时间:2014-08-15 16:26:06

标签: c++ multithreading thread-safety opencl openmp

我的GPU是ATI Mobility Radeon HD 5450;可以找到5470的规格(几乎相同)here。我使用多个主机线程(使用OpenMP)和OpenCL时遇到了问题。我正在做的是:

我有一个包含上下文,程序,队列等的以下类的实例:

class OclMain
{
    ...
    ...
    cl::Device       device;
    cl::Context      context;
    cl::CommandQueue queue;
    cl::Program      program;
    cl::Program::Sources sources;
    ...
    ...
}

对于每个OpenMP线程,我有一个以下类的实例,每个实例都包含自己的cl :: Kernel,因为setArg(...)不是线程安全的。这些中的每一个还处理它自己的缓冲区创建,内核的执行等。例如,如果我使用#pragma omp parallel for num_threads(16)最多有16个线程,我创建了16个这些对象,每个线程都有它自己的Ocl对象。完成一个线程后,Ocl对象将重新用于上述for循环的下一次迭代,并再次调用setEpi()以将新数据上载到设备。每个线程处理一个cv :: Mat epi。

class Ocl
{
    Ocl(OclMain *oclm) : oclm(oclm) { kernel = cl::Kernel(oclg->program,"kernel"); }
    ...
    // this data doesn't change during execution of an openmp thread, so I only upload it once to the device after thread creation
    void setEpi(cv::Mat &epi)
    {
        ...
        img_epi = cl::Image2D(oclm->context, CL_MEM_READ_ONLY, cl::ImageFormat(CL_RGBA, CL_FLOAT), epi.cols, epi.rows, 0, 0);

        cl::size_t<3> origin;
        origin[0] = 0; origin[1] = 0, origin[2] = 0;
        cl::size_t<3> region;
        region[0] = epi.cols; region[1] = epi.rows; region[2] = 1;

        oclg->queue.enqueueWriteImage(img_epi, CL_TRUE, origin, region, 0, 0, epi.data, 0, 0);
        ...

        // enqueue some more WriteBuffers here (only small buffers)
        ...
            ...
    }
    ...
    // gets called multiple times (maximum epi.rows times, on a row per row basis; 
    // the algorithm I need to implement works this way)
    void runKernel(...)
    {
        // will contain result of kernel computation
        cl::Buffer buff(oclg->context,CL_MEM_WRITE_ONLY,sizeof(float)*dmax*epi.cols);

        // set kernel args here
        // ...

        // enqueue kernel
        oclg->queue.enqueueNDRangeKernel(kernel, cl::NullRange, cl::NDRange(epi.cols/64*64+64),cl::NDRange(64));

        // get results from device
        oclg->queue.enqueueReadBuffer(buffer,CL_TRUE,0,sizeof(float)*dmax*epi.cols,result.data());      
    }

    ...
    ...
    cl::Kernel  kernel;
    OclMain    *oclm
    cl::Image2D img_epi

}

如果epi.rows和epi.cols很小(例如:240x100),这没有问题。 如果epi.rows和epi.cols很大(例如:863x100),它不会,除非我只使用一个OpenMP线程。如果我使用更多线程,程序将在执行前几个线程后冻结。就radeontop而言;此时GPU上没有任何内容,所有统计数据均为0%。

问题似乎是对oclg-&gt; queue.enqueueWriteImage(img_epi,CL_TRUE,origin,region,0,0,epi.data,0,NULL)的调用永远不会完成。如果我将呼叫更改为非阻塞,则程序继续运行,直到下一个阻止呼叫,该呼叫也不会返回。

我试着冲洗;也没有多大帮助。但是,如果我使用CL_MEM_COPY_HOST_PTR方法上传数据而不是将WriteImage排入队列,我似乎不会遇到此问题。发生了什么事?

0 个答案:

没有答案