我正在尝试了解numa(3)
Linux 上的库。
我分配了一个大数组(许多 GB 的内存)。在随机 NUMA 节点上运行的线程写入它,因为这样的页面在随机 NUMA 内存节点上出现故障(默认 NUMA 策略)。
在线程计算结束时,我有一个单线程作业来总结结果。为此,我首先压缩数组,删除大量元素,然后将剩余部分移动到主线程的 NUMA 节点。
系统move_pages
调用不适合这项工作,因为它需要每个页面的数组条目 - 开销太大。
文档不清楚是否可以强制numa_tonode_memory
移动故障内存。
所以我看到的唯一方法是使用mbind
with 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
什么?