我在常量内存中有一个数组(它是一个全局变量),并通过函数调用 cudaGetSymbolAddress 获得了对它的引用。当我使用这个引用来获取常量数据而不是使用全局变量时,我的内核运行缓慢。这是什么原因?
__constant__ int g[2] = {1,2};
// __device__ int g[2] = {1,2};
// kernel: use by reference
__global__ void add_1( int *a, int *b, int *c, int *f )
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
c[tid] = f[0] * a[tid] + f[1] * b[tid];
}
// kernel: use global variable
__global__ void add_2( int *a, int *b, int *c, int *f )
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
c[tid] = g[0] * a[tid] + f[1] * b[tid];
}
int main()
{
......
// a,b,c are large arrays in device memory of size 40960.
int *f;
cudaGetSymbolAddress( (void **)&f, (char *)&g);
add_1 <<< 160, 256 >>> ( a, b, c, f );
......
}
这是示例代码,warp 中的所有线程同时加载相同的位置。注释代码是通过直接访问常量内存
解释为什么不使用常量内存缓存 (通过 talonmis)
原因是缺少常量缓存。
只有当编译器在显式标记为处于常量状态空间的变量上发出特定的 PTX 指令 (ld.const) 时,才会发生缓存访问。编译器知道这样做的方式是声明变量时
__constant__
-- 它是影响代码生成的静态编译时属性。同样的过程不能在运行时发生。如果您在全局内存中传递一个指针并且编译器无法确定常量状态空间中的指针,则它不会生成正确的 PTX 以通过常量缓存访问该内存。因此,访问速度会变慢。
未解答的问题
为什么即使数组
g
声明为 __device__
变量,当引用它时代码会变慢。通过查看 PTX
代码,用于将全局内存加载到寄存器:ld.global.s32
的2条说明使用,它将 4 个字节加载到寄存器。 (在代码中使用引用)ld.global.v2.s32
的1条指令使用,它将 8 个字节加载到 2 个寄存器,(在使用全局变量的代码中)有什么区别,任何文档引用将不胜感激?
最佳答案
与全局内存不同,对常量内存的访问如果不是统一的(一个(计算能力 1.x 的一半)warp 的所有线程访问相同的地址,则它们将被序列化(拆分为多个事务)。
因此,如果访问可能是统一的,则仅使用常量内存。
关于cuda常量内存引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12933469/