OpenMp 不使用所有 CPU(双插槽、Windows 和 Microsoft Visual Studio)

Posted

技术标签:

【中文标题】OpenMp 不使用所有 CPU(双插槽、Windows 和 Microsoft Visual Studio)【英文标题】:OpenMp doesn't utilize all CPUs(dual socket, windows and Microsoft visual studio) 【发布时间】:2019-04-19 18:37:52 【问题描述】:

我有一个双插槽系统,每个 CPU 有 22 个真实内核或每个 CPU 有 44 个超线程。我可以让 openMP 完全利用第一个 CPU(22 核/44 超),但我不能让它利用第二个 CPU。

我正在使用 CPUID HWMonitor 检查我的核心使用情况。第二个 CPU 在所有内核上始终处于或接近 0%。

使用:

int nProcessors = omp_get_max_threads();

得到我 nProcessors = 44,但我认为它只是使用 1 个 CPU 的 44 个超线程而不是 44 个真正的内核(应该是 88 个超线程)

看了很多遍,不知道如何利用其他CPU。

我的 CPU 运行良好,因为我可以运行使用所有 CPU 的其他并行处理程序。

我正在用 64 位编译它,但我认为这并不重要。另外,我使用的是 Visual Studio 2017 Professional 15.2 版。打开 MP 2.0(只有一个 vs 支持)。在 64 位 Windows 10 Pro 上运行,配备 2 个 Intel Xeon E5-2699v4 @ 2.2Ghz 处理器。

【问题讨论】:

提及您使用的操作系统以及您使用的编译器和 OpenMP 版本/实现可能会有所帮助。 您可以使用omp_set_num_threadsomp_set_dynamic(false) 强制线程数禁用动态团队。我不确定它在 2-socket 设置上的表现如何。或许this read 能给出一点答案? 您可以设置线程数,它的表现很好,线程的分配方式取决于操作系统。操作系统可能会尝试将它们全部保留在同一个 CPU 上以确保更快的内存访问,我真的不知道 Windows 在多插槽计算机上的行为(或者哪些版本甚至支持它 - 我假设并非所有人都支持)。 @AlexG:我将 num_threads 设置为 44 和 88(以防万一它认为超线程是一个线程?) omp_set_dynamic 为 false,但它仍然没有使用其他 CPU。你提到的帖子是由于一个 linux 内核错误,这与 Qubit 可能提到的 Windows 如何处理事情有关。这就是为什么我不知道我还能做些什么来帮助解决问题。我现在应该将 44 个线程作为最大线程返回吗?还是应该是88?我不确定。 @Marvg 您可能想阅读this 和this。不确定 OMP_PLACES 出现在哪个版本中(我认为是 OpenMP 4.0),但它似乎与您的情况有关。 【参考方案1】:

感谢@AlexG 提供了一些见解来回答我自己的问题。请参阅问题的 cmets 部分。

这是 Microsoft Visual Studio 和 Windows 的问题。

先读Processor Groups for Windows。

基本上,如果您有 64 个以下的逻辑核心,这将不是问题。但是,一旦您克服了这一点,您现在将为每个套接字(或 Windows 这样选择的其他组织)拥有两个进程组。在我的例子中,每个进程组有 44 个超线程并代表一个物理 CPU 插槽,而我正好有两个进程组。默认情况下,每个进程(程序)只能访问一个进程组,因此我最初只能在一个内核上使用 44 个线程。但是,如果您手动创建线程并使用 SetThreadGroupAffinity 将线程的处理器组设置为与程序最初分配的组不同的组,那么您的程序现在将成为多处理器组。这似乎是启用多处理器的一种迂回方式,但是的,这就是如何做到这一点。一旦开始设置每个线程的单独进程组,调用 GetProcessGroupAffinity 将显示组数大于 1。

我能够像这样创建一个开放的 MP 块,并通过并分配进程组:

...

#pragma omp parallel num_threads( 88 )

    HANDLE thread = GetCurrentThread();

    if (omp_get_thread_num() > 32)
    
        // Reserved has to be zero'd out after each use if reusing structure...
        GroupAffinity1.Reserved[0] = 0;
        GroupAffinity1.Reserved[1] = 0;
        GroupAffinity1.Reserved[2] = 0;
        GroupAffinity1.Group = 0;
        GroupAffinity1.Mask = 1 << (omp_get_thread_num()%32);
        if (SetThreadGroupAffinity(thread, &GroupAffinity1, &previousAffinity))
        
            sprintf(buf, "Thread set to group 0: %d\n", omp_get_thread_num());
            OutputDebugString(buf);
        
    
    else
    
        // Reserved has to be zero'd out after each use if reusing structure...
        GroupAffinity2.Reserved[0] = 0;
        GroupAffinity2.Reserved[1] = 0;
        GroupAffinity2.Reserved[2] = 0;
        GroupAffinity2.Group = 1;
        GroupAffinity2.Mask = 1 << (omp_get_thread_num() % 32);
        if (SetThreadGroupAffinity(thread, &GroupAffinity2, &previousAffinity))
        
            sprintf(buf, "Thread set to group 1: %d\n", omp_get_thread_num());
            OutputDebugString(buf);
        
    

所以使用上面的代码,我能够强制运行 64 个线程,每个套接字 32 个线程。现在,即使我尝试将 omp_set_num_threads 强制设置为 88,我也无法超过 64 个线程。原因似乎与 Visual Studio 的 OpenMP 实现不允许超过 64 个 OpenMP 线程有关。这是一个关于更多的链接information

感谢大家帮助收集更多有助于最终回答的花絮!

【讨论】:

很高兴你能找到一些东西。如果您真的需要性能,您可能还想在没有超线程的情况下进行一些测试。在最好的情况下,它会带来 15% 的性能提升,但如果你在处理数字,它可能会减慢你的速度。

以上是关于OpenMp 不使用所有 CPU(双插槽、Windows 和 Microsoft Visual Studio)的主要内容,如果未能解决你的问题,请参考以下文章

双插槽与单插槽内存模型?

共享内存的 MPI 与 openMP

单核CPU使用openmp,会大幅度提高计算性能吗?

C++ openmp并行程序在多核linux上如何最大化使用cpu

OpenMP、VTune、空闲线程

物理CPU 逻辑CPU 核数