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:没有这样的文件或目录”。你知道出了什么问题吗? 好的。我得到了它。内存是通过 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 的哪个部分?的主要内容,如果未能解决你的问题,请参考以下文章