我刚刚问过自己,使用例如 threadIdx.x 进行的复杂索引计算是否会对性能产生影响。内核上传到设备后,这些变量是否会保持不变?
我想导航到一个巨大的数组,其中索引取决于 threadIdx.x、threadIdx.y 和 threadIdx.z。我需要例如模运算,例如
array[threadIdx.y % 2 + ...]
我刚刚问过自己,使用例如 threadIdx.x 进行的复杂索引计算是否会对性能产生影响。内核上传到设备后,这些变量是否会保持不变?
我想导航到一个巨大的数组,其中索引取决于 threadIdx.x、threadIdx.y 和 threadIdx.z。我需要例如模运算,例如
array[threadIdx.y % 2 + ...]
您的索引计算中有一个加法和一个模数。
来自 CUDA 编程指南: 的吞吐量operator+
非常高(3.5 计算能力的 GPU 为 160)。
operator%
需要数十个操作,其吞吐量类似于operator+
.
在您的情况下,您使用operator%
的是文字常量,编译器很可能会对其进行优化。此外,您的常数是两个数字 (2) 的幂,因此编译器将用按位替换它operator&
(与 相同的吞吐量operator+
)。
分析您的应用程序以避免浪费时间优化算术运算而没有获得任何性能是很重要的。算术运算通常被内存加载和存储操作完全隐藏,在这种情况下,您需要专注于优化内存吞吐量。
我假设
array[threadIdx.y % 2 + ...]
只是一个例子。
一般来说,%
操作可能很慢。加快指数计算的一个有用技巧是注意到
foo%n==foo&(n-1) if n is a power of 2
所以,也许对于上面的例子,编译器会为你做这个优化,但如果你有foo%n
,上面的技巧值得使用。
如果有人感兴趣,我已经评估了相应的 PTX 代码。
(1) 复杂的线程ID计算对性能有影响。“threadIdx.x”等不是常量。
(2) “threadIdx.y % 2”实现高效,对应“threadIdx.y & 0x00000001”(Cuda Toolkit 5.5)。