OpenMP 线程未充分利用新机器上的 CPU 核心

Ana*_*nas 0 c++ multithreading fortran openmp

我有一个多线程应用程序,可以并行解决巨大的矩阵。我最近更换了笔记本电脑,并开始在新笔记本电脑上出现一些奇怪的行为。旧笔记本电脑中的处理器是第 11 代英特尔(R) 酷睿(TM) i9-11950H,新笔记本电脑中的处理器是第 12 代英特尔(R) 酷睿(TM) i9-12900H。在旧笔记本电脑上运行我的多线程应用程序(使用 4 个线程)时,我看到这些线程占用了 4 个核心并充分利用它们,由于笔记本电脑有 8 个物理核心,总体 CPU 使用率约为 50%。请看下图: 在此输入图像描述

当使用相同(完全相同)的可执行二进制文件运行相同的应用程序时,我发现只有一个核心得到充分利用,其余核心的利用率约为 10%-20%,总体 CPU 使用率低于 15%。请看下图: 在此输入图像描述

有没有解释为什么相同的二进制文件在一台机器上运行而没有在另一台机器上运行?

笔记:

  • 我正在使用 OpenMP 启动线程
  • 我尝试将线程的优先级设置为高,但没有帮助

注意:在配备第 12 代英特尔(R) 酷睿(TM) i9-12900H 的笔记本电脑上,我从 BIOS 禁用了 E 核心,以确保线程仅分配给 P 核心,但这并没有解决问题。请看下面: 在此输入图像描述

从上图中我们可以看到,只有线程1充分利用了它的CPU。

以下是我启动线程的方式:

    CALL OMP_SET_NUM_THREADS(4)
    !$OMP PARALLEL DO PRIVATE(i)  
    DO i = 1, 4, 1
        CALL solve_axb_r_submat(n, A, line_A, X, B, flag, i, submatrix_number, Fkluunit(i))
    END DO
    !$OMP END PARALLEL DO
Run Code Online (Sandbox Code Playgroud)

上面的代码被调用超过 20000 次,因此每次迭代都会调用一个具有上面代码段的函数。我正在使用 Visual studio 2022 和 OpeApi 2023 在 Windows 上工作。以下是我的一些项目属性: 在此输入图像描述 在此输入图像描述 在此输入图像描述 在此输入图像描述 在此输入图像描述

请注意我们添加的命令行以确定上一个图像中线程的关联性。当我们添加时,我们看到线程被固定在同一个核心上,并且不在核心之间移动。

Jér*_*ard 6

i9-11950H 处理器是 Tiger-Lake 处理器,而 i9-12900H 是 Alder-Lake 处理器。主要区别在于 Alder-Lake 具有 Big-Little 架构,而前者是统一的(并且更加主流)。实际上,这意味着有两组核心:大核心速度快但能量效率低,小核心能量效率高但速度慢。这种架构在笔记本电脑上非常有趣,因此可以在性能和功耗之间提供良好的权衡。在某些特定情况下,高效的内核还可以帮助提高 CPU 的整体性能。坏消息是,迄今为止,许多运行时和应用程序对这种架构的支持很差。一个主要问题是不同类型的核心导致的负载不平衡。事实上,对于相同的工作负载,在性能核心上运行的 1 个线程通常比在高效核心上运行的线程运行得更快。较快的线程应等待其他线程,因此整体计算受到较慢核心的限制。我想这就是这里发生的情况:1 个核心被密集使用,而其他 3 个核心几乎没有使用,其他核心则处于空闲状态。我的假设是,密集使用的核心是高效核心,而其他核心是性能核心(等待慢速核心)。

您可以请求 OpenMP 使用动态调度,以便自动平衡不同内核之间的工作负载。这会产生额外的开销,但在这种情况下可能会更好。schedule(dynamic)一种方法是在并行 for 循环上使用子句。另一种方法是调整环境变量OMP_SCHEDULE

或者,您可以自行绑定 OpenMP 线程,以便使用相同类型的内核。您可以通过更改环境变量来做到这一点OMP_PROC_BINDOMP_PLACES这应该是操作系统应该自动执行的操作,但看起来它失败了(或者这实际上不是问题)...

  • 此外,像 VTune 这样的低级分析工具可以帮助查看负载不平衡(假设这是来自此)。这是一个好主意,既可以使用它来确认/否定假设,也可以在假设被证明不正确时获得大量有用的信息。如果 OpenMP 线程正在旋转等待(假设等待策略处于活动状态),您可以在时间轴上看到以橙色显示的 OpenMP 线程等待时间。使用被动等待策略,您应该看到大多数线程在一个正在计算的同时没有被调度。 (2认同)
  • @PierU 一些 OpenMP 运行时(例如 IOMP)默认将线程绑定到核心,并且这种绑定有时会在异常/新架构(尤其是非统一架构)上被破坏。到目前为止,它发生在 3 种不同的 (HPC) 架构上。拥有这样的绑定是相当令人惊讶的,但这是迄今为止我根据所提供的信息得到的最好的解释(这也是为什么我提倡检查假设并以其他方式检索附加信息)。 (2认同)