我可以访问由两个NUMA节点组成的双路系统来进行一些数据处理。
我的代码相对简单,我正在将openMP用于主要的可并行循环,如下所示( k 是一个函数参数,而 buffer 是几千兆字节长度为 n 的数组):
uint64_t m=0;
uint64_t *rk = (uint64_t *) calloc(k, sizeof(uint64_t));
#pragma omp parallel
{
#pragma omp for reduction(+:m), reduction(+:rk[:k])
for (uint64_t i=0; i<n-k; i++)
{
m += (uint64_t)buffer[i];
for (uint64_t j=0; j<k; j++)
{
rk[j] += (uint64_t)buffer[i]*(uint64_t)buffer[i+j];
}
}
/* Other stuff, serial and parallel */
}
在Linux Mint下,我可以毫无问题地使用gcc进行编译,并且两个插槽上的所有内核都得到了很好的利用。但是,在Windows上(cygwin上为Mingw-gcc),仅使用单个NUMA节点。由于我的代码对内存延迟并不十分敏感,因此在Windows上我的速度下降了2倍。
我不知道如何强制Windows在两个节点上分布线程。据我了解,openMP不支持Windows上的亲和力(无论如何都是cygwin mingw-gcc实现),但我不知道我应该如何手动进行。
非常感谢您的帮助!
答案 0 :(得分:1)
我找到了问题的原因。计算机上有超过64个逻辑核心,因此Windows需要两个CPU组来对其进行寻址。默认情况下,它将每个NUMA节点放在自己的组中。
如果您的物理内核少于64个,则修复程序是禁用HTT,或者在BIOS中禁用NUMA分组。在后一种情况下,前64个逻辑核心将被分组,并在Windows中显示为单个NUMA节点,其余部分放置在第二个节点中。理想的解决方案取决于您的特定应用程序,无论您是受益于使用所有内核还是受益于超线程。
[编辑]
您也可以手动管理线程。如果您想这样做,建议您深入研究Processtopologyapi.h
和processthreadsapi.h
,尤其是功能GetActiveProcessorCount
和SetThreadGroupAffinity
。