ArrayFire CUDA应用程序在第一分钟非常慢

时间:2018-05-08 20:56:06

标签: c++ cuda arrayfire

我正在使用在Windows 10 + Nvidia Gtx 970上运行的ArrayFire编写测试程序。该程序将使用SGD解算器训练神经网络。因此,主要计算是更新网络参数的迭代。迭代在一个名为step()的函数中。

该程序执行预期的操作,但它在第一分钟执行速度极慢。以下是该程序的输出。第一列是经过的时间。

ArrayFire v3.5.1 (CUDA, 64-bit Windows, build 0a675e8)
Platform: CUDA Toolkit 8, Driver: CUDA Driver Version: 8000
[0] GeForce GTX 970, 4096 MB, CUDA Compute 5.2
  time epochs training error
     5  0.002 5.6124567
     6  0.007 5.5981609
     7  0.010 5.3560046
     8  0.015 5.2485286
     9  0.020 5.1370633
    10  0.022 5.1081303
     ....
    52  0.148 3.2528560
    53  0.150 3.2425120
    54  0.153 3.2180901
    55  0.155 3.2048657
    56  0.157 3.1949191
    57  0.158 3.1816899
    58  0.160 3.1717312
    59  0.162 3.1597322
    60  0.165 3.1370639
    60  0.498 2.1359600
    61  0.548 2.0685355
    61  0.882 1.7098215
    62  0.943 1.6575973
    62  1.277 1.4156345
    63  1.343 1.3845720
    63  1.677 1.1789854
    64  1.733 1.1549067
    64  2.067 1.0162785
     ....
    71  4.517 0.4732214
    71  4.850 0.4522045
    72  4.910 0.4501807
    72  5.243 0.4355422
    73  5.305 0.4307187

正如你所看到的,在第一分钟,它甚至没有完成1/5的时代。但过了一分钟,它突然加速,在大约4秒钟内完成了一个时代。

分析数据也说明了同样的事情:在第一分钟,函数step()的平均执行时间约为500毫秒,但在第一分钟后,它下降到6毫秒。

Nvidia visual profiler显示内核在第一分钟内几乎处于空闲状态。

我不知道在第一分钟之后可能导致性能变化的原因。任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:2)

ArrayFire在运行时使用JIT编译来融合多个函数调用。因此,当您执行添加或任何其他元素操作时,ArrayFire将创建自定义内核并执行此内核。当您第一次生成此内核时,这会产生一些开销,但这些内核会被缓存,并且不需要编译其他调用。通常,在不需要额外的编译之前,它应该只需要几次迭代。奇怪的是,即使经过60次左右的迭代,内核也很慢。

使用基于内核和内核大小的内部启发式方法评估JIT内核。也许您的应用程序没有以最佳方式触发内核并导致额外的内核编译。您可以通过调用变量上的eval函数来强制进行评估。这是一个人为的例子:

array a = randu(10, 10);
array b = randu(10, 10);
for(int i = 0; i < 100; i++) {
      a += b / 4;
      b *= i;
      eval(a, b);
}

在这里,您将在每次迭代时评估变量a和b的JIT树。这将在每次迭代时重用相同的内核,而不是为不同的迭代次数创建内核。

需要注意的是元素方面,以及像select和shift这样的条件函数是JITed。其他功能在使用之前强制评估其参数。此外,如果您经常评估,您将降低应用程序的性能。