Cuda 将设备内存访问与主机线程同步

Cuda 将设备内存访问与主机线程同步,cuda,gpu,synchronize,Cuda,Gpu,Synchronize,CUDA内核是否可以在没有任何主机端调用的情况下(例如,cudaDeviceSynchronize)同步写入设备映射内存?当我运行以下程序时,内核似乎不会在终止之前等待对设备映射内存的写入完成,因为在内核启动后立即检查页面锁定的主机内存不会显示内存的任何修改(除非插入延迟或取消对cudaDeviceSynchronize的调用注释): #包括 #包括 __全局无效函数(int*a,int N){ int idx=threadIdx.x; if(idx

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

#包括
#包括
__全局无效函数(int*a,int N){
int idx=threadIdx.x;
if(idx

我在Linux上使用CUDA 4.2.9为sm_20编译上述内容,并在费米GPU(S2050)上运行它.

在任何内核活动发生之前,内核启动将立即返回到主机代码。内核执行以这种方式与主机执行异步,并且不会阻止主机执行。因此,您需要等待一点或使用屏障(如cudaDeviceSynchronize())来查看内核的结果也就不足为奇了

如上所述:

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

  • 内核启动
  • 两个地址之间的存储器拷贝到同一设备存储器
  • 内存从主机复制到64 KB或以下内存块的设备
  • 由后缀为Async的函数执行的内存拷贝
  • 内存设置函数调用
当然,这都是有意为之的,这样你就可以同时使用GPU和CPU。如果你不想要这种行为,你已经发现了一个简单的解决方案,就是插入一个屏障。如果你的内核正在生成数据,你将立即复制回主机,你不需要单独的屏障。在内核之后调用cudaMemcpyel将等到内核完成后才开始复制操作

我猜要回答您的问题,您希望内核启动是同步的,甚至不需要使用屏障(为什么要这样做?添加CudDeviceSynchronize()调用是否有问题?)

“程序员可以全局禁用所有应用程序的异步内核启动 通过设置 CUDA_LAUNCH_阻塞环境变量为1。此功能为 仅为调试目的提供,不应作为一种方式使用 使生产软件可靠运行。”


如果您想要这种
同步
行为,最好只使用屏障(或者依赖另一个后续的cuda调用,如cudaMemcpy)。如果您使用上述方法并依赖它,那么当其他人试图在未设置环境变量的情况下运行代码时,您的代码将立即中断。因此,这真的不是一个好主意。

我试图了解uu threadfence_system()有效地充当各种类型的设备侧屏障;请参阅Greg Smith的最后评论。另请参阅CUDA 4.2编程指南中的B.5节。_threadfence是各种类型的设备屏障。但它只是设备活动的屏障(即threadfence调用后的设备代码).Host活动仍然是异步的。启动内核后,会立即释放主机线程以继续。要停止主机端活动,您需要一个主机端屏障。但是如果仍然必须使用主机端屏障,uuu threadfence_system()对“页锁定主机内存访问的主机线程”有什么影响阻止调用线程(即设备线程),直到写入主机页锁定内存的数据(对主机线程)可见。这意味着在_threadfence_system()之后call释放设备线程以继续,您可以预期任何访问页面锁定内存的主机线程都会看到在屏障之前写入的任何结果。但它不会在任何时候阻止任何主机线程。因此,如果您的主机线程恰好在该点之前读取,它可能会得到其他结果。因为所有这些都不会阻止主机线程,它们仍然是异步的。
#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);
}