【发布时间】:2011-10-21 06:01:27
【问题描述】:
在我的内核中,有必要对一个小的查找表(只有 8 个 32 位整数)进行大量随机访问。每个内核都有一个唯一的查找表。下面是内核的简化版本,用于说明如何使用查找表。
__kernel void some_kernel(
__global uint* global_table,
__global uint* X,
__global uint* Y) {
size_t gsi = get_global_size(0);
size_t gid = get_global_id(0);
__private uint LUT[8]; // 8 words of of global_table is copied to LUT
// Y is assigned a value from the lookup table based on the current value of X
for (size_t i = 0; i < n; i++) {
Y[i*gsi+gid] = LUT[X[i*gsi+gid]];
}
}
由于体积小,我通过将表保存在 __private 内存空间中获得了最佳性能。但是,由于访问查找表的随机性,仍然存在很大的性能损失。删除查找表代码(例如,替换为简单的算术运算)后,虽然内核会提供错误的答案,但性能提高了 3 倍以上。
有没有更好的方法?我是否忽略了一些为非常小的内存块提供有效随机访问的 OpenCL 功能?是否有使用向量类型的有效解决方案?
[edit] 注意,X 的最大值为 7,但 Y 的最大值为 2^32-1。换句话说,查找表的所有位都在使用,因此不能将其打包成更小的表示形式。
【问题讨论】:
-
只是为了确保我理解正确,LUT[] 和 X[] 对于每个工作项都是唯一的吗?
-
您是否尝试过将
__constant内存用于查找表? GPU 通常为恒定内存实现单独的缓存和内存访问路径,以加快共享查找表之类的速度。 -
我确实尝试将 global_table 作为 __constant 传递,但由于某种原因,它对性能没有帮助。每个内核都在 global_table、X 和 Y 的独立部分上运行(取决于线程 ID)。
-
如果是这种情况,__constant 很可能无济于事,因为至少在我见过的大多数 GPU 上,它基本上是一个用于全局内存的小型缓存。如果每个线程读取不同的值,缓存将无济于事。
-
英特尔的 OpenCL 指南谈到了将“共享本地内存”用于 LUT。 software.intel.com/en-us/articles/… 一般可能有用。
标签: opencl