Cuda Windows上的重叠计算和传输

Cuda Windows上的重叠计算和传输,cuda,Cuda,我在Windows上尝试重叠计算和传输时遇到了一些问题(使用VS2015和CUDA 10.1)。代码完全没有重叠。但是Linux上的代码与预期行为完全相同 以下是NVVP的视图: Windows 10 NVVP屏幕截图: Linux NVVP屏幕截图: 请注意以下几点: 我的主机内存被分页锁定 我使用两种不同的流 我正在使用cudaMemcpyAsync方法在主机和设备之间进行传输 如果我在Linux上运行我的代码,一切都很好 我在文档中没有看到任何描述这两个系统之间不同行为的内容 因此

我在Windows上尝试重叠计算和传输时遇到了一些问题(使用VS2015和CUDA 10.1)。代码完全没有重叠。但是Linux上的代码与预期行为完全相同

以下是NVVP的视图:

Windows 10 NVVP屏幕截图:

Linux NVVP屏幕截图:

请注意以下几点:

  • 我的主机内存被分页锁定
  • 我使用两种不同的流
  • 我正在使用cudaMemcpyAsync方法在主机和设备之间进行传输
  • 如果我在Linux上运行我的代码,一切都很好
  • 我在文档中没有看到任何描述这两个系统之间不同行为的内容
因此,问题如下:

我错过什么了吗? 是否存在在该配置(Windows 10+1080Ti)上实现重叠的方法


您可以在此处找到一些代码来重现该问题:

#include "cuda_runtime.h"

constexpr int NB_ELEMS = 64*1024*1024;
constexpr int BUF_SIZE = NB_ELEMS * sizeof(float);

constexpr int BLK_SIZE=1024;

using namespace std;

__global__
void dummy_operation(float* ptr1, float* ptr2)
{
    const int idx = threadIdx.x + blockIdx.x * blockDim.x;
    if(idx<NB_ELEMS)
    {
        float value = ptr1[idx];
        for(int i=0; i<100; ++i)
        {
            value += 1.0f;
        }

        ptr2[idx] = value;
    }
}


int main()
{
    float *h_data1 = nullptr, *h_data2 = nullptr,
        *h_data3 = nullptr, *h_data4 = nullptr;
    cudaMallocHost(&h_data1, BUF_SIZE);
    cudaMallocHost(&h_data2, BUF_SIZE);
    cudaMallocHost(&h_data3, BUF_SIZE);
    cudaMallocHost(&h_data4, BUF_SIZE);

    float *d_data1 = nullptr, *d_data2 = nullptr,
        *d_data3 = nullptr, *d_data4 = nullptr;

    cudaMalloc(&d_data1, BUF_SIZE);
    cudaMalloc(&d_data2, BUF_SIZE);
    cudaMalloc(&d_data3, BUF_SIZE);
    cudaMalloc(&d_data4, BUF_SIZE);

    cudaStream_t st1, st2;
    cudaStreamCreate(&st1);
    cudaStreamCreate(&st2);

    const dim3 threads(BLK_SIZE);
    const dim3 blocks(NB_ELEMS / BLK_SIZE + 1);

    for(int i=0; i<10; ++i)
    {
        float* tmp_dev_ptr = (i%2)==0? d_data1 : d_data3;
        float* tmp_host_ptr = (i%2)==0? h_data1 : h_data3;
        cudaStream_t tmp_st = (i%2)==0? st1 : st2;
        cudaMemcpyAsync(tmp_dev_ptr, tmp_host_ptr, BUF_SIZE, cudaMemcpyDeviceToHost, tmp_st);
        dummy_operation<<<blocks, threads, 0, tmp_st>>>(tmp_dev_ptr, d_data2);
        //cudaMempcyAsync(d_data2, h_data2);
    }

    cudaStreamSynchronize(st1);
    cudaStreamSynchronize(st2);

    return 0;
}
#包括“cuda_runtime.h”
constexpr int NB_ELEMS=64*1024*1024;
constexpr int BUF_SIZE=NB_ELEMS*sizeof(float);
constexpr int BLK_SIZE=1024;
使用名称空间std;
__全球的__
无效虚拟_操作(浮动*ptr1,浮动*ptr2)
{
const int idx=threadIdx.x+blockIdx.x*blockDim.x;

如果(idx如@talonmies所指出的,要重叠计算和传输,您需要在特斯拉计算集群模式下使用图形卡

我用一个旧的Quadro P620检查了这个行为

[Edit]自从我应用Windows10更新1909以来,内核和副本之间的重叠似乎一直在工作


我不确定windows更新是否包含图形驱动程序更新。但可以:)

与linux相比,这可能与Windows上WDDM驱动程序的行为有关。除了在TCC模式下使用受支持的GPU之外,可能没有其他解决方案。代码和探查器输出不匹配。您正在调用
cudaMemcpyDeviceToHost
,但在探查器输出中,它是H2D。您确定此代码生成这些探查器吗结果?@Akifördük你是对的,因为内存是分页锁定的,看起来像是设备内存或主机内存被视为设备,我尝试了CudamCpyDeviceToHost、CudamCpyHostToDevice,CudamCpyDevice执行从主机到设备的复制(根据给定的指针)@talomnies谢谢你给我指出这一点,我会试着找一张quadro卡来确认。你不一定需要TCC卡来获得重叠,但是WDDM驱动程序会执行大量命令批处理等操作,这些操作可能会破坏流式操作的自然流,并导致重叠丢失。有一种方法可以使用注册表项?不知道,我不是一个习惯性的WDDM用户,但我非常怀疑你是否可以在内核启动后尝试插入,以停止驱动程序对内核进行批处理,并立即启动当前批处理。我模糊地记得这不再是推荐的操作过程,但我想不起建议的替换是什么。如果任何人都记得,请在这里发布链接。