【问题标题】:Why would omp_set_num_threads( omp_get_num_threads() ) change anything?为什么 omp_set_num_threads( omp_get_num_threads() ) 会改变任何东西?
【发布时间】:2021-03-26 16:43:22
【问题描述】:

我遇到了一些奇怪的事情。我正在一台只有一个不起眼的 4 核 I3 的小型本地机器上测试 MPI + OMP 并行代码。事实证明,我的一个循环非常慢,在这个环境中每个进程有超过 1 个 OMP 线程(线程多于内核)。

#pragma omp parallel for
for ( int i = 0; i < HEIGHT; ++i ) 
{
    for ( int j = 0; j < WIDTH; ++j ) 
    {
        double a = 
           ( data[ sIdx * S_SZ + j + i * WIDTH ] - dMin ) / ( dMax - dMin );

        buff[ i ][ j ] = ( unsigned char ) ( 255.0 * a );
    }
}

如果我使用默认值运行此代码(不设置 OMP_NUM_THREADS,或使用 omp_set_num_threads),则大约需要 1 秒。但是,如果我使用任何一种方法(export OMP_NUM_THREADS=1omp_set_num_threads(1)))显式设置线程数,则大约需要 0.005 秒(快 200 倍)。

但似乎omp_get_num_threads() 无论如何都会返回 1。事实上,如果我只是这样做 omp_set_num_threads( omp_get_num_threads() ); 则大约需要 0.005 秒,而注释掉该行需要 1 秒。

知道这里发生了什么吗?为什么在程序开始时调用一次omp_set_num_threads( omp_get_num_threads() ) 会导致 200 倍的性能差异?

一些上下文,

cpu:             Intel(R) Core(TM) i3-9100F CPU @ 3.60GHz
g++ --version:   g++ (GCC) 10.2.0
compiler flags:  mpic++ -std=c++11 -O3 -fpic -fopenmp ...
running program: mpirun -np 4 ./a.out

【问题讨论】:

    标签: c++ multithreading parallel-processing mpi openmp


    【解决方案1】:

    我遇到了一些奇怪的事情。我正在测试 MPI + OMP 并行代码 在只有一个简单的 4 核 I3 的小型本地机器上。之一 事实证明,我的循环非常慢,每个循环超过 1 个 OMP 线程 此环境中的进程(线程多于内核)。

    首先,如果没有将OpenMP 线程(在 MPI 进程内)与内核进行任何显式绑定,人们无法确定这些线程最终会在哪个内核中结束。自然,在同一个逻辑核心中运行多个线程通常会增加被并行化的应用程序的整体执行。您可以通过以下任一方式解决此问题 1) 禁用与 MPI 标志--bind-to none 的绑定,以便将线程分配给不同的内核; 2) 或相应地执行线程绑定。查看SO thread,了解如何将线程映射到混合并行化中的核心,例如MPI + OpenMP

    尽管如此,即使一个(假设)每个进程映射到一个核心,并且 每个 核心有 4 个线程,假设每个核心都有两个 逻辑核心(ie,超线程),应用程序的整体执行时间很可能比使用 4 进程 x 1 线程运行它要慢。在当前情况下,人们可能希望(最多)使用4 Process x 2 线程来提高性能。

    但似乎 omp_get_num_threads() 无论如何都会返回 1。而在 事实上,如果我只是这样做 omp_set_num_threads( omp_get_num_threads() );

    来自source 可以阅读:

    2.15 omp_get_num_threads – 活跃团队的规模

    说明:*返回当前团队中的线程数。 在一个 程序 omp_get_num_threads 的顺序部分返回 1。

    非正式地,如果在并行区域之外调用omp_get_num_threads(),则会得到1 作为线程数,即初始线程

    为什么要调用一次 omp_set_num_threads(omp_get_num_threads()) 在程序开始时会导致 200X 的差异 性能?

    问题的根本原因不是调用omp_set_num_threads( omp_get_num_threads() )per si,而是线程正在争夺资源这一事实。通过将 per 进程的线程数显式设置为 1,您可以确保应用程序使用 1 线程 per 内核运行,从而导致没有多个线程在同一个核心争夺资源。

    【讨论】:

      猜你喜欢
      • 2019-08-17
      • 2019-05-26
      • 2018-08-20
      • 2012-09-11
      • 2020-11-15
      • 1970-01-01
      • 2022-09-30
      • 2019-03-26
      • 1970-01-01
      相关资源
      最近更新 更多