并行化矩阵乘法时,虚拟内核是否有助于提高性能?

Do virtual cores contribute to performance when parallelizing a matrix multiplication?

我在 C 中有一个 O(n^3) 矩阵乘法函数。

void matrixMultiplication(int N, double **A, double **B, double **C, int threadCount) {
  int i = 0, j = 0, k = 0, tid;

  pragma omp parallel num_threads(4) shared(N, A, B, C, threadCount) private(i, j, k, tid) { 
    tid = omp_get_thread_num();
    pragma omp for
      for (i = 1; i < N; i++) 
      {
        printf("Thread %d starting row %d\n", tid, i);
        for (j = 0; j < N; j++)
        {
          for (k = 0; k < N; k++) 
          {
            C[i][j] = C[i][j] + A[i][k] * B[k][j];
          }
        }
      }
    }
    return; 
    }

我正在使用 OpenMP 通过拆分乘法来并行化此函数。我正在使用 1.8 GHz Intel Core i5 处理器对大小为 N = 3000 的方阵执行此计算。

该处理器有两个物理内核和两个虚拟内核。我注意到我的计算有以下表现

我曾预计我的收益会持续到将线程数设置为四个为止。然而,这显然没有发生。

为什么会这样?是因为一个核心的性能等于它的物理核心和虚拟核心的总和吗?

我猜瓶颈是内存(或L3 CPU cache)带宽。这些天算术很便宜。

如果负担得起,请尝试在更强大的处理器(例如某些 socket 2013 i7)上使用相同的数据对相同的代码进行基准测试

请记住,在当今的处理器上,缓存未命中会持续数百条指令(或周期):RAM 非常慢 w.r.t。缓存或 CPU.

顺便说一句,如果你有 GPGPU you could play with OpenCL.

此外,像 LAPACK (or some other numerical libraries) 这样的线性软件包可能比您的简单矩阵乘法更有效。

您也可以考虑使用 __builtin_prefetch(参见 this

顺便说一句,数值计算很难。我根本不是专家,但我遇到了在其中工作了数十年的人(通常是在该领域获得博士学位之后)。

根据具体情况,每个内核使用一个以上的硬件线程可能有帮助也有坏处。

如果一个硬件线程由于高速缓存未命中而停止,而另一个硬件线程可以继续运行并保持 ALU 忙碌,这会有所帮助。

如果每个硬件线程都强制逐出另一个线程所需的数据,则可能会造成伤害。那就是线程破坏性地相互干扰。

解决该问题的一种方法是以一种方式编写内核,使每个线程只需要一半的缓存。例如,阻塞矩阵乘法可用于最小化矩阵乘法的高速缓存占用空间。

另一种方法是编写算法,使两个线程同时对同一数据进行操作,从而相互帮助将数据放入缓存(建设性干扰)。不可否认,这种方法很难用 OpenMP 实现,除非实现对嵌套并行性有很好的支持。