如何在 C++ 程序中通过拓扑考虑在多核 HT 上实现亲和性?
Posted
技术标签:
【中文标题】如何在 C++ 程序中通过拓扑考虑在多核 HT 上实现亲和性?【英文标题】:How to implement affinity on multi-core HT with topological considerations in a C++ program? 【发布时间】:2011-10-18 17:54:50 【问题描述】:我正在开发一些具有可变线程数的 C++ 多核程序,我想知道如何设置适当的(实际上是“最佳”)亲和力。我使用 Boost-threads,所以我可以调用 get_hardware_concurrency() 来了解有多少逻辑内核。到目前为止,我写了一个映射“第 n 个线程到第 n 个逻辑核心”,但这并不是最聪明的事情,因为多插槽处理器和超线程。我的程第 2 个物理上的第 1 个逻辑,...,第 n 个物理上的第 1 个逻辑,第 1 个物理上的第 2 个逻辑等等。
我发现了很多关于如何发现是否启用 HT (CPUID) 以及如何确定逻辑和物理内核 PER 包的内容。我知道我必须处理一些汇编代码,这并不吓到我,但我真的不知道如何了解有关逻辑核心、物理核心和包的完整信息以及操作系统如何处理所有这些信息。
尽可能简洁:我如何知道操作系统(Windows 和 Linux)称为第 N 个线程的确切位置(物理内核和包)?
【问题讨论】:
【参考方案1】:这是一段代码 sn-p,它将为您提供 Linux 上的 CPU 拓扑结构。
#!/bin/bash
function filter
cat /proc/cpuinfo | grep -E "$1.*: [0-9]*" | sed -e 's/^.*: //g'
CPU_ID=`filter processor`
SOCKET_ID=(`filter 'physical id'`)
CORE_ID=(`filter 'core id'`)
for cpu_id in $CPU_ID; do
echo "cpu $cpu_id: socket$SOCKET_ID[$cpu_id]_core$CORE_ID[$cpu_id]"
done
如果我在启用了 HT 的核心 i7 上运行它,我会得到以下输出:
cpu 0: socket0_core0
cpu 1: socket0_core1
cpu 2: socket0_core2
cpu 3: socket0_core3
cpu 4: socket0_core0
cpu 5: socket0_core1
cpu 6: socket0_core2
cpu 7: socket0_core3
在这里你可以看到cpu 0和4在同一个核心上,即核心0上的HT线程。
将它与 sched_setaffinity 或 pthread_setaffinity_np(3) 结合使用将允许您将进程映射到一组 CPU。您也可以使用taskset(1),无需任何代码行。
【讨论】:
谢谢,这会很有帮助。但是,要在 C++ 程序中使用此代码,我想我应该从 system() 指令中调用它。我可以避免吗?顺便说一句,它比使用 asm、cpuid 和所有那些汇编的东西要好得多! 我不会用系统调用它。我的建议是,在 shell 脚本中创建一个包装器,首先找到 cpu 拓扑,然后将其作为参数传递给您的程序。【参考方案2】:对于 Windows:GetLogicalProcessorInformation 和 SetThreadAffinityMask
还有GetCurrentProcessorNumber()
,但是当您不将它们固定到特定 CPU 时,操作系统会频繁交换线程,因此这对您自己的目的没有帮助。
【讨论】:
+ 在GetLogicalProcessorInformation
之上的即用型工具:alax.info/blog/1188 显示配置。【参考方案3】:
在linux上,看看man pages for sched_setaffinity
【讨论】:
【参考方案4】:LIKWID 工具套件可以方便地处理多核环境中的拓扑和亲和性问题。除其他外,它还包含用于确定拓扑、将线程固定到内核以及测量硬件性能指标的工具:
http://code.google.com/p/likwid
只要代码中的线程机制是基于pthreads并且应用程序是动态链接的,likwid-pin就可以在不改变源代码的情况下将线程绑定到资源。
【讨论】:
以上是关于如何在 C++ 程序中通过拓扑考虑在多核 HT 上实现亲和性?的主要内容,如果未能解决你的问题,请参考以下文章