是否有一个特殊的“等待事件”功能,可以在设备端同时等待3个队列,所以它不会从主机端串行等待所有队列?
是否有检查点命令发送到命令队列,以便它必须等待其他命令队列命中相同(垂直)屏障/检查点等待并从设备端继续,因此不需要主机端往返?
目前,我尝试了两种不同的版本:
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个等待命令来实现这一点,那么它也必须有一个“刷新”版本但我找不到。
有没有办法实现下面的图片,而不是在每个管道步骤之间添加刷新?
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]);
如果这个“入队障碍”可以与其他队列交谈,我怎么能实现呢?我需要保持主机端事件处于活动状态,直到所有队列都完成,或者我可以删除它们还是以后重新使用它们?从文档中看,似乎第一个屏障事件可以放到第二个队列,第二个屏障事件可以与第一个事件一起放到第三个,所以可能就像:
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”是%100可信任“不开始直到我冲洗/完成”他们?如何从主机向设备引发事件(sameEvt没有“raise”功能,是clCreateUserEvent吗?)?
所有3个队列都是有序类型,并且位于相同的上下文中。所有图形卡都不支持乱序类型。正在使用C ++绑定。
还有enqueueWaitList(这是不赞成的?)和clEnqueueMarker,但我不知道如何使用它们,文档在Khronos的网站上没有任何示例。
答案 0 :(得分:1)
您提出的问题太多,并且表达了太多的变体来为您提供唯一的解决方案,因此我将尽力回答您可以找出最合适的解决方案。
如果队列绑定到相同的上下文(可能绑定到同一上下文中的不同设备),则可以通过事件同步它们。即您可以从提交到一个队列的命令中获取事件,并使用此事件来同步提交到另一个队列的命令,例如
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和opencl_node
。 opencl_node
使用事件进行同步,并尽可能避免“主机设备”同步。但是,为同一设备使用多个队列可能会很棘手。
据我所知,Intel HD Graphics 530支持无序队列(至少是主机端)。
答案 1 :(得分:1)
你使它变得比它需要的更难。在写队列上接受一个事件。将其用作计算队列上计算的条件,并执行另一个事件。将其用作读取队列上的读取条件。没有理由强制进行任何其他同步。注意:我对规范的解释是,在将该事件用作另一个队列的条件之前,必须clFlush在您从中获取事件的队列。