查询默认流时如何理解cudaStreamQuery行为?

时间:2018-12-22 03:18:35

标签: cuda

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在第二种情况下不返回错误?

1 个答案:

答案 0 :(得分:1)

您的语句a)对于示例代码中的特定情况不太准确:

  

a)cudaMemcpy()与主机代码同步,因此在返回cudaMemcpy之后,应完成此流中的复制工作,

cudaMemcpy的{​​{3}}状态:

  

在大多数使用情况下,此功能表现出documentation行为。

如果单击synchronous链接,将转到一个进一步定义确切行为的页面。您可能需要阅读整个页面,时间不长。我将从 Synchronous 的定义中摘录两点:

  
      
  1. 对于从可分页的主机内存到设备内存的传输,在启动复制之前执行流同步。一旦将可分页缓冲区复制到临时存储器中以将DMA传输到设备存储器中,该功能将返回,但到最终目标的DMA可能尚未完成。   (添加了重点)
  2.   

和:

  
      
  1. 对于从设备到可分页或固定的主机内存的传输,该功能仅在复制完成后返回。
  2.   

您的代码符合第一个摘录(上面的项目2)。可以在复制完全完成之前返回该传输类型(主机到设备)

如果您在cudaMemcpy示例中反转了指针的顺序,从而反转了副本的方向,则您将进入第二节摘录(上面的项目4)。在这种情况下,可以保证传输已完成,并且错误报告确实会从您的代码中消失。

该行为是可能的,并在文档中进行了说明。