Cuda cuBLAS dsyrk比dgemm慢

Cuda cuBLAS dsyrk比dgemm慢,cuda,cublas,Cuda,Cublas,我试图使用cuBLAS在GPU上计算C=A*A',我发现秩k更新cublasDsyrk比常规矩阵乘法例程cublasDgemm运行速度慢5倍左右 这让我感到惊讶;我认为syrk会更快,因为它是一段更专业的代码。这是一个不合理的期望吗?我做错了吗 代码计时 最终,我将编写CUDA代码,并将其编译成MATLAB的MEX文件,因此,对于没有提供完整的工作示例,我深表歉意(与MATLAB对象发生冲突会有很多无关的代码) 我知道这可能不是最好的方法,但我使用clock()来计算代码运行所需的时间: //

我试图使用cuBLAS在GPU上计算C=A*A',我发现秩k更新
cublasDsyrk
比常规矩阵乘法例程
cublasDgemm
运行速度慢5倍左右

这让我感到惊讶;我认为
syrk
会更快,因为它是一段更专业的代码。这是一个不合理的期望吗?我做错了吗

代码计时 最终,我将编写CUDA代码,并将其编译成MATLAB的MEX文件,因此,对于没有提供完整的工作示例,我深表歉意(与MATLAB对象发生冲突会有很多无关的代码)

我知道这可能不是最好的方法,但我使用
clock()
来计算代码运行所需的时间:

// Start of main function
clock_t tic = clock();
clock_t toc;

/* ---- snip ---- */

cudaDeviceSynchronize();

toc = clock();
printf("%8d (%7.3f ms) Allocated memory on GPU for output matrix\n",
        toc-tic,1000*(double)(toc-tic)/CLOCKS_PER_SEC);

// Compute the upper triangle of C = alpha*A*A' + beta*C
stat = cublasDsyrk(handle, CUBLAS_FILL_MODE_UPPER, CUBLAS_OP_N, 
        M, N, &alpha, A, M, &beta, C, M);

toc = clock();
printf("%8d (%7.3f ms) cublasDsyrk launched\n",
        toc-tic,1000*(double)(toc-tic)/CLOCKS_PER_SEC);

cudaDeviceSynchronize();

toc = clock();
printf("%8d (%7.3f ms) cublasDsyrk completed\n",
        toc-tic,1000*(double)(toc-tic)/CLOCKS_PER_SEC);

/* ----- snip ----- */
运行时 在[12 x 500000]随机矩阵(列主存储器)上运行的输出:

syrk
调用替换为

stat = cublasDgemm(handle, CUBLAS_OP_N, CUBLAS_OP_T, M, M, N, 
        &alpha, A, M, A, M, &beta, C, M);
整个过程运行得更快:

  664 (  0.664 ms) Loaded inputs, initialized cuBLAS context
  796 (  0.796 ms) Allocated memory on GPU for output matrix
  941 (  0.941 ms) cublasDgemm launched
16787 ( 16.787 ms) cublasDgemm completed
16837 ( 16.837 ms) Launched fillLowerTriangle kernel
16859 ( 16.859 ms) kernel completed
17263 ( 17.263 ms) Finished and cleaned up
我用其他尺寸的矩阵试过了;有趣的是,当矩阵只有几行时,速度差似乎最为明显。在100行时,
gemm
仅快2倍,而在1000行时则稍慢(这是我一直期望的)

其他详情
我使用的是CUDA Toolkit 7.5,GPU设备是NVIDIA网格K520(开普勒,计算能力3.0)。我正在Amazon EC2 g2.X2大型实例上运行。对于n=121001000的实例,所有这些都是非常宽泛的矩阵。在这些极端情况下,
gemm()
syrk()
可能无法达到其最高性能,其中
syrk()
的速度几乎是
gemm()
的两倍(因为结果矩阵是symmentric,所以可以节省一半的计算)

另一个考虑因素是CUDA
gemm()
/
syrk()
通常将矩阵划分为固定大小的子矩阵,作为实现高性能的基本计算单元。如以下链接所示,对于
dgemm()
,子矩阵的大小可以高达32x64

如果您的大小(12或100)既不比子矩阵大很多,也不是子矩阵的倍数,则性能通常会下降很多

  664 (  0.664 ms) Loaded inputs, initialized cuBLAS context
  796 (  0.796 ms) Allocated memory on GPU for output matrix
  941 (  0.941 ms) cublasDgemm launched
16787 ( 16.787 ms) cublasDgemm completed
16837 ( 16.837 ms) Launched fillLowerTriangle kernel
16859 ( 16.859 ms) kernel completed
17263 ( 17.263 ms) Finished and cleaned up