5

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

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

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

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


Просто чтобы прояснить: я не рассматриваю покупку терабайт оперативной памяти, в таком масштабе это слишком дорого. Помещение свопа в массив SSD/SSD поможет только немного (измерено), поэтому это также не решение, которое я ищу.


(частичный ответ на вопрос):

Кажется, что действительно последовательное чтение подкачки (только страницы, принадлежащие одному процессу) вряд ли возможно без взлома ядра: я измерил swapoff -a и он определенно не считал swap последовательно. И было бы логично читать его быстрее, если бы такую оптимизацию было легко осуществить.

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

0