Concurrency “mem_fence”是否提供了工作组之间的一致性?
我正在尝试实现所描述的边界框计算。长话短说,我有一个包围盒的二叉树。叶节点都已填充,现在是计算内部节点的时候了。除了节点(每个节点定义子/父索引)之外,每个内部节点都有一个计数器 从每个叶节点开始,访问父节点,并自动递增其标志。如果这是对节点的第一次访问,线程将退出(因为保证只初始化了一个子线程)。如果是第二次访问,则初始化两个子节点,计算其边界框,然后继续该节点的父节点 读取标志和读取其子项数据之间的Concurrency “mem_fence”是否提供了工作组之间的一致性?,concurrency,opencl,Concurrency,Opencl,我正在尝试实现所描述的边界框计算。长话短说,我有一个包围盒的二叉树。叶节点都已填充,现在是计算内部节点的时候了。除了节点(每个节点定义子/父索引)之外,每个内部节点都有一个计数器 从每个叶节点开始,访问父节点,并自动递增其标志。如果这是对节点的第一次访问,线程将退出(因为保证只初始化了一个子线程)。如果是第二次访问,则初始化两个子节点,计算其边界框,然后继续该节点的父节点 读取标志和读取其子项数据之间的mem_围栏是否足以确保子项中的数据可见 kernel void internalBounds
mem_围栏是否足以确保子项中的数据可见
kernel void internalBounds(global struct Bound * const bounds,
global unsigned int * const flags,
const global struct Node * const nodes) {
const unsigned int n = get_global_size(0);
const size_t D = 3;
const size_t leaf_start = n - 1;
size_t node_idx = leaf_start + get_global_id(0);
do {
node_idx = nodes[node_idx].parent;
write_mem_fence(CLK_GLOBAL_MEM_FENCE);
// Mark node as visited, both children initialized on second visit
if (atomic_inc(&flags[node_idx]) < 1)
break;
read_mem_fence(CLK_GLOBAL_MEM_FENCE);
const global unsigned int * child_idxs = nodes[node_idx].internal.children;
for (size_t d = 0; d < D; d++) {
bounds[node_idx].min[d] = min(bounds[child_idxs[0]].min[d],
bounds[child_idxs[1]].min[d]);
bounds[node_idx].max[d] = max(bounds[child_idxs[0]].max[d],
bounds[child_idxs[1]].max[d]);
}
} while (node_idx != 0);
}
内核void internalBounds(全局结构绑定*const绑定,
全局无符号int*const标志,
常量全局结构节点*常量节点){
const unsigned int n=获取全局大小(0);
常数大小D=3;
const size\u t leaf\u start=n-1;
size\u t node\u idx=leaf\u start+get\u global\u id(0);
做{
node_idx=节点[node_idx]。父节点;
写入内存围栏(CLK全球内存围栏);
//将节点标记为已访问,两个子节点在第二次访问时初始化
if(原子_inc(&flags[node_idx])<1)
打破
read_mem_fence(CLK_GLOBAL_mem_fence);
常量全局无符号int*child_idxs=节点[node_idx].internal.children;
对于(大小d=0;d
我仅限于OpenCL 1.2。不,它没有。CLK_GLOBAL_MEM_FENCE仅在访问全局内存时提供工作组内的一致性。OpenCL1.x中没有工作组间同步
尝试使用单个大型工作组并迭代数据。和/或从适合单个工作组的小树开始 没有。CLK_GLOBAL_MEM_FENCE仅在访问全局内存时提供工作组内的一致性。OpenCL1.x中没有工作组间同步
尝试使用单个大型工作组并迭代数据。和/或从适合单个工作组的小树开始
mem_fence(…)
仅为单个工作项同步mem访问。即使所有工作项都有这一行,它们也可能不会同时命中(并继续)它
barrier(…)
对工作组中的所有工作项进行同步,并让它们等待最慢的一个(即isa访问作为参数给定的指定内存),但只连接到其自己的工作组工作项。(例如,对于amd intel,只有64或256个,对于nvidia,可能是1024个)因为opencl设备驱动程序实现可能被设计为在加载新的波前碎片之前完成所有波前,因为所有全局项根本无法装入芯片内存(例如64M工作项,每个工作项使用1kB本地内存,需要64GB内存!-->即使是软件仿真也需要数百或数千次传递,并将性能降低到单核cpu的水平)
无法进行全局同步(所有工作组都已同步)
为了防止工作项工作组和处理元素的含义混淆,
您放在那里的原子函数已经在访问全局内存,所以添加组作用域同步应该不重要
如果需要,还要检查机器代码
bounds[child_idxs[0]].min[d]
在访问min[d]
之前,正在将整个bounds[child_idxs[0]]]
结构获取到私有内存中。如果是,您可以将min作为一个独立的数组单独访问它的项,以便为它增加100%的内存带宽
在intel hd 400上测试,超过100000个线程
__kernel void fenceTest( __global float *c,
__global int *ctr)
{
int id=get_global_id(0);
if(id<128000)
for(int i=0;i<20000;i++)
{
c[id]+=ctr[0];
mem_fence(CLK_GLOBAL_MEM_FENCE);
}
ctr[0]++;
}
表现得一模一样
int id=get_global_id(0);
if(id==0)
{
ctr[0]++;
mem_fence(CLK_GLOBAL_MEM_FENCE);
}
mem_fence(CLK_GLOBAL_MEM_FENCE);
c[id]+=ctr[0];
对于此Intel igpu设备(只是偶然,但它证明更改的内存在“所有”后续线程中可见,但不能证明它总是发生(例如,第一个计算单元打嗝,第二个首先启动),并且对于访问它的多个单线程而言,它不是原子的)。
mem_fence(…)
只同步单个工作项的mem访问。即使所有工作项都有此行,它们也可能不会同时命中(并继续)它
barrier(…)
对工作组中的所有工作项进行同步,并让它们等待最慢的一个(即isa访问作为参数给定的指定内存),但只连接到其自己的工作组工作项。(例如,对于amd intel,只有64或256个,对于nvidia,可能是1024个)因为opencl设备驱动程序实现可能被设计为在加载新的波前碎片之前完成所有波前,因为所有全局项根本无法装入芯片内存(例如64M工作项,每个工作项使用1kB本地内存,需要64GB内存!-->即使是软件仿真也需要数百或数千次传递,并将性能降低到单核cpu的水平)
无法进行全局同步(所有工作组都已同步)
为了防止工作项工作组和处理元素的含义混淆,
您放在那里的原子函数已经在访问全局内存,所以添加组作用域同步应该不重要
如果需要,还要检查机器代码
bounds[child_idxs[0]].min[d]
在访问min[d]
之前,正在将整个bounds[child_idxs[0]]]
结构获取到私有内存中。如果是,您可以将min作为一个独立的数组单独访问它的项,以便为它增加100%的内存带宽
在intel hd 400上测试,超过10
int id=get_global_id(0);
if(id==0)
{
ctr[0]++;
mem_fence(CLK_GLOBAL_MEM_FENCE);
}
mem_fence(CLK_GLOBAL_MEM_FENCE);
c[id]+=ctr[0];