我正在尝试编写一个小型演示程序,其中包含两个cuda流,并且由事件控制,彼此等待。到目前为止,这个程序看起来像这样:
// event.cu
#include <iostream>
#include <cstdio>
#include <cuda_runtime.h>
#include <cuda.h>
using namespace std;
__global__ void k_A1() { printf("\tHi! I am Kernel A1.\n"); }
__global__ void k_B1() { printf("\tHi! I am Kernel B1.\n"); }
__global__ void k_A2() { printf("\tHi! I am Kernel A2.\n"); }
__global__ void k_B2() { printf("\tHi! I am Kernel B2.\n"); }
int main()
{
cudaStream_t streamA, streamB;
cudaEvent_t halfA, halfB;
cudaStreamCreate(&streamA);
cudaStreamCreate(&streamB);
cudaEventCreate(&halfA);
cudaEventCreate(&halfB);
cout << "Here is the plan:" << endl <<
"Stream A: A1, launch 'HalfA', wait for 'HalfB', A2." << endl <<
"Stream B: Wait for 'HalfA', B1, launch 'HalfB', B2." << endl <<
"I would expect: A1,B1, (A2 and B2 running concurrently)." << endl;
k_A1<<<1,1,0,streamA>>>(); // A1!
cudaEventRecord(halfA,streamA); // StreamA triggers halfA!
cudaStreamWaitEvent(streamA,halfB,0); // StreamA waits for halfB.
k_A2<<<1,1,0,streamA>>>(); // A2!
cudaStreamWaitEvent(streamB,halfA,0); // StreamB waits, for halfA.
k_B1<<<1,1,0,streamB>>>(); // B1!
cudaEventRecord(halfB,streamB); // StreamB triggers halfB!
k_B2<<<1,1,0,streamB>>>(); // B2!
cudaEventDestroy(halfB);
cudaEventDestroy(halfA);
cudaStreamDestroy(streamB);
cudaStreamDestroy(streamA);
cout << "All has been started. Synchronize!" << endl;
cudaDeviceSynchronize();
return 0;
}
我对CUDA流的掌握如下:流是一种我可以添加任务的列表。这些任务是串联处理的。所以在我的程序中,我可以放心,streamA将按顺序
和streamB将
通常两个流可能彼此异步运行。但是,我想阻止streamB直到A1完成,然后阻止streamA直到B1完成。
这似乎并不那么简单。在我的Ubuntu上用特斯拉M2090(CC 2.0)输出
nvcc -arch=sm_20 event.cu && ./a.out
是
Here is the plan:
Stream A: A1, launch 'HalfA', wait for 'HalfB', A2.
Stream B: Wait for 'HalfA', B1, launch 'HalfB', B2.
I would expect: A1,B1, (A2 and B2 running concurrently).
All has been started. Synchronize!
Hi! I am Kernel A1.
Hi! I am Kernel A2.
Hi! I am Kernel B1.
Hi! I am Kernel B2.
我真的希望在cudaEventRecord(halfB,streamB)之前完成B1。然而,流A显然不等待B1的完成,因此不能记录halfB。
更重要的是:如果我完全删除了cudaEventRecord命令,我希望程序能够锁定cudaStreamWait命令。但它不会产生相同的输出。我在这里俯瞰什么?
答案 0 :(得分:5)
我认为这是因为“cudaStreamWaitEvent(streamA,halfB,0);”在记录“halfB”之前被调用(cudaEventRecord(halfB,streamB);)。 cudaStreamWaitEvent调用可能正在搜索关闭的“halfB”之前;因为没有找到它,它只是悄悄地向前移动。请参阅以下文档:
流
stream
将仅等待cudaEventRecord()
上event
的最近一次主持人呼叫的完成。返回此调用后,可能会再次cudaEventRecord()
调用任何函数(包括cudaEventDestroy()
和event
),后续调用不会对stream
产生任何影响。< / p>
如果你必须进行深度优先编码,我找不到解决方案;但是,以下代码可能会导致您想要的内容:
k_A1<<<1,1,0,streamA>>>(d); // A1!
cudaEventRecord(halfA,streamA); // StreamA triggers halfA!
cudaStreamWaitEvent(streamB,halfA,0); // StreamB waits, for halfA.
k_B1<<<1,1,0,streamB>>>(d); // B1!
cudaEventRecord(halfB,streamB); // StreamB triggers halfB!
cudaStreamWaitEvent(streamA,halfB,0); // StreamA waits for halfB.
k_A2<<<1,1,0,streamA>>>(d); // A2!
k_B2<<<1,1,0,streamB>>>(d); // B2!
由分析确认:
请注意,我更改了内核接口。