0

在这个应用程序中,我有一组 N (POSIX) 线程。第一组开始,创建一个对象 A,然后结束。稍后,一个具有 N 个线程的新组启动,使用 A 创建一个类似的对象 B,然后结束。这种模式是重复的。该应用程序是高度内存密集型的(A 和 B 有大量 malloc'ed 数组)。我希望尽可能地在本地访问内存。我可以用它numactl --localalloc来实现这一点,但为了让它工作,我还需要确保第一组和第二组中处理相同数据的线程绑定到同一个 NUMA 节点。我已经研究过sched_setaffinity,但想知道是否存在更好的方法。

应用程序的逻辑使得没有单独线程组的解决方案会破坏程序逻辑。也就是说,单组线程管理第一个对象 A 和后来的对象 B(中间没有结束)的解决方案将是非常人为的,并且会消除代码的面向对象布局。

4

1 回答 1

1

将 B 组中的线程绑定到它们在 A 组上运行的相同核心比您需要的限制更多。现代处理器为每个内核使用专用的 1 级缓存 (L1) 和 2 级缓存 (L2),因此将线程绑定到特定内核仅对获取这些缓存中仍然“热”的数据才有意义。您可能的意思是将 B 组线程绑定到与 A 组中的线程相同的 numa 节点,以便大型数组位于同一本地内存中。

也就是说,您有两个选择:

  1. 您将组 A 的亲和性设置为特定的 numa 节点,并使用同一个 numa 节点来设置组 B 的亲和性,或者
  2. 您找出您的 malloc 数组位于哪个 numa 节点,然后将组 B 的亲和性设置为该 numa 节点。

方案(1)比较简单,下面说说方案(2)如何实现。

以下 SO 答案描述了如何在给定进程中的虚拟地址的情况下找出哪个 numa 节点具有本地内存:

我可以从指针地址(在 Linux 上的 C 中)获取 NUMA 节点吗?

-lnuma 中有一个 move_pages 函数:http://linux.die.net/man/2/move_pages可以将地址(页面)的当前状态报告给节点映射:

nodes 也可以为 NULL,在这种情况下 move_pages() 不会移动任何页面,而是会在状态数组中返回每个页面当前所在的节点。可能需要获取每个页面的状态以确定需要移动的页面。

有了这些信息,您希望将 B 组线程的亲和性设置为该 numa 节点,如何做到这一点,我们去这个 SO 答案

如何确保在多核中创建 std::thread?

对于具有 POSIX 线程的 GNU/linux,您将需要 pthread_setaffinity_np()、FreeBSD cpuset_setaffinity()、Windows SetThreadAffinityMask() 等。

于 2014-04-04T16:28:59.067 回答