我並行運行一堆 CPU 密集型流程;它們通常各自使用幾 GB 記憶體。有時他們也會分配大量記憶體(例如 150-250GB)。通常最多有一個進程會這樣做,因此它們適合可用的 RAM(我的機器上為 384GB)。然而,有時會發生更多的人同時分配這麼大的數量,並且(顯然)一切都會因為交換而變慢。
在這種情況下,我會停止除一個佔用記憶體的進程之外的所有進程,以使其能夠有效地進行計算。但換入已停止的進程需要很長時間,因為這意味著以隨機存取模式從磁碟加載數十GB。因此問題是:如何強制單一進程從交換中順序載入整個核心?
到目前為止,我只發現了一個 swappiness 核心提示,它(在 cgroups 的幫助下)可以阻止進程進行更多交換,但對去交換的效能沒有幫助。關閉所有交換顯然是不可能的,因為其他停止的程序必須佔用那裡的空間。
建立我自己的迷你調度程序也不是一個選擇 - 這些進程是 python 中的各種小腳本/程序,內存峰值通常發生在庫調用中,所以我無法預測峰值何時會發生。
只是為了澄清:我不考慮購買 TB 的 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
僅載入給定進程。腳本是修改後的片段這個答案。