2 Punkte von GN⁺ 2024-12-06 | 1 Kommentare | Auf WhatsApp teilen

Ruby-Leistung verbessern: C in Ruby neu schreiben

Vergleich der Ruby-Performance
  • In einem aktuellen Sprachvergleichs-Repository wurde Ruby als schneller als R und Python bewertet, aber zugleich als die drittschlechteste Sprache eingestuft.
  • Die Benchmarks bestehen aus zwei Tests, „Loops“ und „Fibonacci“, die jeweils Schleifen und Bedingungen sowie den Overhead von Funktionsaufrufen und die Rekursionsleistung hervorheben.
Performance-Vergleich zwischen Ruby und Node.js
  • Auf einem M3 MacBook Pro benötigt Ruby 3.3.6 28 Sekunden für das Schleifenbeispiel und 12 Sekunden für das Fibonacci-Beispiel.
  • Node.js benötigt für beide Beispiele jeweils etwa 1 Sekunde.
  • Auf einem M2 MacBook Air fällt Rubys Performance noch schlechter aus.
Bedeutung der Benchmarks
  • Solche Benchmarks haben in der Praxis möglicherweise keine große Aussagekraft.
  • Python wurde zwar als langsamste Sprache bewertet, ist auf GitHub aber dennoch die meistgenutzte Sprache.
  • Programmiersprachen sollten effizient sein, doch ihre Nützlichkeit und Produktivität sind wichtiger als reine Performance.
Einsatz von YJIT
  • Mit YJIT verbessert sich die Fibonacci-Performance deutlich.
  • Beim Schleifenbeispiel ist der Performance-Gewinn dagegen gering.
Optimierung von Ruby-Code
  • Range#each ist in C geschrieben und kann daher nicht von YJIT optimiert werden.
  • Integer#times wurde in Ruby 3.3 von C nach Ruby umgestellt und kann dadurch von YJIT optimiert werden.
  • Array#each wurde in Ruby 3.4 von C nach Ruby umgestellt.
Optimierung von Integer#times
  • Integer#succ arbeitet schneller als i += 1.
  • YJIT optimiert Integer#times und steigert die Performance dadurch erheblich.
Optimierung von Array#each
  • Array#each wurde in Ruby 3.4 von C nach Ruby umgestellt und kann dadurch von YJIT optimiert werden.
  • Mit dem Modul Primitive wird C-Code in Ruby ausgewertet.
Ruby-Microbench-Repository
  • Benchmarks werden mit verschiedenen Ruby-Versionen und mit YJIT ausgeführt.
  • Ruby 3.4 mit YJIT zeigt deutlich verbesserte Performance.
Optimierung von range#each
  • Die Implementierung der Klasse Range in reinem Ruby kann die Performance verbessern.
YJIT-Standardbibliothek
  • Das YJIT-Team verbessert die Performance, indem es C-Code durch Ruby ersetzt.
  • Mit dem Block with_yjit wird die Ruby-Implementierung verwendet, wenn YJIT aktiviert ist.
Untersuchung der YJIT-Optimierung
  • YJIT optimiert die Performance, indem Ruby-VM-Bytecode in Maschinencode umgewandelt wird.
  • Durch die Analyse des Maschinencodes von Integer#succ lässt sich der Optimierungsprozess von YJIT besser verstehen.

1 Kommentare

 
GN⁺ 2024-12-06
Hacker-News-Kommentare
  • Das Schleifenbeispiel wiederholt sich 1 Milliarde Mal und verwendet verschachtelte Schleifen. Es ist anzunehmen, dass dieser Benchmark in den ersten beiden Zeilen über 99 % der Zeit verbringt

    • Durch Liveness-Analyse der Array-Elemente könnte die gesamte äußere Schleife entfernt und das Programm einfach umgeformt werden
    • Ich frage mich, ob der Compiler eine solche Analyse durchführen kann
    • Selbst wenn u zur Compile-Zeit nicht bekannt ist, könnte die innere Schleife durch einige wenige Instruktionen ersetzt werden
  • Es gibt eine Erwähnung zukünftiger Ruby-Versionen: Ruby 3.4.0 soll zu Weihnachten dieses Jahres erscheinen, Ruby 3.5.0 zu Weihnachten im nächsten Jahr

    • Ich frage mich, welche Auswirkungen Pythons minimales JIT auf solche Schleifen haben wird
    • Python 3.13 muss mit aktiviertem JIT gebaut werden, und es wäre interessant, den Benchmark damit auszuführen
  • Meine Zuneigung zu Ruby ist immer noch da. Danke an Matz

  • Anfang 2024 gab es einen PR zur Leistungsverbesserung von Integer#succ, wodurch ich verstanden habe, warum man Integer#succ verwendet

    • Integer#succ wird beim Umschreiben von Schleifenmethoden verwendet, und im Interpreter wird opt_succ (i = i.succ) schneller verarbeitet als putobject 1; opt_plus (i += 1)
    • Ich persönlich nutze #succ oft aus Gründen der Lesbarkeit und verwende es zweimal in der #bytes-Methode meiner UUID-Bibliothek, damit man beim Lesen des Codes im „Bit-Slicing-Modus“ bleibt
  • Es werden Erfahrungen mit TruffleRuby geteilt; TruffleRuby ist schneller als Node.js und kommt an Bun oder Golang heran

    • Ich bin mir nicht sicher, ob der bereitgestellte Benchmark die Geschwindigkeit von TruffleRuby nach der Änderung zeigt
    • Ich würde den Benchmark gern verifizieren und ihn per Commit zum Haupt-Repository hinzufügen
  • Ruby ist sehr viel schneller geworden, und TruffleRuby ist noch beeindruckender

  • Ich wusste nicht, dass YJIT in Rust geschrieben wurde

  • Python war im Benchmark die langsamste Sprache, ist aber laut GitHub-Stand Oktober 2024 die am häufigsten verwendete Sprache

    • Es scheint eine Korrelation zwischen der Langsamkeit einer Sprache und ihrer Popularität zu geben
  • Es gibt ein älteres Repository zum Vergleich von Programmiersprachen mit mehr Sprachen

  • Das hat meine Advent-of-Code-Lösungen stark verändert, und sie sehen erstaunlich ähnlich aus