【问题标题】:How to obtain performance enhancement while multiplying two sub-matrices?如何在将两个子矩阵相乘时获得性能提升?
【发布时间】:2023-01-12 23:31:42
【问题描述】:

我有一个程序将驻留在同一容器矩阵中的两个子矩阵相乘。我试图通过使用 OpenMP API 进行并行化来获得一些性能提升。下面是我使用的乘法算法。

#pragma omp parallel for
for(size_t i = 0; i < matrixA.m_edgeSize; i++) {
    for(size_t k = 0; k < matrixA.m_edgeSize; k++) {
        for(size_t j = 0; j < matrixA.m_edgeSize; j++) {
            resultMatrix(i, j) += matrixA(i, k) * matrixB(k, j);
        }
    }
}

该算法按行访问两个输入子矩阵的元素,以增强空间局部性的缓存使用。

可以使用哪些其他 OpenMP 指令从该简单算法中获得更好的性能?有没有其他指令可以优化两个子矩阵重叠区域的操作?

您可以假设所有子矩阵都具有相同的大小并且它们是方形的。生成的子矩阵驻留在另一个容器矩阵中。

【问题讨论】:

  • 是为了实用还是为了学习?在第一种情况下,有很多高性能线性代数库可以为您的特定 CPU 进行各种优化
  • “如何在两个子矩阵相乘的同时获得性能提升?” - 第一步是转向构建代码时的编译器优化器(调试构建(通常是编译器默认)可以是真的慢的)。
  • @Unlikus 这是为了学习。感谢您的建议。
  • @JesperJuhl 我的目的是增强这个单一的代码片段。无论如何,感谢您的优化建议。

标签: c++ openmp matrix-multiplication


【解决方案1】:

还有一些其他 OpenMP 指令可用于优化此矩阵乘法算法的性能:

#pragma omp 崩溃:此指令允许您将多个嵌套循环折叠为一个循环,从而减少创建和管理线程的开销。您可以使用此指令来折叠外部两个循环,如下所示:

#pragma omp parallel for collapse(2)
    for(size_t i = 0; i < matrixA.m_edgeSize; i++) {
        for(size_t k = 0; k < matrixA.m_edgeSize; k++) {
            for(size_t j = 0; j < matrixA.m_edgeSize; j++) {
                resultMatrix(i, j) += matrixA(i, k) * matrixB(k, j);
            }
        }
    }

#pragma omp simd:该指令告诉编译器对最内层循环进行矢量化,允许 CPU 使用其 SIMD(单指令多数据)功能并行执行多个操作。这可以像这样添加到最内层的循环中:

#pragma omp parallel for collapse(2)
    for(size_t i = 0; i < matrixA.m_edgeSize; i++) {
        for(size_t k = 0; k < matrixA.m_edgeSize; k++) {
            #pragma omp simd
            for(size_t j = 0; j < matrixA.m_edgeSize; j++) {
                resultMatrix(i, j) += matrixA(i, k) * matrixB(k, j);
            }
        }
    }

#pragma omp 时间表:此指令允许您控制循环迭代在线程之间的分配方式。您可以使用静态、动态、引导式或自动调度来平衡线程之间的工作负载。

#pragma omp parallel for collapse(2) schedule(dynamic)
    for(size_t i = 0; i < matrixA.m_edgeSize; i++) {
        for(size_t k = 0; k < matrixA.m_edgeSize; k++) {
            #pragma omp simd
            for(size_t j = 0; j < matrixA.m_edgeSize; j++) {
                resultMatrix(i, j) += matrixA(i, k) * matrixB(k, j);
            }
        }
    }

#pragma omp atomic:此指令可用于确保对 resultMatrix(i,j) 元素的操作是原子的,并防止在多个线程尝试同时更新同一元素时可能发生的任何竞争条件。

#pragma omp parallel for collapse(2) schedule(dynamic)
    for(size_t i = 0; i < matrixA.m_edgeSize; i++) {
        for(size_t k = 0; k < matrixA.m_edgeSize; k++) {
            #pragma omp simd
            for(size_t j = 0; j < matrixA.m_edgeSize; j++) {
                #pragma omp atomic
                resultMatrix(i, j) += matrixA(i, k) * matrixB(k, j);
            }
        }
    }

值得注意的是,这些 OpenMP 指令的性能提升将取决于特定的硬件、编译器和其他因素。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-17
    • 2015-04-19
    • 1970-01-01
    • 2018-10-02
    • 2018-01-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多