如何在OpenCL中基于数据同步(特定)工作项? 背景:
需要模拟一组相关的离散元件(复杂电子电路)。因此,每个组件从其他几个组件接收输入,并输出到其他几个组件 预期的设计是有一个如何在OpenCL中基于数据同步(特定)工作项? 背景:,opencl,gpgpu,Opencl,Gpgpu,需要模拟一组相关的离散元件(复杂电子电路)。因此,每个组件从其他几个组件接收输入,并输出到其他几个组件 预期的设计是有一个内核,配置参数定义了它应该表示的组件。电路的每个组件都由一个工作项表示,并且所有电路都将适合于单个工作组(或者将电路进行适当的拆分,以便每个工作组可以将所有组件作为工作项进行管理) 问题是: 有可能吗?万一有,怎么可能?是否让某些工作项等待其他工作项数据? 工作项(在数据驱动位置)生成到阵列的输出。另一个工作项需要等待这种情况发生,然后才能开始进行处理。 网络没有循环,因此,
内核
,配置参数定义了它应该表示的组件。电路的每个组件都由一个工作项表示,并且所有电路都将适合于单个工作组(或者将电路进行适当的拆分,以便每个工作组可以将所有组件作为工作项进行管理)
问题是:
有可能吗?万一有,怎么可能?是否让某些工作项等待其他工作项数据?
工作项(在数据驱动位置)生成到阵列的输出。另一个工作项需要等待这种情况发生,然后才能开始进行处理。
网络没有循环,因此,单个工作项不可能需要运行两次
尝试:
在以下示例中,每个元件最多可以有一个单一输入(以简化),使电路成为一棵树,其中电路的输入为根,3个输出为叶
inputIndex
通过为每个组件指示哪个其他组件提供输入,对该树进行建模。第一个组件将自身作为输入,但内核管理这种情况(为了简化)
result
保存每个组件的结果(电压、强度等)
inputModified
指示给定组件是否已计算其输出
// where the data come from (index in result)
constant int inputIndex[5]={0,0, 0, 2, 2};
kernel void update_component(
local int *result, // each work-item result.
local int *inputModified // If all inputs are ready (one only for this example)
) {
int id = get_local_id(0);
int size = get_local_size(0);
int barrierCount = 0;
// inputModified is a boolean indicating if the input is ready
inputModified[id]=(id!=0 ? 0 : 1);
// make sure all input are false by default (except the first input).
barrier(CLK_LOCAL_MEM_FENCE);
// Wait until all inputs are ready (only one in this example)
while( !inputModified[inputIndex[id]] && size > barrierCount++)
{
// If the input is not ready, wait for it
barrier(CLK_LOCAL_MEM_FENCE);
}
// all inputs are ready, compute output
if (id!=0) result[id] = result[inputIndex[id]]+1;
else result[0]=42;
// make sure any other work-item depending on this is unblocked
inputModified[id]=1;
// Even if finished, we needs to "barrier" for other working items.
while (size > barrierCount++)
{
barrier(CLK_LOCAL_MEM_FENCE);
}
}
本例中N个组件有N个屏障,这比顺序解决方案更糟糕
注:这只是内核,因为C++最小主机相当长。如果需要的话,我可以想办法添加它
问题:
是否可以通过内核本身高效地让不同的工作项等待其他工作项提供它们的数据?或者哪种解决方案更有效?
这个问题(对我来说)很难解释,而且我还远不是OpenCL方面的专家。请耐心等待,并随时询问是否有任何不清楚的地方。来自屏障文档 如果屏障位于循环内,则所有工作项必须在允许任何工作项继续之前为循环的每次迭代执行屏障 超越障碍的执行 但是内核中的while循环(包含屏障)具有以下条件:
inputModified[inputIndex[id]]
这可能会更改其id为线程的行为,并导致未定义的行为。此外,这之前还有一个障碍
barrier(CLK_LOCAL_MEM_FENCE);
已经同步了工作组中的所有工作项,因此while循环是冗余的,即使它可以工作
最后一个屏障回路也是冗余的
while (size > barrierCount++)
{
barrier(CLK_LOCAL_MEM_FENCE);
}
当内核结束时,它会同步所有工作项
如果您打算向工作组外的工作项发送一些消息,那么您只能使用原子变量。即使在使用原子时,也不应在任何两个工作项之间假设任何工作/发布顺序
你的问题
怎么做?是否让某些工作项等待其他工作项数据?A.
工作项生成到阵列的输出(在数据驱动位置)。
另一个工作项需要等待这种情况发生后才能开始
使之成为一种加工方式。网络没有环路,因此,这是不可能的
单个工作项需要运行两次
可以用OpenCL2.x的“动态并行”特性来回答这个问题,该特性允许工作项在内核中生成新的工作组/内核。它比在自旋等待循环中等待要高效得多,并且比依赖GPU支持的正在运行的线程数量(当GPU不能处理那么多正在运行的线程时,任何自旋等待都会死锁,线程的顺序无关紧要)
当您使用barrier时,不需要通知其他线程“inputModified”。结果的数据在工作组中已可见
如果不能使用OpenCL v2.x,则应使用BFS处理树:
- 为顶部节点启动1个工作项
- 处理它,准备K个输出,并将它们放入队列
- 端核
- 启动K个工作项(队列中的每个pop元素)
- 处理它们,准备N个输出,并将它们推入队列
- 端核
- 重复此操作,直到队列中不再有任何元素