/interleave_mem

交织内存内核模块

Primary LanguageC

交织内存内核模块

当把NVM当作廉价低速内存使用时,我们希望NVM代替一部分DRAM,在(可能)降低性能的同时降低成本,以期找到最佳平衡点。

如果不同内存区域有明显的、较为稳定的冷热区分,那么使用动态的监测、迁移是使用混合内存系统最好的方案。但是,如果我可以断定该业务占用的内存没有明显的、稳定的冷热区分,那么监测和迁移反而会引入额外的开销和颠簸。这种情况下,固定式的内存交织可能是最佳的方案(即以不变应万变)。

该项目提供了这样的解决方案。通过

make
insmod interleave_mem.ko

即可产生内核模块interleave_mem.ko并插入内核中,并且产生/dev/interleave_mem的字符设备接口。事实上,这是一个虚拟设备。

应用程序只需要使用mmap()映射该设备,即可获得一段指定大小的“交织内存区域”。所谓“交织内存区域”,意思是该区域中的内存按页的粒度、用不同NUMA节点的内存页交织构成“。而交织的方式可以由用户的”pattern“指定。

使用一段简单的代码演示:

#include <fcntl.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>

int main() {
    int fd = open("/dev/interleave_mem", O_RDWR);
    assert(fd > 0);
    ssize_t len = write(fd, "\x00\x02\x02", 3);
    assert(len == 3);
    size_t size = 1UL << 30;
    void* ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
                        MAP_SHARED, fd, 0);
    assert(ptr != MAP_FAILED);
    memset(ptr, 0, size);
    return 0;
}

代码中,打开了/dev/interleave_mem设备,并通过write()告知该虚拟设备说,按照"022"的pattern(我更喜欢称之为”图案“)交织内存。之后,使用mmap()从/dev/interleave_mem获取了一段1GB的空间,然后使用memset()写这段空间。怎么理解”022“的图案呢?对于这1GB中的任一内存页,如果其绝对虚拟页框号(= 页首地址 / 页大小),除以3之后余数是0,那么该页来自NUMA节点0,否则来自NUMA节点2。又比如说,指定了”000112“的图案,那么这段内存空间的页如下图所示:

000112000112000112000112......000112

每一个数字就是每一个页所在的NUMA节点。换言之,在该段空间中,不断重复着这个”图案“。

有了这个模块,用户就能构建一段按照任一”图案“交织的混合内存。注意,”图案“是一个高于”比例“的概念。比如同样是Node 0和Node 1按照1:2的比例交织,我可以是”022022022...“,也可以是”002222002222...“,甚至是”020222020222...“。这样,才能验证不同的交织方案对于性能是否有影响。

那么numactl不是也可以提供交织内存吗?问题在于,numactl可以指定节点0和节点1交织,但是各个节点权重都是一样的,这就没法控制任一比例,也就没法找到最佳平衡点。