【问题标题】:OpenMP threads executing on the same cpu core在同一个 cpu 内核上执行的 OpenMP 线程
【发布时间】:2023-04-02 15:52:01
【问题描述】:

我目前在 4 核 phenom2 上使用 openmp 并行化程序。但是我注意到我的并行化对性能没有任何作用。自然地,我认为我错过了一些东西(错误共享、通过锁进行序列化……),但是我找不到类似的东西。此外,从 CPU 利用率来看,该程序似乎只在一个内核上执行。根据我的发现,sched_getcpu() 应该给我当前安排执行调用的线程的核心 ID。于是我写了如下测试程序:

#include <iostream>
#include <sstream>
#include <omp.h>
#include <utmpx.h>
#include <random>
int main(){
    #pragma omp parallel
    {
        std::default_random_engine rand;
        int num = 0;
    #pragma omp for
        for(size_t i = 0; i < 1000000000; ++i) num += rand();
    auto cpu = sched_getcpu();
    std::ostringstream os;
        os<<"\nThread "<<omp_get_thread_num()<<" on cpu "<<sched_getcpu()<<std::endl;
        std::cout<<os.str()<<std::flush;
    std::cout<<num;
    }
}

在我的机器上,这给出了以下输出(随机数当然会有所不同):

Thread 2 on cpu 0 num 127392776
Thread 0 on cpu 0 num 1980891664
Thread 3 on cpu 0 num 431821313
Thread 1 on cpu 0 num -1976497224

据此,我假设所有线程都在同一个内核(id 为 0 的内核)上执行。为了更加确定,我还尝试了this answer 的方法。结果哪里一样。此外,使用#pragma omp parallel num_threads(1) 并没有使执行速度变慢(实际上稍微快一点),为所有线程使用相同 cpu 的理论提供了可信度,但是 cpu 始终显示为 0 的事实让我有点怀疑.此外,我检查了最初未设置的GOMP_CPU_AFFINITY,因此我尝试将其设置为0 1 2 3,这应该将每个线程绑定到我理解的不同核心。然而,这并没有什么不同。

由于是在windows系统上开发,所以我在virtualbox中使用linux进行开发。所以我认为虚拟系统可能无法访问所有内核。但是检查virtualbox的设置显示虚拟机应该获得所有4个核心并同时执行我的测试程序4次似乎使用所有4个核心从CPU利用率判断(以及系统变得非常无响应的事实) .

所以我的问题基本上是这里到底发生了什么。更重要的是: 我是否推断所有线程都正确使用相同的内核?如果是,那么这种行为的原因可能是什么?

【问题讨论】:

  • 这是一个常见错误,您是否设置了环境变量 OMP_NUM_THREADS =4?
  • @pyCthon: OMP_NUM_THREADS 似乎没有设置,但是由于 openmp 确实创建了 4 个线程,我认为我不需要。
  • 很奇怪,我认为这可能与您的虚拟机有关,我尝试了相同的代码,甚至安装了 utmpx.h,它似乎在 8 核和 16 核机器上运行良好
  • 我在某处读到虚拟机(来宾操作系统)在您的主机操作系统内作为单个进程运行。这可能是您所看到的行为的原因吗?
  • 在我使用 Scientific Linux 6 的 2 CPU x86-64 服务器上也发生了同样的情况。看不到 IDE 或虚拟机。

标签: c++ linux openmp virtualbox


【解决方案1】:

经过一些实验,我发现问题在于我是从 Eclipse IDE 内部启动我的程序,这似乎将亲和力设置为只使用一个内核。我以为我从 IDE 外部启动时遇到了同样的问题,但重复测试表明,当从终端而不是从 ide 内部启动时,程序运行良好。

【讨论】:

【解决方案2】:

我在 Linux 上使用 g++ 4.6 编译了你的程序

g++ --std=c++0x -fopenmp test.cc -o test

不出所料,输出是:

Thread 2 on cpu 2

Thread 3 on cpu 1
910270973
Thread 1 on cpu 3
910270973
Thread 0 on cpu 0
910270973910270973

启动 4 个线程的事实(如果您没有以任何方式设置线程数,例如使用 OMP_NUM_THREADS)应该意味着程序能够看到 4 个可用的 CPU。我猜不出它为什么不使用它们,但我怀疑您的硬件/软件设置、某些环境变量或编译器选项存在问题。

【讨论】:

    【解决方案3】:

    你应该使用#pragma omp parallel for
    是的,你不需要 OMP_NUM_THREADS 是对的。 omp_set_num_threads(4); 也应该做得很好。

    【讨论】:

    • 如果我希望线程在循环之外执行操作(例如将它们的 id 写入输出),我为什么要使用 #pragma omp parallel for?正如我提到的,它默认创建 4 个线程,似乎只是在同一个核心上执行
    • 这也是真的。顺便说一句,如果你不说 omp parallel for,那么循环中不会发生并行化。但是当然你在一个并行部分,所以....我能想到的唯一其他可能的解释是你的虚拟机缺乏硬件支持。你试过用其他CPU吗? superuser.com/questions/33723/…
    • 我没有。但是,如上所述,可以使用 vbox 中的所有内核,因此似乎不太可能缺乏支持
    【解决方案4】:

    如果你在 Windows 上运行,试试这个:

    c:\windows\system32\cmd.exe /C start /affinity F path\to\your\program.exe

    /亲和 1 使用 CPU0

    /affinity 2 使用 CPU1

    /affinity 3 使用 CPU0 和 CPU1

    /affinity 4 使用 CPU2

    /affinity F 使用全部 4 个核心

    将数字转换为十六进制,然后查看右边的位是要使用的内核。

    您可以在其运行时使用任务管理器验证亲和性。

    【讨论】:

    • vbox 确实具有使用所有内核的正确亲和力(我检查过,除了它如何在我的测试中使用所有内核并多次启动我的测试程序)。因为我在 vbox 中使用 linux,所以在那里并没有真正的帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-29
    • 1970-01-01
    • 1970-01-01
    • 2017-08-22
    • 2011-05-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多