我在常量内存中有一个数组(它是一个全局变量),并通过函数调用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中的所有线程同时加载相同的位置。注释代码是通过直接访问常量内存
解释为什么不使用常量内存缓存( talonmies )
原因是缺乏恒定的缓存。
缓存访问仅在编译器在标记为处于常量状态空间的显式变量上发出特定PTX指令(ld.const)时发生。编译器知道这样做的方式是当一个变量被声明为__constant__
时 - 它是一个静态的编译时属性,它会影响代码生成。同样的过程不能在运行时发生。
如果在全局内存中传递指针并且编译器无法确定指针处于常量状态空间,则它将不会生成正确的PTX以通过常量缓存访问该内存。结果访问速度会变慢。
未答复的问题
为什么即使将数组g
声明为__device__
变量,代码在使用时也会变慢。通过查看PTX
代码,将全局内存加载到寄存器:
ld.global.s32
的2条指令,将4个字节加载到寄存器。 (在使用参考的代码中)ld.global.v2.s32
的1条指令,将2个字节加载到2个寄存器(使用全局变量的代码中)有什么区别,任何文件参考都会受到赞赏?
答案 0 :(得分:2)
与全局内存不同,对常量内存的访问将被序列化(拆分为多个事务),如果它们不一致(a(计算能力1.x的一半)的所有线程都会转换为相同的地址。
因此,如果访问可能是一致的,那么只使用常量内存。