1 Punkte von GN⁺ 5 시간 전 | 1 Kommentare | Auf WhatsApp teilen
  • nbd-vram ist ein kleiner Daemon, der es ermöglicht, ungenutzten VRAM einer NVIDIA-GPU unter Linux als Swap-Speicher mit hoher Priorität zu verwenden
  • Auf Hybrid-Grafik-Laptops, bei denen verlöteter Arbeitsspeicher schwer aufzurüsten ist und eine integrierte AMD/ATI-GPU die Bildausgabe übernimmt, wird ungenutzter NVIDIA-VRAM genutzt, um Speicherdruck zu entschärfen
  • Die Testumgebung besteht aus AMD/ATI + RTX 3070 Laptop, 16 GB RAM, 8 GB VRAM, NVIDIA-Treiber 580.159.03, Kernel 6.17 und Pop!_OS; dabei werden 7 GB VRAM als Swap zugewiesen, was zusammen mit zram- und SSD-Swap rund 46 GB adressierbaren Speicher ergibt
  • Die Funktionsreihenfolge ist so aufgebaut, dass zuerst der RAM voll läuft, danach VRAM über PCIe überlaufende Seiten aufnimmt, anschließend zram auf der CPU komprimiert und zuletzt die SSD verwendet wird
  • Der Daemon allokiert VRAM über die CUDA driver API, stellt über das NBD(Network Block Device)-Protokoll auf einem Unix-Socket ein Blockgerät bereit, und der eingebaute nbd-Treiber des Kernels stellt dieses als /dev/nbdX bereit, sodass es wie ein gewöhnliches Swap-Gerät verwendet werden kann
  • Der Datenpfad verläuft von kernel swap subsystem → /dev/nbdX → nbd kernel driver → Unix socket → nbd-vram daemon → cuMemcpyHtoD/DtoH → GPU VRAM
  • Da weder ein separates Kernel-Modul noch NVIDIA-Kernel-Symbole erforderlich sind, kann die Lösung auch nach Kernel- oder Treiber-Updates ohne erneutes Bauen erhalten bleiben
  • Beim NVIDIA-P2P-API-Ansatz liefert nvidia_p2p_get_pages_persistent auf Consumer-GeForce-GPUs EINVAL zurück; auch der direkte BAR1-ioremap_wc-Ansatz scheitert, da Lesezugriffe außerhalb des Display-Framebuffers von etwa 16 MiB nur 0 zurückgeben
  • Der CUDA-Kopierpfad über cuMemcpyHtoD und cuMemcpyDtoH funktioniert auf CUDA-GPUs ohne besondere Berechtigungen, sodass der NBD-Zugriff die Beschränkungen von P2P und BAR1 umgeht
  • Erforderlich sind eine CUDA-fähige NVIDIA-GPU, ein NVIDIA-Treiber mit libcuda.so.1, das nbd-Modul eines Linux-Kernels ab 3.0, nbd-client, gcc und make; das CUDA Toolkit wird nicht benötigt
  • Nach der Installation wird der systemd-Dienst vram-swap-nbd beim Booten automatisch gestartet; über VRAM_SETUP_SIZE_MB und VRAM_SWAP_PRIORITY in /etc/systemd/system/vram-swap-nbd.service lassen sich die maximale nutzbare VRAM-Menge und die Swap-Priorität anpassen
  • Der Daemon versucht zunächst die angeforderte VRAM-Größe und reduziert sie bei zu wenig GPU-Speicher in Schritten von 512 MiB, daher fungiert VRAM_SETUP_SIZE_MB nicht als Mindestwert, sondern als Obergrenze
  • Wenn energieabhängige Verwaltung aktiviert ist, wird der Dienst beim Trennen vom Netzteil oder unterhalb eines Batterie-Grenzwerts automatisch gestoppt und nach Wiederherstellung der Stromversorgung neu gestartet; ein manuelles systemctl stop wird dabei nicht überschrieben
  • Im Benchmark mit dem RTX 3070 Laptop sind sequentieller Durchsatz und anhaltendes zufälliges I/O auf NVMe schneller, aber bei der 4K-Leselatenz mit 1 request/sec ist VRAM mit durchschnittlich 335 us 27-mal schneller als NVMe mit 9,05 ms
  • Das Projekt steht unter der MIT-Lizenz und das Repository enthält test-nbd.sh für Smoke-Tests, test-fill.sh für die Prüfung ganzer Partitionen sowie Benchmark-Skripte für Durchsatz, IOPS und Latenz

1 Kommentare

 
GN⁺ 5 시간 전
Hacker-News-Kommentare
  • Wenn man es über CUDA wie einen Dateispeicher oder ein Mount behandelt, ist der Overhead hoch; mit BAR ließen sich Durchsatz und IOPS vermutlich deutlich verbessern.

  • Wenn die Erklärung lautet, dass das für Laptops mit verlötetem Speicher ohne Upgrade-Pfad gedacht ist, beantwortet das die unmittelbare Frage, warum man von teurem RAM auf noch teureres RAM swappt.
    Der Anwendungsfall wirkt zwar eng, aber in einer Swap-auf-SSD-Situation die ungenutzten 8 GB VRAM zu verwenden, ist bei Bedarf eine gute Idee.

    • Ein weiterer Grund ist, dass man zwar VRAM hat, ihn aber nicht immer nutzt.
      Wenn man sich etwa für Spiele eine GPU gekauft hat, braucht man außerhalb des Spielens keine 16 GB VRAM fürs Desktop-Rendering; also warum nicht anderweitig nutzen?
      Dafür müsste das System beim Start eines Spiels allerdings den als Swap genutzten VRAM wieder freigeben können, und ich frage mich, ob das in der Praxis möglich ist.
    • Kann man VRAM tatsächlich wie normalen RAM verwenden? Wenn man zum Beispiel ein 16-GB-RAM-Modul hat und die GPU 16 GB VRAM besitzt: Kann man das System dann als 32 GB RAM erscheinen lassen, und welche Auswirkungen hätte das?
    • Früher nannte man so etwas RAM-Disk, und auf dem Atari ST war das wahnsinnig schnell.
      Beim Amstrad PCW, der in Großbritannien von Mitte der 80er bis Mitte der 90er weit verbreitet war, konnte man bis zu 512 kB RAM nutzen, und einen ziemlich großen Teil davon als RAM-Disk anlegen.
      Auch das Kompilieren mit Turbo Pascal wurde dadurch sehr schnell :-)
  • Die Idee ist gut, aber hier scheint etwas grundlegend schiefzulaufen.
    Beim RTX 3070 Laptop heißt es, der sequentielle Durchsatz liege bei etwa 1,3 GB/s; dieser RTX-3070-Chip ist aber PCIe 4.0 x16 und sollte 64 GB/s schaffen, und die 8 GB GDDR6 selbst liegen bei 448 GB/s.
    Auf ein NVMe-Laufwerk zu swappen wäre wohl doppelt so schnell, hätte aber höhere Latenz.

    • PCIe 4.0 x16 sind 32 GB/s pro Richtung, und diese Implementierung ist nicht die Art, die man für hohe Performance wählen würde.
      Der Benchmark lief außerdem mit ZRAM, und ZRAM komprimiert Seiten, bevor sie in den Swap gehen. Ich weiß nicht genau, wie hoch der Performance-Overhead ist, aber vermutlich ziemlich groß.
      Zunächst hängt das Ganze an einem Userspace-Programm über den dafür bekannten langsamen nbd-Treiber, und bevor Daten zur GPU gehen, wird auch noch ein Bounce-Buffer im Userspace verwendet. Wenn der Kernel eine Seite auslagern will, kopiert er sie zuerst in einen für den Userspace sichtbaren Buffer; danach muss das Userspace-Programm wieder aufwachen, eine CUDA-Operation auslösen und die Seite in den Gerätespeicher kopieren.
      nbd unterstützt außerdem weder hohe Queue-Tiefen noch das gute Zusammenfassen benachbarter Zugriffe. Wenn der Kernel ohne Merging viele 4K-Seiten in den Swap schickt, braucht man schon für nur 4 GB/s mindestens eine Million Kernel-/Userspace-Kontextwechsel pro Sekunde. Von 64 GB/s ganz zu schweigen. Und das betrachtet nur den NBD-Teil, ohne die Komplexität des NVIDIA-Treibers.
      PCIe kann viele Daten bewegen, aber um in die Nähe der vollen Bandbreite zu kommen, muss man eine DMA-Engine mit langen Seitenlisten verwenden. Wenn man auf PCIe für jede 4K-Seite einzeln eine Übertragung einrichtet, bekommt man den Bus nicht vollständig ausgelastet.
      Der Pfad für Swap auf NVMe ist sehr stark optimiert. Der Swapper kann Seitenlisten direkt an den NVMe-Treiber übergeben, und der Controller holt sie per DMA direkt aus dem RAM; CPU-seitige Kopien oder Kontextwechsel fallen dabei gar nicht an.
      Mit dem ublk-Treiber könnte man den Userspace-Bounce-Buffer vielleicht vermeiden, und mit mehreren Write-Queues ließen sich CUDA-Kopien parallel aufsetzen, was Verbesserungen bringen könnte.
    • Swap auf NVMe verbraucht außerdem PE-Zyklen des NAND und verursacht so über die Zeit Verschleiß.
      RAM oder VRAM werden durch Nutzung nicht schlechter.
  • Ich habe auf meiner Entwicklungsmaschine 32 GB RAM und 32 GB VRAM, die die meiste Zeit ungenutzt herumliegen, solange keine AI-Modelle laufen; daher ist die Idee gar nicht so schlecht.

    • Das wirkt ein bisschen wie ein pcmasterrace-Körper: obenrum riesig, Beine spindeldürr.
  • Ich frage mich, wie Backpressure behandelt wird. Was passiert, wenn eine VRAM-Allokationsanforderung kommt, während VRAM als Swap-Speicher verwendet wird?
    Unter X11 sind Buffer vorallokiert, also ist das nicht ganz so schlimm, aber unter Wayland sind Allokationen viel dynamischer; wenn der VRAM ausgeht, kann leicht der gesamte Desktop abstürzen.
    Beim Umschalten des Rechners mit Hyprland+llama-server+KVM hatte ich schon einige solcher Abstürze, weil VRAM nicht freigegeben werden konnte.

  • Ein Swap-Gerät im Userspace zu bauen, galt schon immer als eines der klassischen unlösbaren Probleme.
    Was macht man, wenn der Daemon eine Seite wieder einlagern will, dafür aber erst die Seiten des Daemons selbst wieder eingelagert werden müssten?
    Solche Diskussionen gab es zumindest als Grund, warum Mikrokernel angeblich nie funktionieren würden. Ich weiß nicht, was hier die Lösung ist.

    • Der Daemon muss nur schlau genug sein zu wissen, welche Seiten seine eigenen sind, und verhindern, dass diese ausgelagert werden.
      Der Linux-Kernel verhindert ja ebenfalls, dass seine eigenen Textseiten ausgelagert werden; die Lösung existiert also bereits, und ich sehe keinen Grund, warum sie sich nicht auch auf Mikrokernel-Designs anwenden ließe.
    • Das allgemeine Prinzip lautet: Was am Paging beteiligt ist, darf selbst nicht paged werden.
      Wenn man den gesamten Speicher dieses Daemons fest pinnt, ist das Problem trivial gelöst.
  • Ich erinnere mich, vor langer Zeit etwas Ähnliches mit dem MTD/phram-Treiber von Linux gemacht zu haben: https://wiki.archlinux.org/title/Swap_on_video_RAM
    Ich weiß allerdings nicht, ob das heute noch relevant ist, weil ich nicht weiß, wie es mit DRM zusammenspielt und wie die Reservierung eines Teils des VRAM gehandhabt wird. Die Empfehlung, das über Limits in xorg.conf zu machen, ist inzwischen wahrscheinlich ziemlich veraltet.
    Auf der Seite gibt es auch ein auf OpenCL basierendes FUSE-Dateisystem: https://github.com/Overv/vramfs
    Das könnte kompatibler sein.

    • Früher habe ich über mtd 8 MB Videospeicher gemappt und genutzt, und das half damals beim Bauen dieser … X11-Treiber.
      Das weckt Erinnerungen.
  • Unter Windows habe ich vor ein paar Jahren etwas Ähnliches gesehen.
    Das war ein experimenteller Proof-of-Concept-Treiber, mit dem man aus dem VRAM von NVIDIA-Karten ein RAM-Laufwerk machen konnte; sequenzielle Zugriffe waren erwartungsgemäß schnell, bei zufälligen Zugriffen gab es aber noch viel Verbesserungspotenzial.
    GpuRamDrive erstellt ein virtuelles Laufwerk auf Basis von GPU-RAM: https://github.com/prsyahmi/GpuRamDrive
    Fork mit AMD-Unterstützung: https://github.com/brzz/GpuRamDrive/

  • Ähnlich, aber mit OpenCL API und daher auch auf AMD lauffähig.
    Allerdings sind die AMD-Treiber ziemlich fehlerhaft, daher muss man „lauffähig“ vielleicht genauer definieren: https://libguestfs.org/nbdkit-vram-plugin.1.html

  • Ich verstehe nicht, warum ein Apple-Silicon-Mac mit 32 GB RAM eine Swap-Datei nutzt oder sogar überhaupt anlegt, obwohl noch 20 GB ungenutzt bzw. „free“ sind.
    Warum gibt es nicht einfach einen simplen Befehl wie swapoff -a unter Linux, um die Swap-Datei vollständig zu deaktivieren?
    Wenn das Ziel nicht absichtlich darin besteht, die SSD-Lebensdauer zu verkürzen, wirkt das ziemlich töricht.
    Es wäre schön, wenn es in der GUI eine Systemeinstellung zum Abschalten der Swap-Datei gäbe, und Apple dürfte endlich auch das heutige „Stufen“-Layout der Systemeinstellungen loswerden. Im Vergleich zu den alten Kontrollfeldern für Systemeinstellungen wirkt es immer noch wie Wortsalat.
    #Apple #Feedback #swapfile

    • Das Prinzip des Paging-Systems ist, dass der Hauptspeicher ein Cache des Sekundärspeichers ist.
      Auch der Begriff „verfügbarer Speicher“ ist idealerweise eher als „Speicher, der schnell für andere Zwecke zurückgewonnen werden kann“ zu verstehen.
      Manchmal ist es besser, gecachte Dateiinhalte diesen Platz einnehmen zu lassen, statt anonymen Speicher weiter im Hauptspeicher zu halten.