openmp部分中的Opencl独立队列和clFinish

时间:2014-02-08 16:27:35

标签: c++ opencl openmp

我正在制作一个opencl包装器,它为每个缓冲区使用不同的命令队列。

所有读/写操作都是非阻塞的。

问题是,没有发出其中一个读/写操作(从profiler看来)。 CodeXL分析器显示孔。我在照片上标记了它们。

enter image description here

问题:什么可能导致这个问题?我检查了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();
    }
}

仔细看看:

看到右侧的蓝色条纹,其中一条缺失了一些。 enter image description here

设备:HD7870 主持人:FX8150

Opencl 1.2 C ++绑定。

1 个答案:

答案 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;数据传输?这将允许您摆脱同步点。