Как быстро загрузить всю память процесса из подкачки (Linux)?

Как быстро загрузить всю память процесса из подкачки (Linux)?

Я запускаю несколько ресурсоемких процессов параллельно; обычно они используют несколько ГБ памяти каждый. Время от времени они также выделяют большой объем памяти (скажем, 150-250 ГБ). Обычно это делает максимум один из процессов, чтобы они уместились в доступной оперативной памяти (384 ГБ на моей машине). Однако иногда случается, что несколько из них выделяют этот большой объем одновременно, и (очевидно) все замедляется из-за подкачки.

В таких случаях я останавливаю все, кроме одного, из процессов, поглощающих память, чтобы позволить ему эффективно вычислять. Но на подкачку остановленного процесса уходит уйма времени, поскольку это означает загрузку десятков гигабайт с диска в случайном порядке. Отсюда вопрос: как заставить один процесс последовательно загрузить все ядро ​​из подкачки?

Пока что я нашел только подсказку ядра swappiness, которая (с помощью cgroups) может помешать процессу больше подкачивать, но не помогает производительности де-свопинга. Отключить весь своп, очевидно, невозможно, поскольку другие, остановленные процессы должны занимать там место.

Создание собственного мини-планировщика также не является вариантом — процессы представляют собой различные небольшие скрипты/программы на Python, а пики памяти обычно возникают при вызовах библиотек, поэтому я не могу предсказать, когда произойдет пик.


Просто для ясности: я не рассматриваю покупку терабайт оперативной памяти, в таком масштабе это слишком дорого. Размещение подкачки на массиве 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и загружает только данный процесс. Скрипт — это измененный фрагмент изэтот ответ.

Связанный контент