【发布时间】:2012-10-17 11:39:57
【问题描述】:
我在常量内存中有一个数组(它是一个全局变量),并通过函数调用 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 中的所有线程同时加载相同的位置。注释代码是通过直接访问常量内存
解释为什么不使用常量内存缓存(by talonmies)
原因是缺少常量缓存。
仅当编译器在显式标记为处于常量状态空间中的变量上发出特定的 PTX 指令 (ld.const) 时,才会发生缓存访问。编译器知道这样做的方式是在声明变量__constant__ 时——它是一个影响代码生成的静态编译时属性。运行时不能发生相同的过程。
如果您在全局内存中传递一个指针,而编译器无法确定该指针在常量状态空间中,则它不会生成正确的 PTX 以通过常量缓存访问该内存。因此访问速度会变慢。
未回答的问题
为什么即使数组g 被声明为__device__ 变量,引用它时代码也会变慢。通过查看PTX 代码,将全局内存加载到寄存器:
- 使用了
ld.global.s32的2条指令,将4个字节加载到寄存器中。 (在代码中使用参考) - 使用
ld.global.v2.s32的1条指令,将8个字节加载到2个寄存器中,(在使用全局变量的代码中)
有什么区别,任何文档参考都将不胜感激?
【问题讨论】:
-
我猜你没有利用常量特性。您如何访问全局和常量内存中的数据?您的代码的 sn-p 将帮助我们为您提供更好的答案。
-
pQB 是对的。我刚刚看到了 talonmies 的回答,根据给出的信息,无法确定哪一个适用于您的问题。另外,你的 GPU 是什么计算能力?
-
@tera 计算能力为 1.3
-
我在代码中根本看不到
__constant__声明。你怎么称呼内核? -
@tera 我更改了相关代码。