最近我在CUDA中编写一些信号处理代码,通过使用1D纹理和调整我的访问模式,我成功地将性能提升了10倍。(之前我尝试过从全局内存到共享内存的事务对齐预取,但后来发生的非均匀访问模式弄乱了warp→shared cache bank关联(我想)).
现在我面临的问题是,CUDA纹理和绑定如何与异步memcpy交互。
考虑以下核函数
texture<...> mytexture;
__global__ void mykernel(float *pOut)
{
pOut[threadIdx.x] = tex1Dfetch(texture, threadIdx.x);
}
内核在多个流中启动。
extern void *sourcedata;
#define N_CUDA_STREAMS ...
cudaStream stream[N_CUDA_STREAMS];
void *d_pOut[N_CUDA_STREAMS];
void *d_texData[N_CUDA_STREAMS];
for(int k_stream = 0; k_stream < N_CUDA_STREAMS; k_stream++) {
cudaStreamCreate(stream[k_stream]);
cudaMalloc(&d_pOut[k_stream], ...);
cudaMalloc(&d_texData[k_stream], ...);
}
/* ... */
for(int i_datablock; i_datablock < n_datablocks; i_datablock++) {
int const k_stream = i_datablock % N_CUDA_STREAMS;
cudaMemcpyAsync(d_texData[k_stream], (char*)sourcedata + i_datablock * blocksize, ..., stream[k_stream]);
cudaBindTexture(0, &mytexture, d_texData[k_stream], ...);
mykernel<<<..., stream[k_stream]>>>(d_pOut);
}
现在我想知道的是,由于只有一个纹理引用,当我将缓冲区绑定到纹理时,其他流的内核访问该纹理会发生什么?cudaBindStream不需要流参数,因此我担心通过将纹理绑定到另一个设备指针,同时运行内核异步访问所述纹理,会将它们的访问重定向到其他数据。
CUDA文档没有提供关于这个问题的信息。如果必须解开这个问题以允许并发访问,似乎我需要创建一些纹理引用,并使用一个切换语句来根据作为内核启动参数传递的流编号进行选择。
不幸的是,CUDA不允许在设备端放置纹理数组,即以下内容无法工作:
texture<...> texarray[N_CUDA_STREAMS];
分层纹理不是一个选择,因为我拥有的数据量只适用于一个普通的1D纹理,而不绑定到CUDA数组中(请参见CUDA 4.2 C编程指南中的表F-2)。