我正在制作一个opencl包装器,它为每个缓冲区使用不同的命令队列。
所有读/写操作都是非阻塞的。
问题是,没有发出其中一个读/写操作(从profiler看来)。 CodeXL分析器显示孔。我在照片上标记了它们。
问题:什么可能导致这个问题?我检查了cl错误,但都给了CL_SUCCESS。
c ++ opencl 1.2程序的流程:
(from main thread)
issue write buffer 0
issue write buffer 1
issue write buffer N
(from many threads by openmp body)
clFinish(queue0)
clFinish(queue1)
clFinish(queue2)
(from main thread)
issue kernel 0
issue kernel 1
issue kernel N
clFinish(kernelQueue)
(from main thread)
issue read buffer 0
issue read buffer 1
issue read buffer N
(from many threads by openmp body)
clFinish(queue0)
clFinish(queue1)
clFinish(queue2) ----> has some holes!!!
clFinish(queueN)
以下是主线程的外观:
void Air::update_air_and_h_gpu(void)
{
if (airMode != 4)
{
/* update air*/
gpu->WriteToClFrom2DCPP("pv",&pv[0][0]);
gpu->WriteToClFrom2DCPP("vx",&vx[0][0]);
gpu->WriteToClFrom2DCPP("vy",&vy[0][0]);
gpu->WriteToClFrom2DCPP("fvx",&fvx[0][0]);
gpu->WriteToClFrom2DCPP("fvy",&fvy[0][0]);
gpu->WriteToClFrom2DCPP("bmap_blockair",&bmap_blockair[0][0]);
gpu->WriteToClFrom2DCPP("bmap",&bmap[0][0]);
gpu->WriteToClFromCPP("kernelArr",&kernel[0]);
/* update heat*/
gpu->WriteToClFrom2DCPP("hv",&hv[0][0]);
gpu->WriteToClFrom2DCPP("ambientAirTemp",&(ambientAirTemp));
gpu->WriteToClFrom2DCPP("gravityMode",&(sim.gravityMode));
gpu->WriteToClFrom2DCPP("bmap_blockairh",&bmap_blockairh[0][0]);
gpu->syncW();
/* update air*/
gpu->Compute("UpdateAirReduceEdge0");
gpu->Compute("UpdateAirReduceEdge1");
gpu->Compute("UpdateAirClearVelWall");
gpu->Compute("UpdateAirPressAdjVel");
gpu->Compute("UpdateAirVelAdjPress");
gpu->Compute("UpdateAirBigLoop");
gpu->Compute("UpdateAirBigLoop2");
/* update heat*/
gpu->Compute("UpdateAirHeatLoop0");
gpu->Compute("UpdateAirHeatLoop1");
gpu->Compute("UpdateAirHeatLastLoop");
gpu->Compute("UpdateAirHeatLastLoop2");
gpu->sync();
/*update air*/
gpu->ReadFromClTo2DCPP("pv",&pv[0][0]);
gpu->ReadFromClTo2DCPP("vx",&vx[0][0]);
gpu->ReadFromClTo2DCPP("vy",&vy[0][0]);
/* update heat*/
gpu->ReadFromClTo2DCPP("hv",&hv[0][0]);
gpu->syncR();
}
}
以下是gpu-> syncR()和gpu-> syncW是如何通过openmp完成的(在选项中也激活):
void syncR()
{
omp_set_num_threads(2); //tried 8 but holes still exist
#pragma omp parallel for
for(int i=0;i<cqR.size();i++)
{
cqR[i].finish();
}
}
void syncW()
{
omp_set_num_threads(2); //tried 8 but holes still exist
#pragma omp parallel for
for(int i=0;i<cqW.size();i++)
{
cqW[i].finish();
}
}
仔细看看:
看到右侧的蓝色条纹,其中一条缺失了一些。
设备:HD7870 主持人:FX8150
Opencl 1.2 C ++绑定。
答案 0 :(得分:1)
为每个mem对象使用单独的命令队列IMHO看起来不是最佳实践。在这种情况下,您在每个队列的范围内很少发出命令。命令不能重新排序,放入传送带等。简单地说 - 你不能从大规模的数据传输中受益。你在多个队列处理上浪费你的CPU资源。我的建议是使用几个命令队列与OpenMP线程安全访问:
cl_command_queue
q_DtoH = clCreateCommandQueue(...),
q_DtoD = clCreateCommandQueue(...)
...;
#pragma omp parallel for
for(;;)
{
#pragma omp critical
clEnqueueNDWriteBuffer(q_DtoH, ...); //Or whatever else
....
}
理想情况下,尝试使用带有事件同步的无序队列进行数据传输。此外,对象引用计数用于调试目的(推测,您的命令队列使用相同的上下文,您可以检查它的引用计数)。
并且,在您的代码段中:
/* update heat*/
....
gpu->Compute("UpdateAirHeatLoop0");
gpu->sync();
/*update air*/
gpu->ReadFromClTo2DCPP("pv",&pv[0][0]);
...
为什么不使用相同的命令队列来发出内核执行&amp;数据传输?这将允许您摆脱同步点。