2 Punkte von GN⁺ 2023-11-30 | 1 Kommentare | Auf WhatsApp teilen
  • Ausgangspunkt war ein Hinweis, dass das Lesen von Dateien über die Python-Bindings von Apache OpenDAL langsamer sei als Pythons eingebautes open().read(). Der Engpass lag jedoch weder bei OpenDAL noch bei PyO3 selbst
  • In einem Benchmark zum Lesen einer 64-MiB-Datei wurde python-fs-read mit etwa 15–19 ms gemessen, während Rust std::fs und eine C-Implementierung bei etwa 23 ms lagen – Rust/C wirkten damit langsamer als Python
  • Mit strace, eBPF und perf zeigte sich, dass der Unterschied mit dem Offset zusammenhing, an dem der Zielpuffer des read-Systemcalls innerhalb einer Speicherseite liegt; nahe 0x10 ließ sich der Performance-Einbruch reproduzieren
  • Ähnliche Effekte wurden auf AMD Ryzen 9 5900X, Ryzen 7 5700X und Ryzen 9 5900HX beobachtet; ein zentraler Hinweis war die Ausführungsleistung von rep movsb innerhalb von Kernel-_copy_to_iter
  • Python war nicht grundsätzlich schneller. Das Ergebnis entstand durch einen CPU-Bug rund um FSRM/rep movsb bei AMD Zen 3 und einen zufälligen Speicher-Offset; auch die Verbesserung durch jemalloc lag nicht am Allocator selbst, sondern an einem anderen Offset

Ein merkwürdiger Benchmark, der bei den OpenDAL-Python-Bindings begann

  • Apache OpenDAL ist eine Datenzugriffsschicht, um Daten über verschiedene Storage-Services hinweg einheitlich zu lesen und zu schreiben; die Python-Bindings werden über PyO3 bereitgestellt
  • Ein Nutzer meldete, dass Code zum Lesen einer 150-MB-Datei über die OpenDAL-Python-Bindings langsamer sei als Pythons eingebautes Datei-Lesen
    • Python eingebautes open(...).read() 100-mal: 4.470868484000675
    • OpenDAL-Python-Bindings 100-mal: 8.993250704006641
  • Auch beim vereinfachten Lesen einer 64-MiB-Datei waren die OpenDAL-Bindings langsamer
    • python-fs-read: durchschnittlich 15,9 ms
    • python-opendal-read: durchschnittlich 32,9 ms
    • Pythons eingebautes Lesen wurde 2,07-mal schneller gemessen als die OpenDAL-Bindings

Die Spur führt hinunter zu Rust OpenDAL und std::fs

  • Selbst wenn dieselbe Logik mit dem OpenDAL-fs-Service in Rust umgesetzt wurde, war sie langsamer als Pythons eingebautes Lesen
    • rust-opendal-fs-read: durchschnittlich 23,8 ms
    • python-fs-read: durchschnittlich 15,6 ms
    • Pythons eingebautes Lesen wurde 1,52-mal schneller gemessen als die Rust-OpenDAL-Implementierung
  • Da OpenDALs fs-Service std::fs aus Rust verwendet, wurde zur Prüfung des OpenDAL-Overheads separat eine Implementierung auf Basis von std::fs geschrieben
  • Auch bei der direkten Rust-std::fs-Implementierung setzte sich das gleiche Muster fort
    • rust-std-fs-read: durchschnittlich 23,1 ms
    • python-fs-read: durchschnittlich 15,2 ms
    • Pythons eingebautes Lesen wurde 1,52-mal schneller gemessen als Rust std::fs

Systemcalls und mmap aus Sicht von strace

  • Die Analyse mit strace zeigte, dass sowohl Rust als auch Python für große Puffer-Allokationen mmap nutzten
  • Die Ausführung von Rust std::fs öffnete /tmp/file, las 64 MiB in einem Schritt, rief danach ein read zur EOF-Prüfung auf und schloss die Datei wieder
  • Pythons eingebautes Lesen führte zwar mehr Systemcalls wie newfstatat, ioctl und lseek aus, brauchte insgesamt aber weniger Zeit
  • Der Aufruf mmap(NULL, 67112960, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) diente nicht dem File-Mapping, sondern der anonymen Speicherallokation
    • 67112960 entspricht 64 MiB plus 4 KiB
    • MAP_ANONYMOUS bedeutet eine Speicherallokation ohne Bezug zu einer Datei
  • Rusts Standard-Build für x86_64-unknown-linux-gnu verwendet malloc aus glibc, und glibc kann für große Allokationen mmap einsetzen

Rust wird mit jemalloc schneller – und die Zwischenfolgerung kippt

  • Nachdem der globale Rust-Allocator auf jemallocator::Jemalloc umgestellt wurde, war Rust schneller als Python
    • rust-std-fs-read-with-jemalloc: durchschnittlich 9,7 ms
    • python-fs-read: durchschnittlich 15,8 ms
    • Die Rust-Implementierung mit jemalloc wurde 1,64-mal schneller gemessen als Python
  • Zu diesem Zeitpunkt sah es so aus, als läge die Ursache bei mmap oder beim Standard-Speicherallocator, doch in einem späteren Update wurde diese Interpretation korrigiert
  • Nach dem Update vom 01.12.2023 entstand der Unterschied nicht, weil jemalloc, pymalloc oder mimalloc grundsätzlich schneller wären als glibc malloc
  • Der tatsächliche Unterschied kam vom Offset innerhalb der Speicherseite des vom Allocator erzeugten Puffers
    • rust-std-fs-read: liest beim Offset 0x10 relativ zur mmap-Startadresse
    • rust-std-fs-read-with-jemalloc: liest beim Offset 0x740 relativ zur mmap-Startadresse
  • Der problematische Bereich wurde auf 0x00..0x10 innerhalb der Seite eingegrenzt; auch mit jemalloc lässt sich dasselbe Problem reproduzieren

Ein Problem, dessen Reproduzierbarkeit stärker vom Gerät als von Software-Einstellungen abhing

  • Im weiteren Verlauf der Diskussion wurde bestätigt, dass der Effekt „Rust ist langsamer als Python“ auf dem Gerät des Autors besonders ausgeprägt war
  • Die CPU des Autors war ein AMD Ryzen 9 5950X 16-Core Processor, der Arbeitsspeicher bestand aus DDR4 3200 MT/s 16-GB-DIMMs
  • Auch durch Änderungen verschiedener Einstellungen verschwand der relative Performance-Unterschied nicht
    • Das erneute Aktivieren von Linux-Kernel-mitigations=off änderte das Ergebnis nicht
    • Änderungen bei Transparent Hugepage auf always, madvise oder never änderten die absoluten Werte, die relative Relation blieb aber erhalten
    • Auch das Binden an bestimmte CPU-Kerne per core_affinity führte zum gleichen Ergebnis
  • Auch eBPF-basierte Latenzmessungen des read-Systemcalls zeigten, dass die Rust-Seite langsamer war
    • Python read file: 8.134.049 ns
    • Rust std::fs read file: 24.636.975 ns
  • Aus den Beobachtungen ließ sich der Unterschied nur mit OpenDAL, PyO3 oder der Rust-Standardbibliothek kaum erklären; bereits auf Systemcall-Ebene tat sich die Zeitdifferenz auf

Der Speicher-Offset als Hinweis aus der C-Implementierung

  • Auch eine Implementierung desselben Lesens einer 64-MiB-Datei in C mit fopen/malloc/fread war langsamer als Python
    • c-fs-read: durchschnittlich 23,8 ms
    • python-fs-read: durchschnittlich 19,1 ms
    • Pythons eingebautes Lesen wurde 1,25-mal schneller gemessen als die C-Implementierung
  • Mit strace -e raw=read,mmap wurden die Pointer-Adressen geprüft; dabei unterschieden sich die Start-Offsets der Puffer von C und Python
    • C: read beim Offset 0x10 relativ zur von mmap zurückgegebenen Adresse
    • Python: read beim Offset 0x30 relativ zur von mmap zurückgegebenen Adresse
  • Nachdem der Offset in der C-Implementierung auf dieselbe Weise angepasst wurde, verbesserte sich die Performance deutlich
    • c-fs-read-with-offset: durchschnittlich 8,9 ms
    • 2,15-mal schneller als Python und 2,68-mal schneller als die ursprüngliche C-Implementierung
  • Dieses Problem ließ sich auch auf AMD Ryzen 9 5900X und AMD Ryzen 7 5700X reproduzieren
  • In der Rust-Community wurde unter Std::fs::read slow? ein ähnlicher Effekt gemeldet; dort wurde ebenfalls auf den Zusammenhang zwischen Speicherbereich-Offset und Systemcall-Performance hingewiesen

perf-Analyse zeigt auf rep movsb

  • Ein Kernel-Entwickler reproduzierte c-fs-read und die Version mit Offset auf einem AMD Ryzen 9 5900HX und analysierte sie mit perf
  • Je nach Vorhandensein des Offsets unterschieden sich die Werte für L1-dcache-prefetches und L1-dcache-loads deutlich
    • Ohne Offset: L1-dcache-loads etwa 127.845.213, L1-dcache-prefetches etwa 1.843.493
    • Mit Offset: L1-dcache-loads etwa 13.965.813, L1-dcache-prefetches etwa 395.578
  • Der Hotspot lag im Kernel-read-Pfad von shmem_file_read_iter über copy_page_to_iter bis _copy_to_iter
  • Die zentrale Assembly-Instruktion innerhalb von _copy_to_iter war rep movsb, und die meisten Samples konzentrierten sich auf diese Instruktion
  • Spätere Analysen ordneten ein, dass nicht das L1-Prefetching an sich der wichtigere Hinweis war, sondern dass rep movsb bei seitenausgerichteten Daten schlecht performt und besser wird, wenn diese Seitenausrichtung aufgebrochen wird

FSRM und das AMD-Zen-3-Problem

  • Auch der geteilte Ubuntu-glibc-Bugreport Terrible memcpy performance on Zen 3 when using rep movsb behandelt Performance-Probleme mit rep movsb
  • Das Beispiel im Bericht erklärt, dass der rep movsb-Pfad beim Kopieren von 2113 Bytes etwa 3,2 GB/s erreicht und bei einer Änderung der Größe auf 2111 Bytes auf über 100 GB/s steigt
  • FSRM steht für Fast Short REP MOV und ist eine Funktion, die rep movsb und rep movsd schneller machen soll
  • FSRM ist eine ursprünglich von Intel eingeführte Funktion, die auch bei AMD Einzug gehalten hat; auf CPUs, die Unterstützung dafür deklarieren, nutzt glibc standardmäßig FSRM
  • Damit war die Schlussfolgerung: Python ist nicht grundsätzlich schneller als C/Rust; durch einen AMD-CPU-Bug wurde der C/Rust-Lesepfad bei bestimmten Speicher-Offsets langsam

Update: Kenntnisstand bei AMD und Reaktion von glibc

  • Laut Update vom 01.12.2023 war AMD dieser Bug offenbar bereits seit 2021 bekannt
  • Da nach Veröffentlichung des Artikels mehrere Leser den Link an AMD weitergaben, geht der Autor davon aus, dass AMD von dem Problem weiß
  • Der Autor meint, AMD solle diesen Bug in amd-ucode verantwortlich beheben; unbestätigten Informationen zufolge könnte ein amd-ucode-Fix auf Zen 3 jedoch schwierig sein
  • Die realistische Hoffnung ist, dass glibc bei Bedarf FSRM deaktiviert
  • Auf glibc-Seite laufen Arbeiten zu x86: Improve ERMS usage on Zen3

Reproduktionscode und weiterführende Materialien

1 Kommentare

 
GN⁺ 2023-11-30
Meinungen auf Hacker News
  • Es gibt gleich zwei spezielle CPU-Feature-Flags, die anzeigen, dass REP STOS/MOV schnell ist und als kurze Befehlssequenz für memset/memcpy verwendet werden kann.
    Seit Jahrzehnten besteht der Schmerz darin, optimierte Routinen für jede neue CPU-Generation von Hand neu zu schreiben; dass das immer noch so ist, lässt einen fragen, ob so etwas nicht in die Timing-Test-Suite der CPU-Hersteller gehören müsste.

    • Reine Spekulation, aber es könnte auch an einem Bugfix liegen, der in letzter Minute oder nach dem Release per Microcode-Update eingespielt wurde.
      Vielleicht gab es ein Problem mit seitenweise ausgerichtetem schnellem rep movs, oder es war für irgendeinen Angriff anfällig und wurde deshalb deaktiviert.
    • Wenn ich das richtig verstehe, frage ich mich, ob das bedeutet, dass man für jeden Build zu einem bestimmten Kompilierzeitpunkt zwei ausführbare Dateien erzeugen muss, oder ob man auf bestimmter Hardware kompilieren muss.
      Ich weiß nicht, wie der Fix aussehen sollte – ob dafür etwa ein Runtime-Check nötig ist.
    • Man nimmt leicht an, dass CPU-Hersteller ihre eigenen CPUs am besten kennen.
      Wenn es eine schnellere „Software“-Implementierung gibt, frage ich mich, warum REP MOVS nicht zumindest im Microcode dasselbe macht.
  • Der zugehörige glibc-Bug ist hier. Allerdings geht es dort um Zen 4: https://sourceware.org/bugzilla/show_bug.cgi?id=30994

  • Zuerst habe ich den Artikel gelesen und war bereit, mich darüber lustig zu machen, dass der Autor std::fs falsch benutzt hat; tatsächlich war es aber ein erfreulicher Text mit einem Debugging-Kaninchenbau und einem Mysterium nach dem anderen.
    Gut geschrieben und sehr interessant.

    • Es war wirklich ein guter Artikel. Die Debugging-Methode, ein Testprogramm zu schreiben und Schicht für Schicht abzutragen, war clever; die Schlussfolgerung war interessant und unerwartet, und der Text war klar und leicht nachzuvollziehen.
  • Die Prämisse ist etwas verwirrend. Verglichen wurde nicht reiner Python-Code mit nativem C/Rust-Code, sondern eine Python-Dateilesemethode, also ein Python-Wrapper über nativem Code, mit OpenDAL, einem weiteren Wrapper über nativem Code.
    Dass es einen Performance-Unterschied gibt, ist weiterhin interessant, aber das als „langsamer als Python“ zu beschreiben, ist ziemlich seltsam. Hat man erwartet, dass die gesamte Python-Standardbibliothek in reinem Python geschrieben ist? Eher würde ich erwarten, dass die Funktionsimplementierungen der Python-Standardbibliothek nativ und einzeln stark optimiert sind.
    Dass die Schlussfolgerung mit der Arbeitsweise von nativem Code zu tun hatte, war nicht überraschend, die konkrete Antwort dagegen schon. Nur der Einstieg war verwirrend; der Artikel selbst war sehr interessant.
    Auch der Titel „C is slower than Python with specified offset“ liest sich für Muttersprachler so, als sei „C selbst bei angegebenem Offset langsamer als Python“. Gemeint war tatsächlich das Gegenteil: Als man den in Python verwendeten Offset auch in C angab, wurde C schneller.

    • Ich verstehe eher nicht, warum das verwirrend sein soll.
      Dass eine einfache Aufgabe wie das Lesen einer Datei in der Rust-Standardbibliothek langsamer ist als in der Python-Standardbibliothek, ist überraschend. Selbst wenn man weiß, dass solche Aufrufe der Python-Standardbibliothek in C geschrieben sind, erwartet man, dass ein Aufruf der Rust-Standardbibliothek ungefähr ähnlich schnell ist.
      Normalerweise würde man also eine falsche Verwendung oder ein seltsames Verhalten der Rust-Standardbibliothek vermuten; diesmal war es aber keines von beidem, sondern eine von der Allokationsausrichtung abhängige Performance-Klippe auf bestimmter Hardware.
      Man erwartet zwar, dass Dateisystem-Lesevorgänge in Python gut optimiert sind, denkt aber, dass das in Rust ebenso gilt. Deshalb ist es überraschend, dass die Rust-Seite viel langsamer war – und besonders, dass es von Hardware und Allocator abhing.
    • Ich verstehe nicht, warum Python, wenn es langsam ist, als langsame Sprache beschimpft wird, aber wenn es schnell ist, keine Anerkennung bekommt, weil es „nicht echtes Python“ sei.
      Wenn Code, den ich in Python geschrieben habe, schnell ist, dann ist für mich Python schnell. Ob das daran liegt, dass die Implementierung in einer anderen Sprache geschrieben ist, oder an etwas anderem, ist mir ziemlich egal.
    • Ich weiß nicht, warum man erwarten sollte, dass es „einzeln stark optimiert“ ist.
      Was im Originalartikel passiert ist, kommt fast einem Zufall gleich. Der C-Code von CPython achtet nicht einmal auf const-Konsistenz, und es gibt viele dynamische Speicherallokationen sowie Hilfs-/Komfortaufrufe. Sogar Dinge wie Arithmetik führen dynamische Speicherallokationen aus.
      Wer schon mit CPython gearbeitet hat, erwartet normalerweise keine gute Performance. Wenn man Performance verbessern will, versucht man eher, die dort bereitgestellten Funktionen zu umgehen.
      Außerdem hat Python keinen Standard, also streng genommen auch keine Standardbibliothek, und die mitgelieferte Bibliothek ist größtenteils in Python geschrieben. Einige Teile sind in C geschrieben, aber auch von diesem C-Code ist ein beträchtlicher Anteil im Grunde mechanisch von Python nach C übertragen. Zum Beispiel war Pythons Implementierung der binären Suche ursprünglich in Python geschrieben und wurde später mithilfe der Python C API nach C übersetzt.
      Worauf man hoffen kann, ist höchstens, dass Funktionen, die schlicht auf Betriebssystemfunktionen abbilden, relativ dünne Wrapper haben. Das heißt: Dateilesen geht im Kern direkt in ein Systeminterface, sodass nicht viel Binding-Code nötig sein dürfte.
    • Danke für den Hinweis. Ich habe den Titel geändert.
    • Die Prämisse ist, dass Formulierungen wie „Python ist schneller als Rust“ Pageviews bringen, selbst wenn sie nicht stimmen.
      Nachdem ähnliche Artikel dutzende Male erschienen sind, haben das alle gemerkt.
  • Der Artikel selbst ist hervorragend und enthält viele interessante Informationen zu diesem Thema.
    Was mich jedoch mehr interessiert und beunruhigt, ist, wie das Problem gemeldet und dokumentiert wurde und wie die Kommunikation gehandhabt wird.
    Die Meldung erfolgt auf Discord, einer proprietären Umgebung, die nicht indexiert wird, schwer durchsuchbar ist und nicht dauerhaft erhalten bleibt. Die Diskussion findet auf Discord und Telegram statt; in diesem Kontext könnte Telegram sogar noch schlechter sein.
    Dieser Blogbeitrag und das GitHub-Repository sind die einzigen Spuren, die davon geblieben sind. Hätte Xuanwo nicht im Blog darüber geschrieben, wäre es in der Timeline verschwunden. Eine ziemlich interessante Situation.

    • Dass es eine proprietäre Plattform ist, stimmt und ist nicht gut. Aber der Vorwurf, sie sei nicht indexierbar oder durchsuchbar, überzeugt mich schwer.
      Es gibt kaum Messenger, die standardmäßig öffentlich zugängliche Logs indexieren und durchsuchbar machen. Nicht jeder IRC-Server stellt öffentliche Logs bereit, und bei Matrix-Gruppen ist es genauso. Ich sehe nicht, warum Diskussionen dort nicht ebenfalls in der Timeline verschwinden sollten.
      Öffentliche Logs lassen sich nicht deshalb bereitstellen, weil etwas nicht proprietär ist, sondern weil es eine API gibt, die Logging erlaubt. Telegram hat ebenfalls eine solche API, und die durchsuchbaren Logs unserer Diskussionsgruppe kann man hier sehen: https://luoxu-web.vercel.app/#g=1264662201
      Dass es keine öffentliche Indexierung gibt, liegt vor allem an Privatsphäre, nicht daran, dass die Plattform proprietär ist.
    • Genau deshalb akzeptiere ich jedes Mal, wenn ich den Niedergang von USENET bedauere, die Antwort „Jetzt gibt es doch Discord“ nicht.
      Früher konnte man alle Beiträge sauber über DejaNews und später über Google durchsuchen.
      Wichtige Kommunikation in wichtigen Open-Source-Projekten, etwa beim Internet-/WWW-Stack und bei zentralen Programmierwerkzeugen und -bibliotheken, sollte über offene Standards laufen.
  • Das war der interessanteste Artikel, den ich diese Woche gelesen habe. Eine hervorragende Zusammenfassung.

  • Das Naheliegende scheint zu sein, einen Patch für die Kernel-Methode copy_user_generic einzureichen.
    Wenn eine problematische CPU erkannt wird und sie den Bug auslöst, durch den Speicher-Alignment langsam wird, kann man einfach eine andere Speicherkopier-Implementierung verwenden lassen.

    • So naheliegend ist das nicht. Wenn sich das per Microcode beheben lässt, scheint es besser, die Leute aktualisierten Microcode verwenden zu lassen, statt den Kernel mit Fix-Code für ein praktisch per Software patchbares Problem zu verstreuen.
      Ein Fix, der für jemanden ohne Kernel-Erfahrung akzeptabel wäre, dürfte nicht trivial sein. Wichtiger noch: Es ist auch nicht offensichtlich, wie der Workaround aktiviert werden sollte. Am besten wäre vermutlich eine Messung beim Booten; andernfalls ist unklar, wie man wissen soll, welche Modelle und Steppings betroffen sind.
    • Das ist kein trivialer Fix. AMD muss herausfinden, warum Aliasing bei Adressen nahe an der Page-Ausrichtung kaputtgeht, daher dürfte die Korrektur eher im Microcode liegen.
      Auch eine Software-Abmilderung wäre kompliziert. Denn der Kernel kann die Vektorbefehle, die er normalerweise im alternativen Pfad verwendet, wenn ERMS nicht genutzt werden kann, tatsächlich nicht verwenden.
  • jemalloc war bis 2018 der Standard-Allocator von Rust.
    https://internals.rust-lang.org/t/jemalloc-was-just-removed-...

  • Der Abschnitt „Rust-Entwickler können erwägen, zur Performance-Steigerung auf jemallocator umzusteigen“ macht mich neugierig
    Ich weiß nicht, ob damit praktisch jeder nahezu kostenlose Performance-Gewinne bekommen kann oder ob es dabei Fallstricke gibt. Ich frage mich auch, ob C-Codebasen davon profitieren könnten und ob das derzeit einfach verschenkte Performance ist.

    • Man sollte wissen, dass es bei der Nutzung von jemalloc wegen MADV_FREE Probleme mit der Beobachtbarkeit gibt. htop zeigt dann nicht mehr zuverlässig an, wie viel Speicher tatsächlich in Benutzung ist.
      https://github.com/jemalloc/jemalloc/issues/387#issuecomment...
      https://gitlab.haskell.org/ghc/ghc/-/issues/17411
      Inzwischen scheint jemalloc 10 Sekunden nach MADV_FREE MADV_DONTNEED aufzurufen: https://github.com/JuliaLang/julia/issues/51086#issuecomment...
      Das „behebt“ dieses Problem zwar, erzeugt aber eine verwirrende Verzögerung zwischen dem Zeitpunkt, zu dem Speicher freigegeben wird, und dem Zeitpunkt, zu dem man das in htop beobachten kann.
      Laut https://jemalloc.net/jemalloc.3.html kann man die Verzögerung allerdings durch Setzen von opt.muzzy_decay_ms = 0 beseitigen.
      Trotzdem ist der Autor von musl zurückhaltend dabei, jemalloc zum Standard zu machen: https://www.openwall.com/lists/musl/2018/04/23/2
      Der Kernpunkt ist, dass es Probleme mit starkem Aufblähen, geschwächter ASLR und Optimierungen gibt, die darauf ausgerichtet sind, möglichst schnell zu sein, ohne auf den Speicherverbrauch zu achten. Mit den obigen Tuning-Werten lässt sich das wohl bis zu einem gewissen Grad abmildern, aber die grundsätzliche Ausrichtung – ob man Performance oder Speicherverbrauch priorisiert – dürfte weiterhin ein Trade-off bleiben.
    • Ich würde das als nahezu kostenlos verschenkte Performance sehen. Der Preis ist eine etwas größere Binary.
      Es wird nicht in jeder Situation zwingend schneller sein, aber in fast allen Fällen vermutlich schon. Rust hat früher ebenfalls standardmäßig jemalloc verwendet, aber das wurde geändert, weil es Leute gab, die diesen Default überraschend fanden.
    • Der Wechsel auf einen nicht standardmäßigen Allocator verbessert die Performance nicht immer.
      Das hängt stark vom Workload ab, daher sind Profiling und Benchmarking nötig. Trotzdem sollten Low-Level-Sprachen wie C/C++/Rust solche Allocators auswählbar machen.
      Ein Punkt, auf den man achten sollte, ist die Binary-Größe. Ein benutzerdefinierter Allocator fügt der ausführbaren Datei zusätzliche Bytes hinzu.
    • Rust hat früher standardmäßig jemalloc verwendet, ist aber um 2018 herum wieder zum System-malloc zurückgekehrt[0].
      Heute gibt es in Rust das Trait GlobalAlloc und das Attribut #[global_allocator], sodass eine App jemalloc als Allocator verwenden kann, wenn sie möchte. Ich bin mir nicht sicher, ob Nutzer das mit etwas wie LD_PRELOAD überschreiben können.
      jemalloc ist nicht immer die beste Wahl für jeden Workload und jeden Anwendungsfall. System-Allocators sind oft alles andere als perfekt, wurden aber zumindest breit als Allzweck-Allocators getestet.
      [0] https://github.com/rust-lang/rust/issues/36963
    • Performance ist keine eindimensionale Skala, auf der sich ein Programm von „langsam“ nach „schnell“ bewegt. Es spielen immer auch andere Faktoren mit.
      jemalloc kann für manche Anwendungen die richtige Wahl sein, in anderen Fällen kann aber ein anderer Allocator schneller sein. Oder er ist zwar langsamer, passt aber besser zu Zielen wie weniger Dirty Memory, besserer Beobachtbarkeit oder bestimmten Sicherheitsgarantien.
  • Ich habe das an die passenden Leute weitergeleitet.

    • Meinst du, du hast es an AMD weitergeleitet?