NUMA:如何检查 C++ 数组分配在 RAM 的哪个部分?

Posted

技术标签:

【中文标题】NUMA:如何检查 C++ 数组分配在 RAM 的哪个部分?【英文标题】:NUMA: How to check in which part of RAM a C++ array is allocated? 【发布时间】:2013-11-06 13:42:29 【问题描述】:

我有一台有 2 个 CPU 和 64GB 内存的服务器,每个 CPU 32GB。

我知道每个 CPU 都有自己的 RAM 部分,我们称它们为 RAM1 和 RAM2。我想让我的程序知道它在哪个 RAM(RAM1 或 RAM2)上分配它的数据。

我试图检查指针值:

  // put the thread at i-th CPU, using pthread_setaffinity_np
TData *a = new TData[N];
...
cout << "CPU = " << i << " adress = " << a << endl; 

但输出看起来是随机的。我想那是因为地址是虚拟的。虚拟内存地址和部分RAM有对应关系吗?

如何检查我的数组“a”分配到了哪个 RAM?

【问题讨论】:

How to allocate memory in a specific place in memory (C programming)?的可能重复 可能的重复项看起来很相关,可能会解决@klm123 的问题。然而,问题是不同的。这个问题是关于如何在分配内存之后检查,这个问题是关于预先指定内存应该分配到哪里。 @perreal,我看到了这个问题并回答了它。它如何回答我的问题? @klm123,据我从答案中了解到,您尝试做的已经是默认行为。但是,如果您真的想验证本地分配,那么很抱歉投票结束。 @perreal,是的,我想知道一种方法来验证这一点,因为看起来我的内存分配有问题。我的 CPU 随机完全或部分加载。可能是原因不同,我想确定一下。 【参考方案1】:

您的问题已回答here。我只想添加一些 cmets。

请注意,调用new [] 实际上并不分配物理内存。在现代操作系统上,这只会导致开始进行匿名内存映射。匿名映射与文件系统中的文件不对应,而是由交换(如果有)支持。最初,整个区域指向内核中包含全零的只读页面。只有当你实际写入新分配的内存时,才会安装一个新的内存页面,它会替换访问地址所在的页面范围的零页面。这就是为什么我们说零页是写时复制(或 CoW)映射到进程的虚拟地址空间的原因。默认策略是尝试在同一个 NUMA 节点上分配新页面,访问内存区域的线程在该节点上运行。这称为“首次接触”NUMA 策略。如果该 NUMA 节点上没有足够的内存,则将页面分配到具有足够可用内存的其他节点上。小的分配也可能最终进入更大的区域(称为 arena),由 C 库内存分配器 malloc() 管理(C++ 运算符 new [] 调用 malloc() 以进行实际的内存分配)。在这种情况下,甚至在您写入新分配的内存之前,这些页面可能已经存在于物理内存中。

Linux 有一个讨厌的习惯,即在交换时不保留内存区域的 NUMA 关联。也就是说,如果在 NUMA 节点 0 上分配了一个页面,然后换出然后又换回,则不能保证该页面不会被放置在 NUMA 节点 1 上。这就产生了“我的内存分配在哪里”的问题有点棘手,因为连续换出然后换入很容易使您在几分之一秒前从move_pages() 获得的结果无效。因此,这个问题只在以下两种特殊情况下才有意义:

显式锁定内存区域:可以使用mlock(2) 系统调用来告诉操作系统不要从进程虚拟地址空间交换特定范围; 您的系统没有活动的交换区:这完全阻止了操作系统将页面移出和移回主内存。

【讨论】:

谢谢!使用您的链接我得到“致命错误:numaif.h:没有这样的文件或目录”。你知道出了什么问题吗? 好的。我得到了它。 头文件不包含在 glibc 中,但需要安装 libnuma-devel 或类似的包。【参考方案2】:

内存是通过 MMU 虚拟化的,因此每个进程看到的内存空间大小等于 2^64。在这个过程中,地址是虚拟的,所以它们是没有意义的。在进程级别,虚拟地址(应用程序看到的)和物理地址(在 RAM 上)之间没有任何对应关系。

您的应用程序应查询操作系统以了解当前正在使用的物理地址。

【讨论】:

给定应用程序的 PID(可以通过在 C++ 代码中运行 getpid() 获得),/proc/PID 中应该有一些条目/。它可能是 /proc/PID/map 我的应用程序在两个 cpu 上运行。 /proc/PID/maps 不会公开任何与 NUMA 相关的信息。 /proc/PID/numa_maps 是公开的,但它只告诉每个映射在每个 NUMA 节点上分配了多少页。无法从/proc 获得所需信息。 只是说清楚:如果数组足够大,它会得到自己的映射,然后可以解析/proc/self/numa_maps,找到映射并找出每个分配了多少页NUMA 节点。如果数组嵌入在预先存在的映射中,则无法判断/proc/PID/numa_maps 中列出的页面中有多少与数组占用的子范围相关。另一个问题是,即使是新的映射有时也会与先前存在的映射合并,因此会出现第二种情况。

以上是关于NUMA:如何检查 C++ 数组分配在 RAM 的哪个部分?的主要内容,如果未能解决你的问题,请参考以下文章

如何在特定的 NUMA 内存节点上实例化 C++ 对象?

DPDK预分配了多少虚拟内存

NUMA 会影响内存带宽,还是只是延迟?

在 NUMA 中,每个 CPU 是不是也有类似于本地 RAM 的本地 I/O 控制器?

如何将所有内存分配限制到一个 NUMA 节点

在 linux(CentOS)/多处理器设置中,如何将 CPU 内核分配给 NUMA 节点?