首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >cudaStreamAddCallback不会阻止以后的cudaMemcpyAsync

cudaStreamAddCallback不会阻止以后的cudaMemcpyAsync
EN

Stack Overflow用户
提问于 2018-06-18 01:50:44
回答 1查看 328关注 0票数 0

我试图让cudaMemcpyHost2Device通过使用cudaStreamAddCallback等待一些特定的事件。我发现了关于cudaStreamCallback API的评论

回调将阻止以后在流中工作,直到它完成为止。

因此,以后的工作,如cudaMemcpyAsync被阻止,是预期的。但是后来的代码断言失败了。

代码语言:javascript
复制
#include <cuda_runtime.h>

#include <stdlib.h>
#include <string.h>
#include <cassert>
#include <unistd.h>
#include <stdio.h>

#define cuda_check(x) \
    assert((x) == cudaSuccess)

const size_t size = 1024 * 1024;


static void CUDART_CB cuda_callback(
        cudaStream_t, cudaError_t, void* host) {
    float* host_A = static_cast<float*>(host);
    for (size_t i = 0; i < size; ++i) {
        host_A[i] = i;
    }

    printf("hello\n");
    sleep(1);
}

int main(void) {

    float* A;
    cuda_check(cudaMalloc(&A, size * 4));
    float* host_A = static_cast<float*>(malloc(size * 4));
    float* result = static_cast<float*>(malloc(size * 4));

    memset(host_A, 0, size * 4);

    cuda_check(cudaMemcpy(A, host_A, size * 4, cudaMemcpyHostToDevice));

    cudaStream_t stream;
    cuda_check(cudaStreamCreate(&stream));

    cuda_check(cudaStreamAddCallback(stream, cuda_callback, host_A, 0));
    cuda_check(cudaMemcpyAsync(A, host_A, size * 4, cudaMemcpyHostToDevice,
                               stream));

    cuda_check(cudaStreamSynchronize(stream));
    cuda_check(cudaMemcpy(result, A, size * 4, cudaMemcpyDeviceToHost));

    for (size_t i = 0; i < size; ++i) {
        assert(result[i] == i);
    }

    return 0;
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-06-18 13:53:27

你对正在发生的事情的假设是不正确的。如果我使用分析器为您的代码收集运行时API跟踪( cudaDeviceReset是由我添加的以确保分析数据被刷新),我会看到以下内容:

代码语言:javascript
复制
124.79ms  129.57ms  cudaMalloc
255.23ms  694.20us  cudaMemcpy
255.93ms  38.881us  cudaStreamCreate
255.97ms  123.44us  cudaStreamAddCallback
256.09ms  1.00348s  cudaMemcpyAsync
1.25957s  76.899us  cudaStreamSynchronize
1.25965s  1.3067ms  cudaMemcpy
1.26187s  71.884ms  cudaDeviceReset

如您所见,cudaMemcpyAsync确实被回调所阻塞(它花了>1.0秒才完成)。

复制未能按您认为的顺序发生的事实很可能是因为您使用的是常规的可分页主机分配,而不是固定内存,并且期望回调立即触发空队列。需要注意的是,注册流回调并启动副本的发生时间要小于彼此之间的0.1毫秒,而且回调可能不会立即触发(假设它位于另一个线程中),从而可能在回调函数对空队列条件作出反应之前启动副本。

有趣的是,如果我将host_A更改为固定分配并运行代码,就会得到这个API时间线:

代码语言:javascript
复制
124.21ms  130.24ms  cudaMalloc
254.45ms  1.0988ms  cudaHostAlloc
255.98ms  376.14us  cudaMemcpy
256.36ms  33.841us  cudaStreamCreate
256.39ms  87.303us  cudaStreamAddCallback
256.48ms  17.208us  cudaMemcpyAsync
256.50ms  1.00331s  cudaStreamSynchronize
1.25981s  1.2880ms  cudaMemcpy
1.26205s  68.506ms  cudaDeviceReset

注意,cudaStreamSynchronize是被阻塞的调用。但是在这种情况下,程序传递断言,这可能与调度程序在固定主机内存的情况下正确地管理流中的依赖项有关。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50901819

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档