我想在 CUDA 流上做一些工作,比如内核
K
,这取决于之前需要在 CPU 上完成的工作。我在调度时并不知道CPU工作的具体细节K
;我只是希望 K
在指示一切准备就绪之前不要开始。
现在,如果我确切地知道要完成哪些 CPU 工作,例如
K
可以在某些功能 foo()
得出结论后启动,我可以执行以下操作:
foo()
的调用进行排队E1
E1
K
入队
foo()
?我想允许代码中的其他任意位置在 E1 良好且准备就绪时触发 E1,并在 MainStream 上触发 K。 ...但我不能这样做,因为在 CUDA 中,您只能等待已经排队(已经“记录”)的事件。这似乎是 OpenCL 提供比 CUDA 更丰富的 API 的少数几个领域之一:“用户事件”。它们可以被等待,并且它们的执行完成状态可以由用户设置。参见:
cuda::latch
可能更高效,因为它似乎在旋转时使用 nanosleep 函数
#include <cstdio>
#include <chrono>
#include <thread>
#include <cuda/latch>
__global__
void kernel(){
printf("kernel\n");
}
__global__
void waitKernel(volatile int* flag){
while(*flag != 1);
}
__global__
void waitKernelLatch(cuda::latch<cuda::thread_scope_system>* latchPtr){
latchPtr->wait();
}
int main(){
int* waitFlag;
cudaMallocHost(&waitFlag, sizeof(int));
cuda::latch<cuda::thread_scope_system>* latchPtr;
cudaMallocHost(&latchPtr, sizeof(cuda::latch<cuda::thread_scope_system>));
printf("wait using flag\n");
*waitFlag = 0;
waitKernel<<<1,1>>>(waitFlag);
kernel<<<1,1>>>();
printf("do some cpu stuff\n");
std::this_thread::sleep_for(std::chrono::seconds(3));
*waitFlag = 1;
cudaDeviceSynchronize();
printf("wait using latch\n");
new (latchPtr) cuda::latch<cuda::thread_scope_system>(1);
waitKernelLatch<<<1,1>>>(latchPtr);
kernel<<<1,1>>>();
printf("do some cpu stuff\n");
std::this_thread::sleep_for(std::chrono::seconds(3));
latchPtr->count_down();
cudaDeviceSynchronize();
cudaFreeHost(waitFlag);
}
v
用于向 MainStream 发送信号。
cuMemHostRegister()
上调用 v
,以获取其设备地址(可能与其主机地址相同)。
v
上排队等待(使用
cuStreamWaitValue32()
)
K
v
传递给任何安排额外 CPU 工作的代码。
1
写入
v
。
这是一个可能的想法 - 基于@AbatorAbetor 的评论,尽管我不知道这是否是人们在实践中使用的。
foo()
,它将条件变量作为参数并等待该变量。例如,您可以使用
std::condition_variable
。
foo()
的调用进行排队
E1
E1
在主流上K
foo()
,然后立即触发
E
,然后K
。警告:我假设让 CUDA 回调函数块像这样不会干扰其他 CUDA 运行时/驱动程序工作。