我试图了解Linux上的numa(3)
库。
我分配了一个大型数组(许多GB内存)。在随机NUMA节点上运行的线程写入它,因为这些页面在随机NUMA内存节点上出现故障(默认NUMA策略)。
在线程计算结束时,我有一个单线程作业来总结结果。为此,我首先压缩数组,删除大量元素,然后将剩余部分移动到主线程的NUMA节点。
move_pages
系统调用不适合作业,因为它需要每个页面的数组条目 - 开销太大。
文档不清楚是否可以强制numa_tonode_memory
移动故障内存。
所以,我看到的唯一方法是将mbind
与MPOL_MF_MOVE
一起使用,但我无法理解创建一个正确的nodemask
参数(或其他内容失败) 。就我而言:
#define _GNU_SOURCE
#include <stdlib.h>
#include <sched.h>
#include <numa.h>
#include <numaif.h>
int master_node;
nodemask_t master_nodemask;
// initializer
// has to be called from master/main thread
void numa_lock_master_thread() {
int curcpu = sched_getcpu();
if (curcpu >= 0) {
// master_node = numa_node_of_cpu(curcpu);
numa_run_on_node(master_node = numa_node_of_cpu(curcpu));
if (master_node >= 0) {
struct bitmask * bindmask = numa_bitmask_alloc(numa_num_possible_nodes());
numa_bitmask_clearall(bindmask);
numa_bitmask_setbit(bindmask, master_node);
copy_bitmask_to_nodemask(bindmask, &master_nodemask);
numa_bitmask_free(bindmask);
}
} else { // has never failed before
perror("sched_getcpu");
}
}
static inline void numa_migrate_pages_to_master_node(void * addr, unsigned long len) {
if (master_node < 0)
return;
if ( mbind( addr
, len
, MPOL_BIND
, master_nodemask.n
, numa_max_node()
, MPOL_MF_MOVE)) {
perror("mbind");
}
}
来自/usr/include/numa.h
:
typedef struct {
unsigned long n[NUMA_NUM_NODES/(sizeof(unsigned long)*8)];
} nodemask_t;
有时我得到mbind: Bad address
,有时调用会成功,但后续的内存访问会产生SIGSEGV
。
addr
始终是
mmap(NULL, (num_pages) * sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | (flags), -1, 0);
和len
是页面对齐的。
如何使用尽可能少的系统调用来完成此工作,并且没有move_pages
带来的大量开销?
为nodemask
设置mbind
参数的正确方法是什么?