假设我有两个数组A
和B
以及一个kernel1
,它们通过将数组分成不同的块来对两个数组(例如向量加法)进行一些计算,然后写入部分结果为C
。 kernel1
然后继续这样做,直到处理完数组中的所有元素。
unsigned int i = blockIdx.x*blockDim.x + threadIdx.x;
unsigned int gridSize = blockDim.x*gridDim.x;
//iterate through each chunk of gridSize in both A and B
while (i < N) {
C[i] = A[i] + B[i];
i += gridSize;
}
说,现在我想在kernel2
和另一个数据数组C
上发布D
。无论如何我可以在计算kernel2
中的第一个块之后立即开始C
吗?从本质上讲,kernel1
管道会导致kernel2
。依赖树看起来像这样
Result
/ \
C D
/ \
A B
我考虑过使用CUDA流但不确定如何使用。也许将主机纳入计算中?
答案 0 :(得分:1)
是的,您可以使用CUDA streams来管理此类情景中的顺序和依赖关系。
假设您希望重叠复制和计算操作。这通常意味着您将输入数据分解为&#34;块&#34;然后将块复制到设备,然后启动计算操作。每个内核启动都在&#34; chunk&#34;数据。
我们可以通过主机代码中的循环来管理流程:
// create streams and ping-pong pointer
cudaStream_t stream1, stream2, *st_ptr;
cudaStreamCreate(&stream1); cudaStreamCreate(&stream2);
// assume D is already on device as dev_D
for (int chunkid = 0; chunkid < max; chunkid++){
//ping-pong streams
st_ptr = (chunkid % 2)?(&stream1):(&stream2);
size_t offset = chunkid*chunk_size;
//copy A and B chunks
cudaMemcpyAsync(dev_A+offset, A+offset, chksize*sizeof(A_type), cudaMemcpyHostToDevice, *st_ptr);
cudaMemcpyAsync(dev_B+offset, B+offset, chksize*sizeof(B_type), cudaMemcpyHostToDevice, *st_ptr);
// then compute C based on A and B
compute_C_kernel<<<...,*st_ptr>>>(dev_C+offset, dev_A+offset, dev_B+offset, chksize);
// then compute Result based on C and D
compute_Result_kernel<<<...,*st_ptr>>>(dev_C+offset, dev_D, chksize);
// could copy a chunk of Result back to host here with cudaMemcpyAsync on same stream
}
发送到同一流的所有操作都保证在设备上按顺序(即顺序)执行。发给单独流的操作可以重叠。因此,上述顺序应该:
将对每个块重复上述步骤,但是将向备用流发出连续的块操作。因此,块2的复制操作可以与来自块1等的内核操作重叠。
您可以通过查看有关CUDA流的演示文稿了解更多信息。 Here就是一个例子。
较新的设备(Kepler和Maxwell)应该非常灵活地了解在设备上看到操作重叠所需的程序问题顺序。较旧(费米)设备可能对发布订单敏感。您可以阅读有关here
的更多信息