我的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排入队列,我似乎不会遇到此问题。发生了什么事?