2

我正在尝试了解numa(3)Linux 上的库。

我分配了一个大数组(许多 GB 的内存)。在随机 NUMA 节点上运行的线程写入它,因为这样的页面在随机 NUMA 内存节点上出现故障(默认 NUMA 策略)。

在线程计算结束时,我有一个单线程作业来总结结果。为此,我首先压缩数组,删除大量元素,然后将剩余部分移动到主线程的 NUMA 节点。

系统move_pages调用不适合这项工作,因为它需要每个页面的数组条目 - 开销太大。

文档不清楚是否可以强制numa_tonode_memory移动故障内存。

所以我看到的唯一方法是使用mbindwith 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什么?

4

0 回答 0