OpennCL 中有散射原语吗?
Is there a scatter primitive in OpennCL?
我正在按照此处所述实施拆分操作:https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch39.html。目前我正在尝试实现分散步骤。
scatter 只是执行类似于 OpenCL 的 shuffle 操作(此处:https://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/shuffle.html)的操作,但在一般工作组(__local)数组而不是向量上.
我试图在 OpenCL 文档中找到对此操作的支持,但没有成功。
是否有本机 OpenCL 支持此操作,如果没有,是否有一些论文或文章可以找到实现此操作的有效算法?
一个可能有用的说明,我正在使用 AMD 的实现,所以如果有 AMD 专门提供的解决方案,那就没问题了。但是,通用解决方案要好得多。
这是我试图用代码完成的。这是一个 OpenCL 函数,稍后将由另一个实现基数排序的内核调用:
void Split(__local uint local_keys[256], uint cur_bit, int local_id)
{
__local uint e[256];
__local uint f[256];
__local uint t[256];
__local uint d[256];
e[local_id] = !(local_keys[local_id] & (1 << cur_bit));
f[local_id] = work_group_scan_exclusive_add(e[local_id]);
work_group_barrier(CLK_LOCAL_MEM_FENCE);
uint total_falses = e[255] + f[255];
t[local_id] = local_id - f[local_id] + total_falses;
d[local_id] = e[local_id] ? f[local_id] : t[local_id];
work_group_barrier(CLK_LOCAL_MEM_FENCE);
// TODO scatter .... (Please see last step of the attached image)
.......
}
在我看来,唯一的解决办法是使用辅助数组。像您指出的那样的特殊说明仅对可以保存在寄存器中的数组有效。当您跨越本地内存边界时它们无效,因为那时它需要工作项同步。
在您的过程中,您使用了 4 个本地 uint 向量。这意味着您需要同时分配该数量的本地内存。因此,分配一个辅助数组来进行改组不应使用比您目前已经使用的内存更多的内存。
注意:编译器会意识到 e、f、t 的范围在您计算出值 d 后消失。所以临时数组不应该使用额外的内存,因为它可以重用以前的内存。您还可以使用 { }
.
向编译器提示
void Split(__local uint local_keys[256], uint cur_bit, int local_id)
{
__local uint e[256];
__local uint f[256];
__local uint t[256];
__local uint d[256];
__local uint temp[256];
e[local_id] = !(local_keys[local_id] & (1 << cur_bit));
f[local_id] = work_group_scan_exclusive_add(e[local_id]);
work_group_barrier(CLK_LOCAL_MEM_FENCE);
uint total_falses = e[255] + f[255];
t[local_id] = local_id - f[local_id] + total_falses;
d[local_id] = e[local_id] ? f[local_id] : t[local_id];
temp[local_id] = local_keys[local_id];
work_group_barrier(CLK_LOCAL_MEM_FENCE);
local_keys[d[local_id]] = temp[local_id];
}
我正在按照此处所述实施拆分操作:https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch39.html。目前我正在尝试实现分散步骤。
scatter 只是执行类似于 OpenCL 的 shuffle 操作(此处:https://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/shuffle.html)的操作,但在一般工作组(__local)数组而不是向量上.
我试图在 OpenCL 文档中找到对此操作的支持,但没有成功。
是否有本机 OpenCL 支持此操作,如果没有,是否有一些论文或文章可以找到实现此操作的有效算法?
一个可能有用的说明,我正在使用 AMD 的实现,所以如果有 AMD 专门提供的解决方案,那就没问题了。但是,通用解决方案要好得多。
这是我试图用代码完成的。这是一个 OpenCL 函数,稍后将由另一个实现基数排序的内核调用:
void Split(__local uint local_keys[256], uint cur_bit, int local_id)
{
__local uint e[256];
__local uint f[256];
__local uint t[256];
__local uint d[256];
e[local_id] = !(local_keys[local_id] & (1 << cur_bit));
f[local_id] = work_group_scan_exclusive_add(e[local_id]);
work_group_barrier(CLK_LOCAL_MEM_FENCE);
uint total_falses = e[255] + f[255];
t[local_id] = local_id - f[local_id] + total_falses;
d[local_id] = e[local_id] ? f[local_id] : t[local_id];
work_group_barrier(CLK_LOCAL_MEM_FENCE);
// TODO scatter .... (Please see last step of the attached image)
.......
}
在我看来,唯一的解决办法是使用辅助数组。像您指出的那样的特殊说明仅对可以保存在寄存器中的数组有效。当您跨越本地内存边界时它们无效,因为那时它需要工作项同步。
在您的过程中,您使用了 4 个本地 uint 向量。这意味着您需要同时分配该数量的本地内存。因此,分配一个辅助数组来进行改组不应使用比您目前已经使用的内存更多的内存。
注意:编译器会意识到 e、f、t 的范围在您计算出值 d 后消失。所以临时数组不应该使用额外的内存,因为它可以重用以前的内存。您还可以使用 { }
.
void Split(__local uint local_keys[256], uint cur_bit, int local_id)
{
__local uint e[256];
__local uint f[256];
__local uint t[256];
__local uint d[256];
__local uint temp[256];
e[local_id] = !(local_keys[local_id] & (1 << cur_bit));
f[local_id] = work_group_scan_exclusive_add(e[local_id]);
work_group_barrier(CLK_LOCAL_MEM_FENCE);
uint total_falses = e[255] + f[255];
t[local_id] = local_id - f[local_id] + total_falses;
d[local_id] = e[local_id] ? f[local_id] : t[local_id];
temp[local_id] = local_keys[local_id];
work_group_barrier(CLK_LOCAL_MEM_FENCE);
local_keys[d[local_id]] = temp[local_id];
}