如何快速从交换中加载整个进程内存(linux)?

如何快速从交换中加载整个进程内存(linux)?

我同时运行了一堆 CPU 密集型进程;它们通常每个都使用几 GB 的内存。有时它们也会分配大量内存(比如 150-250GB)。通常最多只有一个进程这样做,所以它们适合可用的 RAM(我的机器上是 384GB)。然而,有时会发生更多进程同时分配这么大的内存,(显然)一切都会因为交换而变慢。

在这种情况下,我会停止所有占用大量内存的进程,只留下一个,以便让它有效地计算。但是,换入一个停止的进程需要很长时间,因为这意味着以随机访问模式从磁盘加载数十 GB 的数据。因此,问题是:我如何强制单个进程按顺序从交换中加载整个核心?

到目前为止,我只发现了一个 swappiness 内核提示,它(在 cgroups 的帮助下)可以阻止进程进行更多交换,但对取消交换的性能没有帮助。关闭所有交换显然是不可能的,因为其他已停止的进程必须占用那里的空间。

构建我自己的小型调度程序也不是一种选择——这些进程是 python 中的各种小脚本/程序,并且内存峰值通常发生在库调用中,所以我无法预测何时会出现峰值。


需要说明的是:我不考虑购买 TB 级的 RAM,这种规模的 RAM 太贵了。将交换放在 SSD/SSD 阵列上只会有一点帮助(已测量),所以这也不是我想要的解决方案。


(部分自答):

看来,如果不对内核进行黑客攻击,几乎不可能真正顺序读取交换(仅读取属于单个进程的页面):我测量过swapoff -a,它肯定没有顺序读取交换。如果这种优化很容易实现,那么更快地读取它是合乎逻辑的。

/proc/[pid]/mem目前我最好的方法是使用下面的脚本(必须以 root 身份运行)通过伪文件读取整个进程内存:

#!/usr/bin/python2
import re
import sys
pid=str(sys.argv[1]) # process pid given by the first arg

print(pid) # just to aviod mistakes

CHUNKSIZE=10485760  # single read() invocation block size

total=0
maps_file = open("/proc/"+pid+"/maps", 'r')
mem_file = open("/proc/"+pid+"/mem", 'r', 0)
for line in maps_file.readlines():  # for each mapped region
    m = re.match(r'([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r])', line)
    if m.group(3) == 'r':  # if this is a readable region
        start = int(m.group(1), 16)
        end = int(m.group(2), 16)
        mem_file.seek(start)  # seek to region start
        togo = end-start # number of bytes to read
        while togo > CHUNKSIZE: # read sequential memory from region one block at the moment
            mem_file.read(CHUNKSIZE) 
            togo -= CHUNKSIZE
            total += CHUNKSIZE
            print(total/1048576) # be verbose, print megabytes read so far
        mem_file.read(togo) # read remaining region contents
        total+=togo # dump contents to standard output
        print(total/1048576) # be verbose...
maps_file.close()
mem_file.close()

它恰好在内存的最后几个字节处失败,但通常具有与给定进程相同的性能,swapoff并且仅加载给定进程。脚本是修改后的片段这个答案

相关内容