当gemm做时,sgemm不多线程

sgemm does not multithread when dgemm does - Intel MKL

本文关键字:多线程 sgemm gemm 做时      更新时间:2023-10-16

我正在使用英特尔MKL的?GEMM函数来乘矩阵。考虑以下两个矩阵乘法:

            cblas_?gemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, m,n,k,
                            1.0,
                            Matrix1,k,
                            Matrix2,n,
                            0.0,
                            A,n);

,其中m=1E5, n=1E4, k=5。当我使用pca_dgemm和pca_sgemm时,它使用所有12个内核,并且执行得很漂亮。

然而,当我做下面的矩阵乘法时:

    cblas_?gemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, m,l,n,
                    1.0,
                    A,n,
                    Ran,l,
                    0.0,
                    Q,l);

,其中m=1E5, n=1E5, l=7(注意传递的参数顺序不同)。这是(m,n) * (n,l))Pca_dgemm使用所有12个内核,并且执行得非常漂亮。

但是,pca_sgemm没有。它只使用一个核心,当然,需要更长的时间。当然,对于sgemm,我使用浮点数数组,而对于dgemm,我使用双精度数数组。

为什么会这样?它们都给出了准确的结果,但是在前者上只使用多线程,而在两者上都使用多线程!简单地改变数据类型怎么会产生这种差异呢?

请注意,所有数组都是使用mkl_malloc分配的,使用64的对齐方式。

编辑2:还请注意,当l=12时,换句话说,有一个更大的矩阵,它在sgemm中线程。换句话说,很明显,sgemm版本需要更大的矩阵来并行化,但dgemm没有这个要求。为什么会这样?

MKL函数预先做了相当多的工作来尝试猜测执行操作的最快方式,因此在处理双精度数或单精度数时得出不同的决定并不奇怪。

在决定采用哪种策略时,它必须权衡在单个线程中执行操作的成本与启动线程并行执行操作的开销。其中一个重要的因素是SSE指令对单精度数字的操作速度是双精度数字的两倍,因此启发式可能会认为,在单个核上执行SSE SIMD操作可能比在单个核上执行SSE SIMD操作更快,而不是踢开12个线程并行执行。它到底能并行处理多少将取决于你的CPU架构的细节;例如,SSE2可以对四个单操作数或两个双操作数进行操作,而最新的SSE指令集支持更广泛的数据。

我在过去发现,对于小矩阵/向量,滚动自己的函数通常比使用MKL更快。例如,如果您的所有操作都是在3向量和3x3矩阵上,那么用纯C编写自己的BLAS函数要快得多,使用SSE优化它们要快得多(如果您能满足对齐约束)。对于3向量和6向量的混合,编写自己的优化SSE版本仍然更快。这是因为当操作很小时,MKL版本决定使用哪种策略的成本会成为相当大的开销。