Hello!
There is a quick description of my problem and code:
A: Kernel 1 Input : din Out: dout1, dout2 @ stream1
B: Kernel 2 Input : dout1 Out: res1 @ stream1
C: Copy Input : dout2 Out: res2 @ stream 2
D: Kernel 3 Input : res1, res2 Out: res3 @ stream1
The order of the execution would be: A → (B/C) → D (B and C in async mode)
Code
// test.cu
#include <cstdio>
#define cudaErrChk(ans) { cudaAssert((ans), __FILE__, __LINE__); }
inline void cudaAssert(cudaError_t code, const char *file, int line, bool abort=true)
{
if (code != cudaSuccess)
{
fprintf(stderr, "CUDA Error: %s %s %d\n", cudaGetErrorString(code), file, line);
if (abort) exit(code);
}
}
__global__
void incKernel(int* dout1, int* dout2, const int *din, int N)
{
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < N)
{
dout1[idx] = din[idx] + 1;
dout2[idx] = din[idx] + 2;
}
}
__global__
void incKernel2(int* dout1, const int *din, int N)
{
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < N)
{
dout1[idx] = din[idx] + 1;
}
}
__global__
void incKernel3(int* dout1, const int* din1, const int* din2, int N)
{
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < N)
{
dout1[idx] = 2*din1[idx] + 3*din2[idx];
}
}
int main()
{
int* hostin;
int* din;
int* dout1;
int* dout2;
int* res1;
int* res2;
int* res3;
int datanum = 2000000;
hostin = new int[datanum];
for(int i=0; i<datanum; ++i) hostin[i] = i;
cudaErrChk(cudaMalloc((void**)&din, datanum*sizeof(int)));
cudaErrChk(cudaMalloc((void**)&dout1, datanum*sizeof(int)));
cudaErrChk(cudaMalloc((void**)&dout2, datanum*sizeof(int)));
cudaErrChk(cudaMalloc((void**)&res1, datanum*sizeof(int)));
cudaErrChk(cudaMalloc((void**)&res2, datanum*sizeof(int)));
cudaErrChk(cudaMalloc((void**)&res3, datanum*sizeof(int)));
cudaErrChk(cudaMemcpy(din, hostin, datanum*sizeof(int), cudaMemcpyHostToDevice));
int thnum = 512;
int bnum = (datanum + thnum - 1)/thnum;
cudaStream_t stream1;
cudaStream_t stream2;
cudaEvent_t event1;
cudaEventCreate(&event1);
cudaErrChk(cudaStreamCreate(&stream1));
cudaErrChk(cudaStreamCreate(&stream2));
incKernel<<<bnum, thnum, 0, stream1>>>(dout1, dout2, din, datanum);
cudaErrChk(cudaMemcpyAsync(res2, dout2, datanum*sizeof(int), cudaMemcpyDeviceToDevice, stream2));
incKernel2<<<bnum, thnum, 0, stream1>>>(res1, dout1, datanum);
cudaEventRecord(event1, stream2);
cudaEventSynchronize(event1);
incKernel3<<<bnum, thnum, 0, stream1>>>(res3, res1, res2, datanum);
int* hostres;
hostres = new int[datanum];
cudaErrChk(cudaMemcpy(hostres, res3, datanum*sizeof(int), cudaMemcpyDeviceToHost));
for(int i=0; i<datanum; ++i)
{
int ana = 2*(i+2)+3*(i+2);
if(hostres[i] != ana)
printf("Err Num: %d Data: %d Ana: %d\n", i, hostres[i], ana);
}
delete[] hostin;
delete[] hostres;
cudaFree(din);
cudaFree(dout1);
cudaFree(dout2);
cudaFree(res1);
cudaFree(res2);
cudaFree(res3);
}
Built by
nvcc -o test -O0 test.cu
Run by
On Ubuntu 20.04 + cuda 12.2 + gcc 9.4 + RTX 4070 Ti
compute-sanitizer ./test
Results
The last part reports incorrect results and claims the failure of my attempt with asynchronous operations between the incKernel2 and the cudaMemcpyAsync functions.
Would you mind helping clarify whether cudaEventRecord(event1, stream2) checks if stream2 is idle or something else? If it is idle, will cudaEventSynchronize allow the host to proceed, or will it result in busy waiting for stream2?
Thank you!