使用主机线程同步设备内存访问

时间:2012-12-05 00:19:59

标签: cuda gpu synchronize

CUDA内核是否有可能在没有任何主机端调用(例如,cudaDeviceSynchronize)的情况下将写入同步到设备映射的内存?当我运行以下程序时,似乎内核在终止之前等待对设备映射内存的写入完成,因为在内核启动后立即检查页面锁定的主机内存没有显示任何修改内存(除非插入延迟或取消注释对cudaDeviceSynchronize的调用):

#include <stdio.h>
#include <cuda.h>

__global__ void func(int *a, int N) {
    int idx = threadIdx.x;

    if (idx < N) {
        a[idx] *= -1;
        __threadfence_system();
    }
}

int main(void) {
    int *a, *a_gpu;
    const int N = 8;
    size_t size = N*sizeof(int);

    cudaSetDeviceFlags(cudaDeviceMapHost);
    cudaHostAlloc((void **) &a, size, cudaHostAllocMapped);
    cudaHostGetDevicePointer((void **) &a_gpu, (void *) a, 0);

    for (int i = 0; i < N; i++) {
        a[i] = i;
    }
    for (int i = 0; i < N; i++) {
        printf("%i ", a[i]);
    }
    printf("\n");

    func<<<1, N>>>(a_gpu, N);
    // cudaDeviceSynchronize();

    for (int i = 0; i < N; i++) {
        printf("%i ", a[i]);
    }
    printf("\n");

    cudaFreeHost(a);
}

我在Linux上使用CUDA 4.2.9为sm_20编译以上内容并在Fermi GPU上运行(S2050)。

1 个答案:

答案 0 :(得分:4)

在发生任何内核活动之前,内核启动将立即返回到主机代码。内核执行以这种方式与主机执行异步,不阻止主机执行。因此,您必须等待一段时间或者使用屏障(如cudaDeviceSynchronize())来查看内核的结果并不奇怪。

如上所述here

  

为了便于主机和设备之间的并发执行,   某些函数调用是异步的:控制权返回给主机   设备完成请求的任务之前的线程。这些是:

     
      
  • 内核启动;
  •   
  • 将两个地址之间的内存复制到同一设备内存;
  •   
  • 内存副本从64 KB或更小的内存块的主机到设备;
  •   
  • 由Async;
  • 后缀的函数执行的内存复制   
  • 内存设置功能调用。
  •   

这当然是故意的,因此您可以同时使用GPU和CPU。如果您不想要这种行为,那么您已经发现的简单解决方案是插入屏障。如果您的内核正在生成您将立即复制回主机的数据,则不需要单独的屏障。内核之后的cudaMemcpy调用将等到内核完成后再开始复制操作。

我想回答你的问题,你希望内核启动是同步的,你甚至不用屏障(你为什么要这样做?添加cudaDeviceSynchronize()调用有问题吗?)这是可能的这样:

  

“程序员可以全局禁用所有人的异步内核启动   通过设置在系统上运行的CUDA应用程序   CUDA_LAUNCH_BLOCKING环境变量为1.此功能是   仅用于调试目的,绝不能用作某种方式   使生产软件可靠运行。 “

如果你想要这种synchronous行为,最好只使用障碍(或依赖于另一个后续的cuda调用,如cudaMemcpy)。如果你使用上面的方法并依赖它,你的代码会在别人尝试运行它而没有设置环境变量时立即中断。所以这真的不是一个好主意。