我将cublas_Sgemm_v2
函数调用了10236次,其中第一个矩阵非转置,第二个转置。但是,在nvprof
结果中,我看到了该函数调用生成的三个项目。函数调用的(m,n,k)值是(588,588,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_sm35_ldg_nt_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)=(588,100,588)的情况,我在调用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
答案 0 :(得分:2)
对不起,不是答案 - 但评论时间太长了:
关于编辑,关于“转置”状态的影响:转置矩阵可能会导致访问模式在内存合并方面更糟糕。一个快速的网络搜索带来了一些关于此的结果(https://devtalk.nvidia.com/default/topic/528450/cuda-programming-and-performance/cublas-related-question/post/3734986/#3734986),但设置略有不同:
K20c上的DGEMM性能
args:ta = N tb = N m = 4096 n = 4096 k = 4096 alpha = -1 beta = 2 lda = 4096 ldb = 4096 ldc = 4096 elapsed = 0.13280010秒GFLOPS = 1034.93
args:ta = T tb = N m = 4096 n = 4096 k = 4096 alpha = -1 beta = 2 lda = 4096 ldb = 4096 ldc = 4096 elapsed = 0.13872910秒GFLOPS = 990.7
args:ta = N tb = T m = 4096 n = 4096 k = 4096 alpha = -1 beta = 2 lda = 4096 ldb = 4096 ldc = 4096 elapsed = 0.12521601秒GFLOPS = 1097.61
args:ta = T tb = T m = 4096 n = 4096 k = 4096 alpha = -1 beta = 2 lda = 4096 ldb = 4096 ldc = 4096 elapsed = 0.13652611秒GFLOPS = 1006.69
在这种情况下,差异似乎不值得改变矩阵存储(例如从列主要到行主要,以避免转置矩阵)的麻烦,因为所有模式似乎以相似的速度运行。但你的里程可能会有所不同 - 特别是,(t,n)和(n,n)之间的测试差异非常大(548ms vs 340ms),我发现这很令人惊讶。如果您可以选择在矩阵的各种表示之间轻松切换,那么涵盖所有四种情况的基准可能是值得的。
在任何情况下,关于你在那里调用的函数的问题:CUBLAS 1.1中sgemm
函数的CUBLAS代码已经充满了展开的循环,并且已经包含了{{{)版本的{{1} 1}}用于使用sgemm
组装的不同案例的函数 - 地狱。必须假设这在新的CUBLAS版本中变得更加难以理解,在这些版本中必须考虑更新的计算能力 - 并且您在那里找到的函数名称表明确实如此:
#define
sgemm_sm35_ldg_nt_64x16x128x8x32
:在具有计算能力3.5 sm35
:?非纹理内存版本? (CUBLAS 1.1包含名为ldg
的函数,它们用于纹理内存,函数sgemm_main_tex_*
用于正常的全局内存)sgemm_main_gld_*
:第一个矩阵未转置,第二个矩阵为转置nt
- 可能与磁贴大小相关,可能是共享内存等... 尽管如此,我认为单次调用64x16x128x8x32
导致调用这些内部函数的三个是令人惊讶的。但正如评论中所提到的:我假设他们尝试使用专门的高效版本处理矩阵的“主要”部分,并使用能够进行范围检查和/或应对经线的“边界瓷砖”。不满。 (不是很精确,只是为了暗示:大小为288x288的矩阵可以由大小为256x256的矩阵的高效核心处理,并且对剩余的32x288和288x32条目进行两次调用)。
但所有这些也是为什么我猜几乎没有关于矩阵大小的一般准则的原因:就矩阵大小的计算时间而言,“最佳”矩阵大小至少取决于
编辑关于评论:可以想象,转换和非转置处理之间应该存在相当大的差异。乘以两个矩阵时
sgemm
然后结果的第一个元素是
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
读取的值不是是连续的。相反,它们是“每行中的第一个值”。一个可能认为这会对内存合并产生负面影响。但可以肯定的是,NVIDIA的工程师们已经尽力避免在这里产生任何负面影响,而且CUBLAS中b
的实现远远不是“天真的3嵌套循环实现的并行版本”,其中访问模式会有这么明显的缺点。