我正在开发一个对视频帧数据执行一些处理的应用程序。为了加速它,我使用2张图形卡并使用OpenCL处理数据。我的想法是将一帧发送到第一张卡,另一帧发送到第二张卡。设备使用相同的上下文,但使用不同的命令队列,内核和内存对象。
然而,在我看来,计算并不是并行执行的,因为2张卡所需的时间几乎与只有一张图形卡所需的时间相同。
有没有人能够同时在独立数据上使用多个设备?
提前致谢。
编辑:
以下是切换到2个单独上下文后生成的代码。但是,使用2张图形卡的执行时间仍与1张图形卡相同。
cl::NDRange globalws(imageSize);
cl::NDRange localws;
for (int i = 0; i < numDevices; i++){
// Copy the input data to the device
commandQueues[i].enqueueWriteBuffer(inputDataBuffer[i], CL_TRUE, 0, imageSize*sizeof(float), wt[i].data);
// Set kernel arguments
kernel[i].setArg(0, inputDataBuffer[i]);
kernel[i].setArg(1, modulusBuffer[i]);
kernel[i].setArg(2, imagewidth);
}
for (int i = 0; i < numDevices; i++){
// Run kernel
commandQueues[i].enqueueNDRangeKernel(kernel[i], cl::NullRange, globalws, localws);
}
for (int i = 0; i < numDevices; i++){
// Read the modulus back to the host
float* modulus = new float[imageSize/4];
commandQueues[i].enqueueReadBuffer(modulusBuffer[i], CL_TRUE, 0, imageSize/4*sizeof(float), modulus);
// Do something with the modulus;
}
答案 0 :(得分:3)
您的主要问题是您正在使用阻止呼叫。如果您以这种方式操作它们,那么您拥有多少设备无关紧要。由于您正在进行操作并等待它完成,因此根本没有并行化(或非常少)。你现在正在这样做:
Wr:-Copy1--Copy2--------------------
G1:---------------RUN1--------------
G2:---------------RUN2--------------
Re:-------------------Read1--Read2--
你应该改变你的代码,至少这样做:
Wr:-Copy1-Copy2-----------
G1:------RUN1-------------
G2:------------RUN2-------
Re:----------Read1-Read2--
使用此代码:
cl::NDRange globalws(imageSize);
cl::NDRange localws;
for (int i = 0; i < numDevices; i++){
// Set kernel arguments //YOU SHOULD DO THIS AT INIT STAGE, IT IS SLOW TO DO IT IN A LOOP
kernel[i].setArg(0, inputDataBuffer[i]);
kernel[i].setArg(1, modulusBuffer[i]);
kernel[i].setArg(2, imagewidth);
// Copy the input data to the device
commandQueues[i].enqueueWriteBuffer(inputDataBuffer[i], CL_FALSE, 0, imageSize*sizeof(float), wt[i].data);
}
for (int i = 0; i < numDevices; i++){
// Run kernel
commandQueues[i].enqueueNDRangeKernel(kernel[i], cl::NullRange, globalws, localws);
}
float* modulus[numDevices];
for (int i = 0; i < numDevices; i++){
// Read the modulus back to the host
modulus[i] = new float[imageSize/4];
commandQueues[i].enqueueReadBuffer(modulusBuffer[i], CL_FALSE, 0, imageSize/4*sizeof(float), modulus[i]);
}
clFinish();
// Do something with the modulus;
关于具有多个上下文的注释,取决于您是否要将两个GPU通信。只要GPU只使用它们的内存,就不会有副本开销。但是如果你经常设置/取消设置内核args,那将触发copys到其他GPU。所以,要小心。
GPU之间非通信的更安全的方法是不同的上下文。
我怀疑你的主要问题是内存副本而不是内核执行,如果你隐藏内存延迟,很可能1 GPU将满足你的需求:
Wr:-Copy1-Copy2-Copy3----------
G1:------RUN1--RUN2--RUN3------
Re:----------Read1-Read2-Read3-