Synchronization 如何将设备端命令队列与主机端队列同步?clFinish()和markerWithWaitList给出的队列错误无效

Synchronization 如何将设备端命令队列与主机端队列同步?clFinish()和markerWithWaitList给出的队列错误无效,synchronization,opencl,dynamic-parallelism,Synchronization,Opencl,Dynamic Parallelism,我正在使用OpenCL2.0动态并行特性,让每个工作项使用单个工作项将另一个内核排队。当子内核的工作完成时间很长时,父内核在子内核之前完成,内存一致性不会得到保留,并且会返回损坏的数据(随机更新的数据项) 由于clFinish()和clEnqueueMarkerWithWaitList()用于仅主机队列,因此我不能将它们用于设备无序队列上的此默认值 如何使子内核在某个同步点之前或至少在缓冲区读取命令之前完成,以实现内存一致性 代码如下: __kernel void test( __global

我正在使用OpenCL2.0动态并行特性,让每个工作项使用单个工作项将另一个内核排队。当子内核的工作完成时间很长时,父内核在子内核之前完成,内存一致性不会得到保留,并且会返回损坏的数据(随机更新的数据项)

由于clFinish()和clEnqueueMarkerWithWaitList()用于仅主机队列,因此我不能将它们用于设备无序队列上的此默认值

如何使子内核在某个同步点之前或至少在缓冲区读取命令之前完成,以实现内存一致性

代码如下:

__kernel void test( __global float *xyz,__global float *xyzn,__global float *xyzo,__global float * arguments)
{
    int threadId=get_global_id(0);
    float dx=xyz[threadId*3]-arguments[2];float dy=xyz[threadId*3+1]-arguments[3];float t=arguments[1];
    float ctr=arguments[0];float wave=0.02f*ctr*sin(40.0f*t+100.0f*sqrt(dx*dx+dy*dy));
    xyzo[threadId*3]=xyz[threadId*3]+xyzn[threadId*3]*wave; // wave equation for all surface vertices
    xyzo[threadId*3+1]=xyz[threadId*3+1]+xyzn[threadId*3+1]*wave; // wave equation for all surface vertices
    xyzo[threadId*3+2]=xyz[threadId*3+2]+xyzn[threadId*3+2]*wave; // wave equation for all surface vertices
}

__kernel void waveEquation( __global float *xyz,__global float *xyzn,__global float *xyzo,__global float * arguments)
{
    int threadId=get_global_id(0);
    if(threadId<arguments[4])
    {
            queue_t q = get_default_queue();
            ndrange_t ndrange = ndrange_1D(threadId,1,1);
            void (^my_block_A)(void) = ^{test(xyz,xyzn,xyzo,arguments);};
            enqueue_kernel(q, CLK_ENQUEUE_FLAGS_NO_WAIT,ndrange,my_block_A);

    }

}
编辑:这种创建队列的方式也不能使其同步:

cl_uint qs=device.getInfo<CL_DEVICE_QUEUE_ON_DEVICE_PREFERRED_SIZE>();
cl_queue_properties qprop[] = { CL_QUEUE_SIZE, qs, CL_QUEUE_PROPERTIES, 
     (cl_command_queue_properties)(CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE |
                                   CL_QUEUE_ON_DEVICE | 
                                   CL_QUEUE_ON_DEVICE_DEFAULT | 
                                   CL_QUEUE_PROFILING_ENABLE), 0 };
device_queue = clCreateCommandQueueWithProperties(context.get(),
                                   device.get(), qprop, &err);

这不起作用,但是完成了,所以没有无限循环。

你应该考虑使用EnQueLeGyMys:

规范中还有一个示例,其中多个内核排队,使用enqueue_marker命令,您可以等待子内核完成,然后继续处理父内核。示例代码如下:

编辑:经过多次实验,结果如下:
随着父内核启动的子内核数量的增加,程序将失败。这可能是由huseyin tugrul buyukisik建议的队列大小引起的。尽管执行不会返回错误代码,但结果是不正确的。OpenCL规范中没有提到此类问题。

这些是内核端事件和标记,对吗?我会努力的。看看我问题的结尾,没用。同样,这对
CLK\u ENQUEUE\u FLAGS\u WAIT\u KERNEL
也不起作用,因为这会强制子内核等待父内核首先完成,而标记已经在等待子内核,从而造成死锁。不仅不起作用,而且还卡住了计算,我不得不按ctrl-alt-del键。若所有enqueue_内核调用的数量大于队列大小,会发生什么情况?他们不是在排队等候准备吗?还是它导致了这个?当我将父内核工作项减少到224个,并让每个工作项生成一个包含256个工作项而不是1个工作项的子内核时,它可以工作,但我还必须在“-CL std=CL2.0”的基础上向clBuildProgram()添加“-g-D CL_VERSION_2_0”。我不知道为什么这样做有效,也不知道队列大小是否有问题。首先,内核需要使用CLK_ENQUEUE_FLAGS_NO_WAIT来确保不会出现死锁。您最初的代码也使用了该标志,所以我认为您会使用它。尽管如此,我认为OpenCL规范将处理此类死锁留给程序员。谢谢,您认为队列大小如何?如果我让内核排队100k次,如果队列大小为50k,这是否会产生一个不可见的错误,例如重新使用队列位置,其中充满了等待计算的内核?或者,设备队列像管道一样工作,在计算某些内核之前阻止新的排队命令?主机队列至少像管道一样工作,它们异步运行,而主机将新命令排入队列,如果没有剩余空间,则阻塞。
cl_uint qs=device.getInfo<CL_DEVICE_QUEUE_ON_DEVICE_PREFERRED_SIZE>();
cl_queue_properties qprop[] = { CL_QUEUE_SIZE, qs, CL_QUEUE_PROPERTIES, 
     (cl_command_queue_properties)(CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE |
                                   CL_QUEUE_ON_DEVICE | 
                                   CL_QUEUE_ON_DEVICE_DEFAULT | 
                                   CL_QUEUE_PROFILING_ENABLE), 0 };
device_queue = clCreateCommandQueueWithProperties(context.get(),
                                   device.get(), qprop, &err);
if(threadId<arguments[4])
{
        clk_event_t markerEvent;
        clk_event_t events[1];
        queue_t q = get_default_queue();
        ndrange_t ndrange = ndrange_1D(threadId,1,1);
        void (^my_block_A)(void) = ^{test(xyz,xyzn,xyzo,arguments);};
        enqueue_kernel(q, CLK_ENQUEUE_FLAGS_NO_WAIT,ndrange,0,NULL,&events[0],my_block_A);
        enqueue_marker(q, 1, events, &markerEvent);

        release_event(events[0]);
        release_event(markerEvent);

}
queue_t q = get_default_queue();
ndrange_t ndrange = ndrange_1D(threadId,1,1);
void (^my_block_A)(void) = ^{test(xyz,xyzn,xyzo,arguments);};
int ctr=0;
while((enqueue_kernel(q, CLK_ENQUEUE_FLAGS_NO_WAIT,ndrange,my_block_A)&
        (   CLK_DEVICE_QUEUE_FULL|
            CLK_EVENT_ALLOCATION_FAILURE|
            CLK_OUT_OF_RESOURCES |
            CLK_INVALID_NDRANGE |
            CLK_INVALID_QUEUE |
            CLK_INVALID_EVENT_WAIT_LIST |
            CLK_INVALID_ARG_SIZE
        ))>0 )
{
}