使用numa_alloc_onnode()分配小块是否有限制?

Ale*_*tov 5 c++ linux memory-management numa

我正在具有4个运行centOS的Operton 6272处理器的计算机上进行NUMA实验。有8个NUMA节点,每个节点都有16GB内存。

这是我正在运行的一个小型测试程序。

void pin_to_core(size_t core)
{
    cpu_set_t cpuset;
    CPU_ZERO(&cpuset);
    CPU_SET(core, &cpuset);
    pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
}

int main()
{
    pin_to_core( 0 );

    size_t bufSize = 100;
    for( int i = 0; i < 131000; ++i )
    {
        if( !(i % 10) )
        {
            std::cout << i << std::endl;
            long long free = 0;
            for( unsigned j = 0; j < 8; ++j )
            {
                numa_node_size64( j, &free );
                std::cout << "Free on node " << j << ": " << free << std::endl;
            }
        }

        char* buf = (char*)numa_alloc_onnode( bufSize, 5 );
        for( unsigned j = 0; j < bufSize; ++j )
            buf[j] = j;
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

因此,基本上,在#0核心上运行的线程在NUMA节点5上分配了131K 100字节缓冲区,并用垃圾将其初始化并泄漏。每10次迭代一次,我们就会输出有关每个NUMA节点上可用内存量的信息。

在输出的开头,我得到:

0
Free on node 0: 16115879936
Free on node 1: 16667398144
Free on node 2: 16730402816
Free on node 3: 16529108992
Free on node 4: 16624508928
Free on node 5: 16361529344
Free on node 6: 16747118592
Free on node 7: 16631336960
...
Run Code Online (Sandbox Code Playgroud)

最后,我得到:

Free on node 0: 15826657280
Free on node 1: 16667123712
Free on node 2: 16731033600
Free on node 3: 16529358848
Free on node 4: 16624885760
Free on node 5: 16093630464
Free on node 6: 16747384832
Free on node 7: 16631332864
130970
Free on node 0: 15826657280
Free on node 1: 16667123712
Free on node 2: 16731033600
Free on node 3: 16529358848
Free on node 4: 16624885760
Free on node 5: 16093630464
Free on node 6: 16747384832
Free on node 7: 16631332864
mbind: Cannot allocate memory
mbind: Cannot allocate memory
mbind: Cannot allocate memory
mbind: Cannot allocate memory
mbind: Cannot allocate memory
mbind: Cannot allocate memory
mbind: Cannot allocate memory
130980
...
Run Code Online (Sandbox Code Playgroud)

我不清楚的事情:

1)为什么会有那些“ mbind:无法分配内存”消息?如果我将缓冲区大小更改为例如1000,我将不会耗尽所有内存,并且行为不会改变,这一事实使我认为我已经用尽了某种内核资源句柄。

2)即使我要求在节点5上分配内存,实际分配似乎还是在节点0和5之间进行了分配。

任何人都可以对发生这种情况的原因提供任何见解吗?

更新

想提供关于点(2)的更多细节。某些内存未在节点5上分配的事实似乎与我们正在初始化核心#0(属于NUMA节点0)上的缓冲区有关。如果更改pin_to_core(0)为,pin_to_core(8)则分配的内存将在节点1和5之间分配。如果是,pin_to_core(40)则所有内存都将在节点5上分配。

更新2

我查看了libnuma的源代​​码,并尝试numa_alloc_onnode()使用那里的更多低级调用替换对的调用:mmap()mbind()。我现在还检查内存驻留在哪个NUMA节点上-我使用该move_pages()调用。结果如下。在初始化之前(循环结束j),页面未映射到任何节点(我得到ENOENT错误代码),并且在初始化之后,页面被分配给了节点0或节点5。该模式是常规的:5,0,5,0 ,...和以前一样,当我们接近第131000次迭代时,mbind()开始返回错误代码,并且发生这种情况时,该页面总是分配给节点0。mbind返回的错误代码是ENOMEM,文档说这意味着“内核内存”用完了。我不知道它是什么,但是它不能是“物理”内存,因为每个节点有16GB。

到目前为止,这是我的结论:

  1. mbind()当另一个NUMA节点的核心首先接触内存时,由施加的对内存映射的限制仅保留50%的时间。我希望这是在某个地方记录下来的,因为悄悄地兑现诺言是不好的……

  2. 拨打电话的数量受到限制mbind。因此,应该尽可能地使用mbind()大内存块。

我要尝试的方法是:在固定到特定NUMA ndoes核心的线程上执行内存分配任务。为了让您更加省心,我将尝试致电mlock(因为此处描述的问题)。

zak*_*kak 2

对于你的第一个问题,来自手册页numa_alloc_onnode

The size argument will be rounded up to a multiple of the system page size.
Run Code Online (Sandbox Code Playgroud)

这意味着虽然您请求少量数据,但您获得的是整个页面。也就是说,在您的程序中,您实际上请求了 131000 个系统页面。

对于第二个问题,我建议如果无法在给定节点上分配页面,则使用numa_set_strict()强制失败。numa_alloc_onnode

numa_set_strict() sets a flag that says whether the functions  allocating
   on specific nodes should use use a strict policy. Strict means the
   allocation will fail if the memory cannot be allocated  on  the  target
   node.   Default operation is to fall back to other nodes.  This doesn't
   apply to interleave and default.
Run Code Online (Sandbox Code Playgroud)