OpenMp 不使用所有 CPU(双插槽,windows 和 Microsoft visual studio)
OpenMp doesn't utilize all CPUs(dual socket, windows and Microsoft visual studio)
我有一个双插槽系统,每个 CPU 有 22 个真正的核心或每个 CPU 有 44 个超线程。我可以让 openMP 完全利用第一个 CPU(22 cores/44 hyper) 但我无法让它利用第二个 CPU。
我正在使用 CPUID HWMonitor 检查我的核心使用情况。第二个 CPU 在所有核心上始终处于或接近 0%。
使用:
int nProcessors = omp_get_max_threads();
让我 nProcessors = 44,但我认为它只是使用 1 CPU 的 44 个超线程而不是 44 个真正的核心(应该是 88 个超线程)
看了很多之后,我不确定如何利用另一个 CPU。
我的 CPU 运行 尽我所能 运行 其他并行处理程序可以利用所有这些程序。
我正在用 64 位编译它,但我认为这不重要。另外,我使用的是 Visual studio 2017 Professional 版本 15.2。打开 MP 2.0(只有一个 vs 支持)。 运行 windows 10 Pro,64 位,配备 2 个 Intel Xeon E5-2699v4 @ 2.2Ghz 处理器。
因此,感谢@AlexG 提供了一些见解,从而回答了我自己的问题。请参阅问题的评论部分。
这是 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 个线程。原因似乎是 linked 到 Visual Studio 的 OpenMP 实现不允许超过 64 个 OpenMP线程。这是 link 更多 information
感谢大家帮助收集更多有助于最终回答的花絮!
我有一个双插槽系统,每个 CPU 有 22 个真正的核心或每个 CPU 有 44 个超线程。我可以让 openMP 完全利用第一个 CPU(22 cores/44 hyper) 但我无法让它利用第二个 CPU。
我正在使用 CPUID HWMonitor 检查我的核心使用情况。第二个 CPU 在所有核心上始终处于或接近 0%。
使用:
int nProcessors = omp_get_max_threads();
让我 nProcessors = 44,但我认为它只是使用 1 CPU 的 44 个超线程而不是 44 个真正的核心(应该是 88 个超线程)
看了很多之后,我不确定如何利用另一个 CPU。
我的 CPU 运行 尽我所能 运行 其他并行处理程序可以利用所有这些程序。
我正在用 64 位编译它,但我认为这不重要。另外,我使用的是 Visual studio 2017 Professional 版本 15.2。打开 MP 2.0(只有一个 vs 支持)。 运行 windows 10 Pro,64 位,配备 2 个 Intel Xeon E5-2699v4 @ 2.2Ghz 处理器。
因此,感谢@AlexG 提供了一些见解,从而回答了我自己的问题。请参阅问题的评论部分。
这是 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 个线程。原因似乎是 linked 到 Visual Studio 的 OpenMP 实现不允许超过 64 个 OpenMP线程。这是 link 更多 information
感谢大家帮助收集更多有助于最终回答的花絮!