3 个队列 + 所有队列的 1 个完成或设备端检查点

3 queues + 1 finish or device-side checkpoints for all queues

是否有一个特殊的"wait for event"函数可以在设备端同时等待3个队列而不是从主机端串行等待所有队列?

是否有一个检查点命令发送到命令队列中,这样它必须等待其他命令队列命中相同(垂直)barrier/checkpoint等待并从设备端继续,所以没有主机端循环-需要旅行吗?

目前,我尝试了两个不同的版本:

clWaitForEvents(3, evt_);

int evtStatus0 = 0;
clGetEventInfo(evt_[0], CL_EVENT_COMMAND_EXECUTION_STATUS,
    sizeof(cl_int), &evtStatus0, NULL);

while (evtStatus0 > 0)
{

    clGetEventInfo(evt_[0], CL_EVENT_COMMAND_EXECUTION_STATUS,
        sizeof(cl_int), &evtStatus0, NULL);
    Sleep(0);
}

int evtStatus1 = 0;
clGetEventInfo(evt_[1], CL_EVENT_COMMAND_EXECUTION_STATUS,
    sizeof(cl_int), &evtStatus1, NULL);

while (evtStatus1 > 0)
{

    clGetEventInfo(evt_[1], CL_EVENT_COMMAND_EXECUTION_STATUS,
        sizeof(cl_int), &evtStatus1, NULL);
    Sleep(0);
}


int evtStatus2 = 0;
clGetEventInfo(evt_[2], CL_EVENT_COMMAND_EXECUTION_STATUS,
    sizeof(cl_int), &evtStatus2, NULL);

while (evtStatus2 > 0)
{

    clGetEventInfo(evt_[2], CL_EVENT_COMMAND_EXECUTION_STATUS,
        sizeof(cl_int), &evtStatus2, NULL);

    Sleep(0);
}

第二个快一点(我从别人那里看到的)并且都在 3 个刷新命令后执行。

查看 CodeXL 探查器结果,第一个在完成点之间等待的时间更长,而且一些操作甚至似乎没有重叠。第二个显示3个结束点都在3毫秒以内,所以它更快,更长的部分重叠(同时读取+写入+计算)。

如果有一种方法可以仅通过主机端的 1 个等待命令实现此目的,那么也必须有一个 "flush" 版本,但我找不到。

有什么方法可以实现下图,而不是在每个管道步骤之间添加刷新?

queue1 write checkpoint write    checkpoint write
queue2  -               compute  checkpoint compute checkpoint compute
queue3  -                        checkpoint read    checkpoint read     

所有检查点都必须垂直同步,所有这些动作必须在发出信号后才能开始。如:

queue1.ndwrite(...);
queue1.ndcheckpoint(...);
queue1.ndwrite(...);
queue1.ndcheckpoint(...);
queue1.ndwrite(...);
queue2.ndrangekernel(...);
queue2.ndcheckpoint(...);
queue2.ndrangekernel(...);
queue2.ndcheckpoint(...);
queue2.ndrangekernel(...);
queue3.ndread(...);
queue3.ndcheckpoint(...);
queue3.ndread(...);
queue3.ndcheckpoint(...);
queue3.ndread(...);

queue1.flush() 
queue2.flush()
queue3.flush()

queue1.finish()
queue2.finish()
queue3.finish()

检查点都在设备端处理,主机端只需要 3 个完成命令(更好的是,所有队列只需要 1 个完成?)

我现在如何使用 "clWaitForEvents(3, evt_);" 将 3 个队列绑定到 3 个事件是:

hCommandQueue->commandQueue.enqueueBarrierWithWaitList(NULL, &evt[0]);
hCommandQueue2->commandQueue.enqueueBarrierWithWaitList(NULL, &evt[1]);
hCommandQueue3->commandQueue.enqueueBarrierWithWaitList(NULL, &evt[2]);

如果这个 "enqueue barrier" 可以与其他队列通信,我该如何实现?我是否需要让主机端事件保持活动状态直到所有队列都完成,或者我可以删除它们或稍后重新使用它们?从文档来看,似乎第一个障碍事件可以放入第二个队列,第二个障碍事件可以与第一个事件一起放入第三个队列,所以可能是这样的:

hCommandQueue->commandQueue.enqueueBarrierWithWaitList(NULL, &evt[0]);
hCommandQueue2->commandQueue.enqueueBarrierWithWaitList(evt_0, &evt[1]);
hCommandQueue3->commandQueue.enqueueBarrierWithWaitList(evt_0_and_1, &evt[2]);

in the end wait for only evt[2] maybe or using only 1 same event for all:

hCommandQueue->commandQueue.enqueueBarrierWithWaitList(sameEvt, &evt[0]);
hCommandQueue2->commandQueue.enqueueBarrierWithWaitList(sameEvt, &evt[1]);
hCommandQueue3->commandQueue.enqueueBarrierWithWaitList(sameEvt, &evt[2]);

where to get sameEvt object?

有人试过这个吗?我是否应该使用屏障启动所有队列,以便它们在我从主机端引发某些事件之前不会启动,或者 "enqueue" 的延迟执行对 "not to start until I flush/finish" 它们是 %100 可信的?如何从主机向设备引发事件(sameEvt 没有 "raise" 函数,是 clCreateUserEvent 吗?)?

所有 3 个队列都是有序类型并且在相同的上下文中。并非所有显卡都支持乱序类型。正在使用 C++ 绑定。

还有 enqueueWaitList(是否已弃用?)和 clEnqueueMarker,但我不知道如何使用它们,并且文档在 Khronos 的网站上没有任何示例。

你问的问题太多,表达的变体太多,无法给你提供唯一的解决方案,所以我会尽量笼统地回答,让你找出最合适的解决方案。

如果队列绑定到相同的上下文(可能绑定到同一上下文中的不同设备),则可以通过事件同步它们。 IE。您可以从提交到一个队列的命令中获取一个事件,并使用此事件来同步提交到另一个队列的命令,例如

queue1.enqueue(comm1, /*dependency*/ NULL, /*result event*/ &e1);
queue2.enqueue(comm2, /*dependency*/ &e1, /*result event*/ NULL);

在此示例中,comm2 将等待 comm1 完成。

如果您需要先将命令加入队列但不允许执行它们,您可以创建用户事件 (clCreateUserEvent) 并手动发出信号 (clSetUserEventStatus)。允许实现在命令入队后立即处理命令(驱动程序不需要等待 flush)。

对于您的目的而言,障碍似乎有些过分,因为它等待之前提交到队列的所有命令。你真的可以使用clEnqueueMarker,它可以用来等待所有事件,并提供一个事件用于其他命令。

据我所知,如果您不再需要它,您可以随时保留该事件。如果出于内部目的需要,实施应延长事件生命周期。

我不知道什么是 enqueueWaitList

题外话:如果您需要计算之间的重要依赖关系,您可能需要考虑 TBB flow graph and opencl_nodeopencl_node 使用事件进行同步,并尽可能避免 "host-device" 同步。但是,为同一设备使用多个队列可能会很棘手。

据我所知,Intel HD Graphics 530 支持无序队列(至少在主机端)。

你让它变得比需要的更难。在写队列上取一个事件。将其用作计算队列上计算的条件,并获取另一个事件。将其用作读取队列上读取的条件。没有理由强制任何其他同步。注意:我对规范的解释是,在将事件用作另一个队列的条件之前,必须对从中获取事件的队列执行 clFlush。