9

cudaMalloc 在 CUDA 4.x 上,第一次调用可能非常慢(这被报告了好几次),这似乎是 CUDA 驱动程序中的一个错误,这已经不是什么秘密了。

最近,我注意到奇怪的行为:运行时间cudaMalloc 直接取决于我链接到我的程序的第 3 方 CUDA 库的数量(请注意,我不使用这些库,只是将我的程序与它们链接)

我使用以下程序运行了一些测试:

int main() {
  cudaSetDevice(0);
  unsigned int *ptr = 0;
  cudaMalloc((void **)&ptr, 2000000 * sizeof(unsigned int));   
  cudaFree(ptr);
return 1;
}

结果如下:

  • 链接:-lcudart -lnpp -lcufft -lcublas -lcusparse -lcurand 运行时间:5.852449

  • 链接:-lcudart -lnpp -lcufft -lcublas 运行时间:1.425120

  • 链接:-lcudart -lnpp -lcufft 运行时间:0.905424

  • 链接:-lcudart 运行时间:0.394558

根据'gdb',时间确实进入了我的cudaMalloc,所以它不是由一些库初始化例程引起的..

我想知道是否有人对此有合理的解释?

4

1 回答 1

11

在您的示例中,cudaMalloc调用会在 GPU 上启动惰性上下文建立。当包含运行时 API 库时,必须检查它们的二进制有效负载,并将它们包含的 GPU 精灵符号和对象合并到上下文中。库越多,您预计该过程所需的时间就越长。此外,如果任何 cubin 中存在架构不匹配并且您拥有向后兼容的 GPU,它还可以触发目标 GPU 的设备代码的驱动程序重新编译。在一个非常极端的情况下,我看到一个与旧版本 CUBLAS 链接的旧应用程序在 Fermi GPU 上运行时需要 10 秒来加载和初始化。

您可以通过发出cudaFree如下调用来显式强制建立惰性上下文:

int main() {
    cudaSetDevice(0);
    cudaFree(0); // context establishment happens here
    unsigned int *ptr = 0;
    cudaMalloc((void **)&ptr, 2000000 * sizeof(unsigned int));   
    cudaFree(ptr);
  return 1;
}

如果您使用计时器分析或检测此版本,您应该会发现第一次cudaFree调用会消耗大部分运行时,并且cudaMalloc调用几乎是免费的。

于 2012-07-26T08:46:26.907 回答