当我尝试重叠数据传输和内核执行时,无论我使用什么流,卡似乎都在按顺序执行所有内存传输。
所以,如果我发出以下内容:
- 流 1:MemcpyA_HtoD_1;内核_1;MemcpyA_DtoH_1
- 流 2:MemcpyA_HtoD_2;内核_2;MemcpyA_DtoH_2
MemcpyA_HtoD_2 将等到 MemcpyA_DtoH_1 完成。所以没有实现重叠。无论我使用什么配置的流,Memcpy 操作总是按顺序发出。因此,实现重叠的唯一方法是缓冲输出或将输出传输延迟到下一次迭代。
我使用 CUDA 5.5、Windows 7 x64 和 GTX Titan。所有 cpu 内存都被固定,并且 data_transfers 使用异步版本完成。
请参阅以下屏幕的行为:
发出,host_to_device -> kernel -> device_to_host(正常行为)并且不能重叠。
发出 host_to_device -> 内核(避免内核后的 device_to_host)得到重叠......因为所有内存副本都是按顺序执行的,无论我尝试什么流配置。
更新
如果有人有兴趣重现此问题,我编写了一个合成程序来显示这种不良行为。它是使用 CUDA 5.5 的完整 VS2010 解决方案
有人可以在 linux 上执行这个来测试重叠吗?
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#define N 1024*1024
__global__ void someKernel(int *d_in, int *d_out) {
for (int i = threadIdx.x; i < threadIdx.x + 1024; i++) {
d_out[i] = d_in[i];
}
}
int main () {
int *h_bufferIn[100];
int *h_bufferOut[100];
int *d_bufferIn[100];
int *d_bufferOut[100];
//allocate some memory
for (int i = 0; i < 100; i++) {
cudaMallocHost(&h_bufferIn[i],N*sizeof(int));
cudaMallocHost(&h_bufferOut[i],N*sizeof(int));
cudaMalloc(&d_bufferIn[i], N*sizeof(int));
cudaMalloc(&d_bufferOut[i], N*sizeof(int));
}
//create cuda streams
cudaStream_t st[2];
cudaStreamCreate(&st[0]);
cudaStreamCreate(&st[1]);
//trying to overlap computation and memcpys
for (int i = 0; i < 100; i+=2) {
cudaMemcpyAsync(d_bufferIn[i], h_bufferIn[i], N*sizeof(int), cudaMemcpyHostToDevice, st[i%2]);
someKernel<<<1,256, 0, st[i%2]>>>(d_bufferIn[i], d_bufferOut[i]);
cudaMemcpyAsync(h_bufferOut[i], d_bufferOut[i], N*sizeof(int), cudaMemcpyDeviceToHost, st[i%2]);
cudaStreamQuery(0);
cudaMemcpyAsync(d_bufferIn[i+1], h_bufferIn[i+1], N*sizeof(int), cudaMemcpyHostToDevice, st[(i+1)%2]);
someKernel<<<1,256, 0, st[(i+1)%2]>>>(d_bufferIn[i+1], d_bufferOut[i+1]);
cudaMemcpyAsync(h_bufferOut[i+1], d_bufferOut[i+1], N*sizeof(int), cudaMemcpyDeviceToHost, st[(i+1)%2]);
cudaStreamQuery(0);
}
cudaDeviceSynchronize();
}