4

当我尝试重叠数据传输和内核执行时,无论我使用什么流,卡似乎都在按顺序执行所有内存传输。

所以,如果我发出以下内容:

  • 流 1:MemcpyA_HtoD_1;内核_1;MemcpyA_DtoH_1
  • 流 2:MemcpyA_HtoD_2;内核_2;MemcpyA_DtoH_2

MemcpyA_HtoD_2 将等到 MemcpyA_DtoH_1 完成。所以没有实现重叠。无论我使用什么配置的流,Memcpy 操作总是按顺序发出。因此,实现重叠的唯一方法是缓冲输出或将输出传输延迟到下一次迭代。

我使用 CUDA 5.5、Windows 7 x64 和 GTX Titan。所有 cpu 内存都被固定,并且 data_transfers 使用异步版本完成。

请参阅以下屏幕的行为:

发出,host_to_device -> kernel -> device_to_host(正常行为)并且不能重叠。

不重叠

发出 host_to_device -> 内核(避免内核后的 device_to_host)得到重叠......因为所有内存副本都是按顺序执行的,无论我尝试什么流配置。

重叠

更新

如果有人有兴趣重现此问题,我编写了一个合成程序来显示这种不良行为。它是使用 CUDA 5.5 的完整 VS2010 解决方案

VS2010 Streams Not Working 链接

有人可以在 linux 上执行这个来测试重叠吗?

#include "cuda_runtime.h"
#include "device_launch_parameters.h"


#include <stdio.h>
#define N 1024*1024

__global__ void someKernel(int *d_in, int *d_out) {
    for (int i = threadIdx.x; i < threadIdx.x + 1024; i++) {
        d_out[i] = d_in[i];
    }
}

int main () {
    int *h_bufferIn[100];
    int *h_bufferOut[100];
    int *d_bufferIn[100];
    int *d_bufferOut[100];

    //allocate some memory
    for (int i = 0; i < 100; i++) {
        cudaMallocHost(&h_bufferIn[i],N*sizeof(int));
        cudaMallocHost(&h_bufferOut[i],N*sizeof(int));
        cudaMalloc(&d_bufferIn[i], N*sizeof(int));
        cudaMalloc(&d_bufferOut[i], N*sizeof(int));
    }

    //create cuda streams
    cudaStream_t st[2];
    cudaStreamCreate(&st[0]);
    cudaStreamCreate(&st[1]);

    //trying to overlap computation and memcpys
    for (int i = 0; i < 100; i+=2) {
        cudaMemcpyAsync(d_bufferIn[i], h_bufferIn[i], N*sizeof(int), cudaMemcpyHostToDevice, st[i%2]);
        someKernel<<<1,256, 0, st[i%2]>>>(d_bufferIn[i], d_bufferOut[i]);
        cudaMemcpyAsync(h_bufferOut[i], d_bufferOut[i], N*sizeof(int), cudaMemcpyDeviceToHost, st[i%2]);
        cudaStreamQuery(0);

        cudaMemcpyAsync(d_bufferIn[i+1], h_bufferIn[i+1], N*sizeof(int), cudaMemcpyHostToDevice, st[(i+1)%2]);
        someKernel<<<1,256, 0, st[(i+1)%2]>>>(d_bufferIn[i+1], d_bufferOut[i+1]);
        cudaMemcpyAsync(h_bufferOut[i+1], d_bufferOut[i+1], N*sizeof(int), cudaMemcpyDeviceToHost, st[(i+1)%2]);
        cudaStreamQuery(0);
    }
    cudaDeviceSynchronize();
}
4

1 回答 1

1

TL;DR:这个问题是由 Nsight Monitor 中的 WDDM TDR 延迟选项引起的!当设置为 false 时,会出现问题。相反,如果您将 TDR 延迟值设置为一个非常高的数字,并将“启用”选项设置为 true,那么问题就会消失。

阅读下面的其他(旧)步骤,直到我找到上面的解决方案,以及其他一些可能的原因。

我最近才能够部分解决这个问题!我认为它是特定于 windows 和 aero 的。请尝试这些步骤并发布您的结果以帮助他人!我在 GTX 650 和 GT 640 上试过。

在您执行任何操作之前,请考虑同时使用板载 gpu(作为显示器)和离散 gpu(用于计算),因为已验证适用于 windows 的 nvidia 驱动程序存在问题!当您使用板载 gpu 时,所说的驱动程序没有完全加载,因此避免了很多错误。此外,在工作时保持系统响应能力!

  1. 确保您的并发问题与旧驱动程序(包括 bios)等其他问题无关。
  2. 转到计算机>属性
  3. 选择左侧的高级系统设置
  4. 转到高级选项卡
  5. 在性能点击设置
  6. 在“视觉效果”选项卡中,选择“调整以获得最佳性能”项目符号。

这将禁用航空和几乎所有的视觉效果。如果此配置有效,您可以尝试逐一启用视觉效果框,直到找到导致问题的精确框!

或者,您可以:

  1. 右键桌面,选择个性化
  2. 从没有航空的基本主题中选择一个主题。

这也可以像上面那样工作,但启用了更多的视觉选项。对于我的两台设备,此设置也适用,所以我保留了它。

请,当您尝试这些解决方案时,请回到这里并发布您的发现!

对我来说,它解决了大多数情况下的问题(我制作的平铺 dgemm),但请注意,我仍然无法正确运行“simpleStreams”并实现并发......

更新:问题已通过新的 Windows 安装完全解决!前面的步骤改善了某些情况下的行为,但只有全新安装才能解决所有问题!

我会尝试找到一种不太激进的方法来解决这个问题,也许只恢复注册表就足够了。

于 2015-04-21T14:21:42.233 回答