NUMA系统中使用HWLOC的realloc()函数

4

我有几个自定义分配器,它们根据不同的策略提供不同的内存分配方式。其中一个分配器在已定义的NUMA节点上分配内存。分配器的接口很直观。

template<typename config>
class NumaNodeStrategy
{

public:

    static void *allocate(const size_t sz){}

    static void *reallocate(void *old, size_t sz, size_t old_sz){}

    static void deallocate(void *p, size_t sz){}
};

使用hwloc_alloc_membind_nodeset() 方法和相关参数设置分配策略来处理分配本身。然而,hwloc仅提供内存分配和释放方法,我想知道如何实现reallocate()
两种可能的解决方案:
1.分配新内存区域并使用memcpy()复制数据。 2.使用hwloc_set_membind_nodeset()为节点集设置内存分配/绑定策略,使用普通的malloc() /posix_memalign()realloc()
有人能帮我正确理解吗?
更新: 我试图让问题更具体:是否有可能使用hwloc执行realloc()而无需分配新内存并移动页面?

直接使用libnuma怎么样?http://linux.die.net/man/3/numa - osgx
因为libnuma可能会产生错误的结果(显示错误的NUMA节点CPU绑定等),我希望使用hwloc代替。https://gist.github.com/1125022 - grundprinzip
嗯...内存绑定设置是针对节点的吗?因此,如果节点5在拥有的内存上调用realloc,那么libc的realloc会进行同一节点的内存分配吗? - osgx
3个回答

2
回复编辑的内容: hwloc中没有realloc函数,我们目前也没有计划添加。如果您确切知道您需要什么(函数的C原型),请随时在https://svn.open-mpi.org/trac/hwloc上添加一个工单。
回复ogsx的内容:内存绑定不是特定的,而是虚拟内存区域特定的,可能还与线程相关。如果您使用realloc,libc不会做任何特殊处理。 1)如果可以在同一页内进行realloc,则可以在同一节点上获得内存。很好,但对于大缓冲区来说很少见。 2)如果它在不同的页面上进行realloc(对于大缓冲区的大多数情况),则取决于malloc库过去是否已经在物理内存中分配了相应的页面(在虚拟内存中malloc并释放,但仍然在物理内存中分配)。 2.a)如果虚拟页面已被分配,则由于各种原因它可能曾经在另一个节点上分配,那么您就无法控制了。 2.b)如果新的虚拟页面尚未分配,则默认情况下将在当前节点上分配。如果您之前使用set_area_membind()或mbind()指定了绑定,则它将在正确的节点上分配。在这种情况下,您可能会感到满意。
简而言之,这取决于很多因素。如果你不想麻烦malloc库做复杂/隐藏的内部操作,尤其是当你的缓冲区很大时,使用mmap(MAP_ANONYMOUS)而不是malloc是一种简单的方法,可以确保在真正需要它们时分配页面。你甚至可以使用mremap来执行类似于realloc的操作。
alloc变成了mmap(length)+ set_area_membind realloc变成了mremap + set_area_membind(在整个mremap的缓冲区上)
我从未使用过,但看起来很有趣。

1

你错了。mbind可以移动已经被触摸过的页面。你只需要添加MPOL_MF_MOVE即可。这就是如果你添加了标志HWLOC_MEMBIND_MIGRATE,hwloc_set_area_membind_nodeset()所做的事情。

move_pages只是另一种不同的方法(更灵活但有点慢,因为你可以将独立的页面移动到不同的位置)。mbind与MPOL_MF_MOVE以及move_pages(和migrate_pages)最终都会使用mm/migrate.c中完全相同的migrate_pages()函数,一旦它们将输入转换为页面列表。


那么,grundprinzip 可以执行通常的 realloc,然后调用 hwloc_set_area_membind_nodeset() 并传入 HWLOC_MEMBIND_MIGRATE 吗? - osgx
1
或者他可以使用hwloc_alloc_membind_nodeset()在正确的内存节点上分配新缓冲区,然后手动从旧缓冲区复制到新缓冲区,最后释放旧缓冲区。无论如何都必须进行复制,因此最好在绑定最终缓冲区后再进行复制。 - Brice
我知道迁移页面是可能的,但正如问题中所述,我想在同一节点上增加分配的内存区域,并避免复制。 - grundprinzip
没有简单的方法可以在不复制的情况下增加,因此在不复制的情况下在同一节点上进行增加会更加困难。 - Brice

1

hwloc_set_area_membind_nodeset 这个函数就能解决问题,不是吗?

 HWLOC_DECLSPEC int     
  hwloc_set_area_membind_nodeset (hwloc_topology_t topology, 
    const void *addr, size_t len, hwloc_const_nodeset_t nodeset, 
    hwloc_membind_policy_t policy, int flags)

将已分配的内存地址(addr、len)与nodeset中的NUMA节点绑定。
返回: -1并设置errno为ENOSYS,如果不支持该操作 -1并设置errno为EXDEV,如果无法执行绑定
在Linux上,这个调用通过mbind实现。它仅在区域中的页面未被访问时才起作用,因此这是你第二个解决方案中移动内存区域的更正确的方式。 更新有一个MPOL_MF_MOVE*标志来移动已访问数据。
我所知道的唯一一个无需重新分配和复制即可移动页面的系统调用是move_pages

move_pages将执行进程地址空间中的一组页面移动到不同的NUMA节点。


正如您所说的,“hwloc_set_area_membind_nodeset”只允许将分配的内存移动到另一个节点,而我正在寻找类似于“libnuma”中的“numa_realloc()”。 - grundprinzip

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接