Como carregar toda a memória do processo do swap rapidamente (linux)?

Como carregar toda a memória do processo do swap rapidamente (linux)?

Eu executo vários processos que consomem muita CPU em paralelo; eles normalmente usam alguns GB de memória cada. De tempos em tempos, eles também alocam grande quantidade de memória (digamos 150-250 GB). Normalmente, no máximo um dos processos faz isso, então eles cabem na RAM disponível (384GB na minha máquina). No entanto, às vezes acontece que mais deles alocam essa grande quantia ao mesmo tempo e (obviamente) tudo fica mais lento por causa da troca.

Nesses casos, paro todos os processos que consomem muita memória, exceto um, para permitir que ele seja computado de maneira eficaz. Mas leva muito tempo para trocar um processo interrompido, pois isso significa carregar dezenas de gigabytes do disco em padrão de acesso aleatório. Portanto, a questão é: como posso forçar um único processo a carregar sequencialmente todo o núcleo do swap?

Até agora, encontrei apenas uma dica de kernel de troca, que (com a ajuda de cgroups) pode impedir que um processo troque mais, mas não ajuda no desempenho da troca. Obviamente, desligar toda a troca não é possível, pois os outros processos interrompidos precisam ocupar espaço lá.

Construir meu próprio mini-agendador também não é uma opção - os processos são vários pequenos scripts/programas em python e os picos de memória geralmente acontecem em chamadas de biblioteca, portanto, não posso prever quando ocorrerá um pico.


Só para deixar claro: não considero comprar terabytes de RAM, nessa escala é muito caro. Colocar swap no array SSD/SSD ajudará apenas um pouco (medido), portanto também não é uma solução que estou procurando.


(auto-resposta parcial):

Parece que a leitura de swap realmente sequencial (apenas páginas que pertencem a um único processo) dificilmente é possível sem hackear o kernel: eu medi swapoff -ae certamente não leu o swap sequencialmente. E seria lógico lê-lo mais rápido se tal otimização fosse fácil de implementar.

Atualmente minha melhor abordagem é ler toda a memória do processo através de /proc/[pid]/mempseudo-arquivo usando o script abaixo (que deve ser executado como 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()

Acontece que falha nos últimos bytes de memória, mas geralmente funciona com o mesmo desempenho swapoffe carrega apenas o processo determinado. O script é um trecho modificado deesta resposta.

informação relacionada