从CUDA manual开始,我知道cudaStreamQuery
在异步流上运行:
查询异步流的完成状态。
我编写了一个简单的程序来测试其在“默认流”上的行为:
#include <cstdlib>
#include <iostream>
#define cudaSafeCall(call) \
do {\
cudaError_t err = call;\
if (cudaSuccess != err) \
{\
std::cerr << "CUDA error in " << __FILE__ << "(" << __LINE__ << "): " \
<< cudaGetErrorString(err) << '\n';\
exit(EXIT_FAILURE);\
}\
} while(0)
int main(void)
{
int N = 1<<20;
float *x, *d_x;
x = (float*)malloc(N*sizeof(float));
cudaSafeCall(cudaMalloc(&d_x, N*sizeof(float)));
cudaSafeCall(cudaMemcpy(d_x, x, N*sizeof(float), cudaMemcpyDefault));
cudaSafeCall(cudaStreamQuery(0));
cudaSafeCall(cudaFree(d_x));
free(x);
return 0;
}
构建并运行它:
$ nvcc sync_test.cu -o sync_test
$ ./sync_test
CUDA error in sync_test.cu(25): device not ready
在cudaStreamSynchronize(0);
和cudaMemcpy
之间添加cudaStreamQuery
后,错误消失了:
cudaSafeCall(cudaMemcpy(d_x, x, N*sizeof(float), cudaMemcpyDefault));
cudaSafeCall(cudaStreamSynchronize(0));
cudaSafeCall(cudaStreamQuery(0));
我有点困惑:
a)cudaMemcpy()
与主机代码同步,因此在返回cudaMemcpy
之后,应完成此流中的复制工作,为什么cudaStreamQuery(0)
在第一种情况下返回错误?
b)如果cudaStreamQuery
仅适用于异步流,而不适用于默认流,为什么cudaStreamQuery
在第二种情况下不返回错误?
答案 0 :(得分:1)
您的语句a)对于示例代码中的特定情况不太准确:
a)
cudaMemcpy()
与主机代码同步,因此在返回cudaMemcpy
之后,应完成此流中的复制工作,
cudaMemcpy
的{{3}}状态:
在大多数使用情况下,此功能表现出documentation行为。
如果单击synchronous链接,将转到一个进一步定义确切行为的页面。您可能需要阅读整个页面,时间不长。我将从 Synchronous 的定义中摘录两点:
- 对于从可分页的主机内存到设备内存的传输,在启动复制之前执行流同步。一旦将可分页缓冲区复制到临时存储器中以将DMA传输到设备存储器中,该功能将返回,但到最终目标的DMA可能尚未完成。 (添加了重点)
和:
- 对于从设备到可分页或固定的主机内存的传输,该功能仅在复制完成后返回。
您的代码符合第一个摘录(上面的项目2)。可以在复制完全完成之前返回该传输类型(主机到设备)。
如果您在cudaMemcpy
示例中反转了指针的顺序,从而反转了副本的方向,则您将进入第二节摘录(上面的项目4)。在这种情况下,可以保证传输已完成,并且错误报告确实会从您的代码中消失。
该行为是可能的,并在文档中进行了说明。