스왑에서 전체 프로세스 메모리를 빠르게 로드하는 방법(Linux)?

스왑에서 전체 프로세스 메모리를 빠르게 로드하는 방법(Linux)?

저는 CPU를 많이 사용하는 여러 프로세스를 병렬로 실행합니다. 일반적으로 각각 몇 GB의 메모리를 사용합니다. 때때로 그들은 많은 양의 메모리(예: 150-250GB)를 할당합니다. 일반적으로 최대 하나의 프로세스가 그렇게 하므로 사용 가능한 RAM(내 컴퓨터에서는 384GB)에 맞습니다. 그러나 때때로 더 많은 사람들이 이 많은 양을 동시에 할당하고 (분명히) 스와핑으로 인해 모든 것이 느려지는 경우가 있습니다.

이러한 경우 효과적인 계산을 위해 메모리를 많이 차지하는 프로세스 중 하나만 제외하고 모두 중지합니다. 그러나 중지된 프로세스를 교체하려면 무작위 액세스 패턴으로 디스크에서 수십 기가바이트를 로드해야 하기 때문에 시간이 오래 걸립니다. 따라서 질문은: 어떻게 단일 프로세스가 스왑에서 전체 코어를 순차적으로 로드하도록 강제할 수 있습니까?

지금까지 나는 (cgroup의 도움으로) 프로세스가 더 이상 스와핑하는 것을 방지할 수 있지만 스와핑 해제 성능에는 도움이 되지 않는 swappiness 커널 힌트만 찾았습니다. 모든 스왑을 끄는 것은 중지된 다른 프로세스가 그곳의 공간을 차지해야 하기 때문에 분명히 불가능합니다.

나만의 미니 스케줄러를 구축하는 것도 선택 사항이 아닙니다. 프로세스는 Python의 다양한 작은 스크립트/프로그램이며 메모리 피크는 일반적으로 라이브러리 호출에서 발생하므로 피크가 언제 발생할지 예측할 수 없습니다.


분명히 말하자면, 저는 테라바이트 규모의 RAM 구입을 고려하지 않습니다. 이 규모에서는 너무 비싸기 때문입니다. SSD/SSD 어레이에 스왑을 적용하면 약간의 도움(측정)만 가능하므로 제가 찾고 있는 솔루션도 아닙니다.


(부분 자체 답변):

실제로 순차적인 스왑 읽기(단일 프로세스에 속한 페이지만)는 커널 해킹 없이는 거의 불가능한 것 같습니다. 제가 측정해 본 swapoff -a결과 확실히 스왑을 순차적으로 읽지 못했습니다. 그리고 그러한 최적화를 구현하기 쉽다면 더 빨리 읽는 것이 논리적일 것입니다.

/proc/[pid]/mem현재 가장 좋은 방법은 아래 스크립트(루트로 실행해야 함)를 사용하여 의사 파일을 통해 전체 프로세스 메모리를 읽는 것입니다 .

#!/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지정된 프로세스만 로드합니다. 스크립트는 다음의 수정된 스니펫입니다.이 답변.

관련 정보