Cuda 一个函数调用产生了三次执行

Cuda 一个函数调用产生了三次执行,cuda,cublas,Cuda,Cublas,我调用了cublas_Sgemm_v2函数10236次,第一个矩阵未转置,第二个矩阵转置。然而,在nvprof结果中,我看到了从该函数调用生成的三个项。函数调用的(m,n,k)值是(588588,20) nvprof结果中列出了一些项目 Time(%) Time Calls Avg Min Max Name 12.32% 494.86ms 10236 48.344us 47.649us 49.888us sgemm_sm

我调用了
cublas_Sgemm_v2
函数10236次,第一个矩阵未转置,第二个矩阵转置。然而,在
nvprof
结果中,我看到了从该函数调用生成的三个项。函数调用的(m,n,k)值是(588588,20)

nvprof
结果中列出了一些项目

Time(%)      Time     Calls       Avg       Min       Max  Name
 12.32%  494.86ms     10236  48.344us  47.649us  49.888us  sgemm_sm35_ldg_nt_128x8x128x16x16
  8.64%  346.91ms     10236  33.890us  32.352us  35.488us  sgemm_sm35_ldg_nt_64x16x128x8x32
  8.11%  325.63ms     10236  31.811us  31.360us  32.512us  sgemm_sm35_ldg_nt_128x16x64x16x16
这是预期的吗?为什么?有人能解释一下函数名中的值,例如
sgemm\u sm35\u ldg\u nt\u 128x8x128x16x16
是什么意思吗

我还使用不同的转置设置对cublas_Sgemm_v2进行了其他函数调用,每个函数调用只能看到一个项

更新:

正如@Marco13所问,我在这里给出了更多的结果:

Time(%)      Time     Calls       Avg       Min       Max  Name
--------------------------------------------------------------------------------

Resulted from 7984 calls with (Trans, NonTrans) with (m, n, k) = (588, 100, 588)
 20.84%  548.30ms      7984  68.675us  58.977us  81.474us  sgemm_sm35_ldg_tn_32x16x64x8x16

Resulted from 7984 calls with (NonTrans, NonTrans) with (m, n, k) = (588, 100, 588)
 12.95%  340.71ms      7984  42.674us  21.856us  64.514us  sgemm_sm35_ldg_nn_64x16x64x16x16

All the following resulted from 3992 calls with (NonTrans, Trans) with (m, n, k) = (588, 588, 100)
  9.81%  258.15ms      3992  64.666us  61.601us  68.642us  sgemm_sm35_ldg_nt_128x8x128x16x16
  6.84%  179.90ms      3992  45.064us  40.097us  49.505us  sgemm_sm35_ldg_nt_64x16x128x8x32
  6.33%  166.51ms      3992  41.709us  38.304us  61.185us  sgemm_sm35_ldg_nt_128x16x64x16x16
另一次运行将588更改为288:

Time(%)      Time     Calls       Avg       Min       Max  Name
--------------------------------------------------------------------------------

Resulted from 7984 calls with (Trans, NonTrans) with (m, n, k) = (288, 100, 288)
 22.01%  269.11ms      7984  33.706us  30.273us  39.232us  sgemm_sm35_ldg_tn_32x16x64x8x16

Resulted from 7984 calls with (NonTrans, NonTrans) with (m, n, k) = (288, 100, 288)
 14.79%  180.78ms      7984  22.642us  18.752us  26.752us  sgemm_sm35_ldg_nn_64x16x64x16x16

Resulted from 3992 calls with (NonTrans, Trans) with (m, n, k) = (288, 288, 100)
  7.43%  90.886ms      3992  22.766us  19.936us  25.024us  sgemm_sm35_ldg_nt_64x16x64x16x16
从最后三行可以看出,某些转置类型可能比其他类型更有效,并且某些矩阵大小在计算时间方面比矩阵大小更经济。确保经济计算的指导原则是什么

更新2:

对于上面(m,n,k)=(588100588)的情况,我在调用sgemm函数之前手动转置了矩阵,那么
nvprof
结果中只有一项。所需时间仅略少于上表中两项的总和。因此,这样做不会带来太多性能收益

Time(%)      Time     Calls       Avg       Min       Max  Name
--------------------------------------------------------------------------------
 31.65%  810.59ms     15968  50.763us  21.505us  72.098us  sgemm_sm35_ldg_nn_64x16x64x16x16

抱歉,不是答案-但评论的篇幅稍长:

关于编辑,关于“转置”状态的影响:转置矩阵可能会导致访问模式在内存合并方面更糟糕。快速的websearch会带来一些关于此()的结果,但设置与您的略有不同:

DGEMM在K20c上的性能

参数:ta=N tb=N m=4096 N=4096 k=4096 alpha=-1 beta=2 lda=4096 ldb=4096 ldc=4096 运行时间=0.13280010秒GFLOPS=1034.93

参数:ta=T tb=N m=4096 N=4096 k=4096 alpha=-1 beta=2 lda=4096 ldb=4096 ldc=4096 已用时间=0.13872910秒GFLOPS=990.7

参数:ta=N tb=T m=4096 N=4096 k=4096 alpha=-1 beta=2 lda=4096 ldb=4096 ldc=4096 经过时间=0.12521601秒GFLOPS=1097.61

参数:ta=T tb=T m=4096 n=4096 k=4096 alpha=-1 beta=2 lda=4096 ldb=4096 ldc=4096 经过时间=0.13652611秒GFLOPS=1006.69

在这种情况下,更改矩阵存储(例如,从列主存储更改为行主存储,以避免变换矩阵)的麻烦似乎并不值得,因为所有模式似乎都以相似的速度运行。但是你的里程数可能会有所不同——特别是,(t,n)和(n,n)之间的测试差异非常大(548毫秒对340毫秒),这让我感到非常惊讶。如果您可以选择在矩阵的各种表示之间轻松切换,那么覆盖所有四种情况的基准可能是值得的


在任何情况下,关于在那里调用的函数的问题:CUBLAS 1.1中的
sgemm
函数的CUBLAS代码已经充满了展开的循环,并且已经包含了80个(!)版本的
sgemm
函数,用于使用
\define
-hell组装的不同情况。必须假设,在较新的CUBLAS版本中,这一点变得更加不可读,必须考虑到较新的计算能力,并且您在其中找到的函数名表明确实如此:

sgemm\u sm35\u ldg\u nt\u 64x16x128x8x32

  • sm35
    :在具有计算能力3.5的设备上运行
  • ldg
    :?非纹理内存版本?(CUBLAS 1.1包含名为
    sgemm\u main\u tex\u*
    的函数,这些函数用于纹理内存,而
    sgemm\u main\u gld\u*
    函数用于普通全局内存)
  • nt
    :第一个矩阵未转置,第二个矩阵已转置
  • 64x16x128x8x32
    -可能与磁贴大小、共享内存等有关
尽管如此,我仍然认为对
sgemm
的一次调用导致调用其中三个内部函数是令人惊讶的。但正如评论中提到的:我假设他们试图用专门、高效的版本来处理矩阵的“主要”部分,并用能够进行范围检查和/或处理未满扭曲的版本来处理“边界块”。(不是很精确,只是想暗示一下:对于大小为256x256的矩阵,一个有效的核心可以处理大小为288x288的矩阵,对于剩余的32x288和288x32条目,可以进行两次调用)

但所有这一切也是为什么我想关于矩阵大小几乎没有一个通用的指导原则的原因:就计算时间而言,相对于矩阵大小,“最佳”矩阵大小至少取决于

  • 目标系统的硬件版本(计算能力)
  • 换位旗
  • 库布拉斯版本

关于注释的编辑:可以想象,转换和非转换处理之间应该有相当大的区别。当两个矩阵相乘时

a00 a01 a02     b00 b01 b02
a10 a11 a12  *  b10 b11 b12
a20 a21 a22     b20 b21 b22
那么结果的第一个元素将是

a00 * b00 + a01 * b10 + a02 * b20

(它只是
a
的第一行和
b
的第一列的点积)。对于此计算,必须从
a
读取连续值。但是从
b
读取的值不是连续的。相反,它们是“每行中的第一个值”。有人认为这会对记忆整合产生负面影响。当然,英伟达工程师们已经努力避免了任何负面影响,在CuBLAS中实现SGEMM远比“天真的3-NESTRATION循环实现的并行版本”更为明显,这种访问模式会有这样一个明显的缺点。只是一个猜测:取决于矩阵是否是转置的