繁体   English   中英

cudaMemcpyAsync 与可分页 memory 阻止主机线程?

[英]cudaMemcpyAsync with pageable memory blocks host thread?

我用可分页内存写了一个关于 cudaMemcpyAsync 的简单代码,并做了一些分析。

Kernel

__global__ void
vectorScale(float *C, float scal, size_t numElements)
{
    int i = blockDim.x * blockIdx.x + threadIdx.x;
    clock_t start_clock = clock();
    clock_t clock_offset = 0;
    while (clock_offset < 14100){
        clock_offset = clock() - start_clock;
    }

    if (i < numElements) C[i] *= scal;
}

主要的

int main(int argc, char* argv[])
{
    cudaStream_t stream;
    // Print the vector length to be used, and compute its size
    size_t numElements = 1024*1024*256;
    size_t size = numElements * sizeof(float);
    printf("[Vector scale of %zu elements]\n", numElements);

    float *h_C; 
    if(argc==1) h_C = (float *)malloc(size);
    else cudaHostAlloc((void**)&h_C, size, cudaHostAllocPortable);

    // Initialize the host input vectors
    for (size_t i = 0; i < numElements; ++i)
        h_C[i] = i*0.01;

    // Allocate the device vector C
    float *d_C = NULL;
    cudaMalloc((void **)&d_C, size);
    cudaStreamCreate(&stream);

    cudaMemcpyAsync(d_C, h_C, size, cudaMemcpyHostToDevice, stream);

    int threadsPerBlock = 256;
    int blocksPerGrid =(numElements + threadsPerBlock - 1) / threadsPerBlock;
    vectorScale<<<blocksPerGrid, threadsPerBlock, 0, stream>>>(d_C, 2.0, numElements);

    cudaMemcpyAsync(h_C, d_C, size, cudaMemcpyDeviceToHost, stream);
    cudaStreamSynchronize(stream);

    // Free device global memory
    cudaFree(d_C);

    // Free host memory
    if(argc==1) free(h_C);
    else cudaFreeHost(h_C);
    cudaStreamDestroy(stream);

    return 0;
}

剖析在此处输入图像描述

如快照所示,在“CUDA API”行中,cudaMemcpyAsync 的时间成本很大,这意味着主机 thead 被阻塞。 它看起来与文档指南不一致。

顺便说一句,如果我使用固定的 memory,cudaMemcpyAsync 的行为与预期一样,主机线程会在 cudaStreamSynchronize() 处阻塞。

似乎很明显(您的测试用例是一个证明点)在某些情况下cudaMemcpyAsync可能成为主机线程的阻塞操作,不再是相对于其他主机 CPU 线程活动的“异步”。

我没有发现任何证据表明这与文档相矛盾,该文档没有任何声明,例如“在任何情况下cudaMemcpyAsync都不会阻塞主机线程”。 如果您知道任何此类声明,请指出。 实际上, 文档表明您正在观察的内容是预期的:

如果异步 memory 副本涉及未页面锁定的主机 memory,则它们也将是同步的。

cudaMemcpyAsync的异步特性取决于将数据传输到固定分配或从固定分配传输(对于 D->H 或 H->D 的传输方向)。 固定分配是必需的,以便编程到 DMA 引擎中的将“异步”进行传输的底层操作具有主机数据的固定映射。 这是必需的。

可分页分配意味着底层逻辑->物理映射可以随时更改,这会阻止cudaMemcpyAsync的正常操作。 由于cudaMemcpyAsync的预期用例是将数据复制到固定分配/从固定分配复制数据,我推测 CUDA 运行时 API 开发人员认为在这种情况下可接受的行为是阻塞主机线程并“立即”完成传输(即同步。我不希望任何违反 CUDA stream 语义的传输,无论是同步还是异步)。 同样,您的测试用例是一个证明点。

继续提供“异步”行为的唯一其他选择 w.r.t。 我可以想象的主机线程将启动另一个 CPU 线程来异步处理操作。 同样,我推测 CUDA 运行时 API 开发人员认为,对于此 API 的非首选用例,开发和维护此类机器是没有必要的。

然而,这里的猜想离题了。 我不想争论它。 主要思想是您所观察的是预期的行为。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM