Wie lädt man den gesamten Prozessspeicher schnell aus dem Swap-Speicher (Linux)?

Wie lädt man den gesamten Prozessspeicher schnell aus dem Swap-Speicher (Linux)?

Ich führe eine Reihe CPU-hungriger Prozesse parallel aus. Normalerweise verwenden sie jeweils einige GB Speicher. Von Zeit zu Zeit belegen sie auch große Speichermengen (sagen wir 150-250 GB). Normalerweise tut dies höchstens einer der Prozesse, sodass sie in den verfügbaren RAM passen (384 GB auf meinem Computer). Manchmal kommt es jedoch vor, dass mehrere Prozesse gleichzeitig diese große Menge belegen und (offensichtlich) alles aufgrund des Swappings langsamer wird.

In solchen Fällen stoppe ich alle Speicherfresser-Prozesse bis auf einen, damit dieser effektiv rechnen kann. Aber es dauert ewig, einen gestoppten Prozess wieder einzulagern, da das bedeutet, dass Dutzende Gigabyte in einem Zufallszugriffsmuster von der Festplatte geladen werden müssen. Daher lautet die Frage: Wie kann ich einen einzelnen Prozess dazu zwingen, den gesamten Kern sequenziell aus dem Swap-Speicher zu laden?

Bisher habe ich nur einen Kernelhinweis zum Thema Swappiness gefunden, der (mithilfe von Cgroups) einen Prozess davon abhalten kann, mehr zu swappen, aber die Leistung des De-Swappings nicht verbessert. Den gesamten Swap abzuschalten ist offensichtlich nicht möglich, da die anderen, gestoppten Prozesse dort Platz belegen müssen.

Das Erstellen eines eigenen Mini-Schedulers ist auch keine Option – die Prozesse bestehen aus verschiedenen kleinen Skripten/Programmen in Python und die Speicherspitzen treten im Allgemeinen bei Bibliotheksaufrufen auf, sodass ich nicht vorhersagen kann, wann eine Spitze auftreten wird.


Nur um das klarzustellen: Ich denke nicht daran, Terabyte an RAM zu kaufen, in diesem Umfang ist es zu teuer. Swap auf SSD/SSD-Array zu setzen, wird (gemessen) nur ein bisschen helfen, also ist es auch nicht die Lösung, nach der ich suche.


(teilweise Selbstantwort):

Es scheint, dass wirklich sequentielles Lesen des Swaps (nur Seiten, die zu einem einzelnen Prozess gehören) ohne Kernel-Hacking kaum möglich ist: Ich habe Messungen durchgeführt swapoff -aund der Swap wurde definitiv nicht sequentiell gelesen. Und es wäre logisch, ihn schneller zu lesen, wenn eine solche Optimierung einfach zu implementieren wäre.

Derzeit besteht meine beste Vorgehensweise darin, den gesamten Prozessspeicher /proc/[pid]/memmithilfe des folgenden Skripts (das als Root ausgeführt werden muss) über eine Pseudodatei zu lesen:

#!/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()

Es kommt vor, dass es bei den letzten Bytes des Speichers fehlschlägt, aber im Allgemeinen funktioniert es mit der gleichen Leistung wieswapoff und lädt nur den angegebenen Prozess. Das Skript ist ein modifizierter Ausschnitt ausdiese Antwort.

verwandte Informationen