【问题标题】:CUDAfy CopyFromDevice several orders of magnitude slower than CopyToDeviceCUDAfy CopyFromDevice 比 CopyToDevice 慢几个数量级
【发布时间】:2015-11-16 08:03:33
【问题描述】:

我正在使用小型重力模拟测试 CUDAfy,在对代码运行分析器后,我发现大部分时间都花在了 GPU 的 CopyFromDevice 方法上。代码如下:

    private void WithGPU(float dt)
    {
        this.myGpu.CopyToDevice(this.myBodies, this.myGpuBodies);
        this.myGpu.Launch(1024, 1, "MoveBodies", -1, dt, this.myGpuBodies);
        this.myGpu.CopyFromDevice(this.myGpuBodies, this.myBodies);
    }

澄清一下,this.myBodies 是一个包含 10,000 个结构的数组,如下所示:

[Cudafy(eCudafyType.Struct)]
[StructLayout(LayoutKind.Sequential)]
internal struct Body
{
    public float Mass;

    public Vector Position;

    public Vector Speed;
}

Vector 是一个结构体,有两个浮点数 X 和 Y。

根据我的分析器,这三行的平均时间是 0.092、0.192 和 222.873 毫秒。这些时间是在带有 NVIDIA NVS 310 的 Windows 7 上拍摄的。

有没有办法提高 CopyFromDevice() 方法的时间?

谢谢

【问题讨论】:

  • 实际执行处理可能需要 222.873 毫秒? CopyFromDevice 需要等待处理完成才能进行复制。
  • 我如何辨别是不是这样?
  • 好问题。老实说,我不知道。我花了一些时间使用 CUDA 来解决我遇到的问题;我最终放弃了这个概念,因为它比它的价值更麻烦,而且实际上需要更长的时间才能为我的特定问题产生结果。据我所知,您将“网格”的大小定义为 1024,但该块仅设置为 1。我认为这实质上意味着您仅在 GPU 上使用一个线程。不要引用我的话——我现在没有时间查看文档。他们确实有一个有用的 CODAfy.net 教程,其中包含可能有用的代码示例
  • 达伦的第一条评论很可能是这样。尝试在内核启动后立即添加this.myGpu.Synchronize(); (this.myGpu.Launch...)。这将充当一个屏障,并在那里等待内核完成,然后再允许主机线程继续。因此它将“吸收”内核中的所有 CUDA 处理时间,然后剩余的CopyFromDevice 操作应该在分析器中缩小到适当的大小。
  • 嗨罗伯特。是的,时间都花在了处理上。添加 Synchronize() 调用后,CopyFromDevice 的时间减少到更合理的数量。请添加您的评论作为接受它的答案。

标签: c# cuda cudafy.net


【解决方案1】:

CUDA 内核启动是异步。这意味着在启动内核后立即释放 CPU 线程以在内核启动后立即处理代码,而内核仍在执行。

如果后续代码包含任何类型的 CUDA 执行屏障,则 CPU 线程将在该屏障处停止,直到内核执行完成。在 CUDA 中,cudaMemcpy(cudafy CopyFromDevice 方法的底层操作)和cudaDeviceSynchronize(cudafy Synchronize 方法底层的操作)都包含执行障碍。

因此,从主机代码的角度来看,内核启动后立即出现的这种屏障似乎会在内核执行期间停止 CPU 线程执行。

因此,此示例中的特定障碍将包括内核执行时间和数据复制时间。您可以在内核启动后立即使用Synchronize 屏障方法来消除通过分析主机代码指示的时间的歧义。

【讨论】:

    猜你喜欢
    • 2016-06-19
    • 2021-07-23
    • 2014-07-06
    • 2016-06-13
    • 2012-04-14
    • 2022-10-23
    • 1970-01-01
    • 2016-08-23
    • 1970-01-01
    相关资源
    最近更新 更多