Einleitung: Warum Rust-Code profilieren?
\n\nRust ist bekannt für seine Geschwindigkeit und Sicherheit, aber selbst der schnellste Code kann langsam laufen, wenn er Engpässe enthält. Profilierung ist der Prozess der Messung der Programmleistung: Ausführungszeit, CPU-Auslastung, Speicher und andere Metriken. Für angehende Rust-Entwickler ist dies eine unverzichtbare Fähigkeit, um "einfach funktionierenden" Code in effizienten und schnellen Code zu verwandeln.
\n\nStellen Sie sich vor, Sie haben einen Log-Parser oder ein Spiel in Rust geschrieben. Alles kompiliert, aber das Programm läuft länger als erwartet. Anstatt zu raten, welcher Codeabschnitt bremst, können Sie Profiler verwenden, die die genauen "Hotspots" anzeigen. In diesem Artikel behandeln wir die wichtigsten Profilierungswerkzeuge für Rust für Anfänger: cargo-flamegraph, perf und einfache Messungen mit std::time::Instant.
1. Der einfachste Weg: Zeitmessungen mit std::time::Instant
\n\nBevor Sie zu komplexen Werkzeugen übergehen, lernen Sie, die Ausführungszeit einzelner Codeabschnitte zu messen. Dies ist eine grundlegende, aber effektive Methode für Anfänger.
\n\nBeispiel: Messung der Ausführungszeit einer Funktion
\n\nuse std::time::Instant;\n\nfn slow_function() {\n let mut sum = 0u64;\n for i in 0..1_000_000 {\n sum += i;\n }\n println!("Summe: {}", sum);\n}\n\nfn main() {\n let start = Instant::now();\n slow_function();\n let duration = start.elapsed();\n println!("Ausführungszeit: {:?}", duration);\n}\n\n\nDieser Code gibt die genaue Laufzeit von slow_function aus. Dieser Ansatz ist jedoch für größere Projekte unpraktisch: Sie müssten manuell Messungen an jeder verdächtigen Stelle platzieren.
Wann ist das nützlich?
\n- \n
- Sie möchten schnell eine Hypothese über eine langsame Funktion überprüfen. \n
- Es ist nicht möglich, zusätzliche Werkzeuge zu installieren. \n
- Sie arbeiten mit single-threaded Code ohne komplexe Logik. \n
Nachteil: Manuelle Messungen zeigen nicht, wie viel Zeit innerhalb aufgerufener Funktionen verbraucht wird (z. B. Speicherallokationen oder Systemaufrufe). Dafür werden Profiler benötigt.
\n\n2. Profilierung mit perf (Linux)
\n\nDas Dienstprogramm perf ist ein leistungsstarker Profiler für Linux, der auf Kernel-Ebene arbeitet. Es sammelt Stichproben (Samples) davon, wo das Programm Zeit verbringt. Stellen Sie zunächst sicher, dass perf installiert ist:
sudo apt install linux-tools-common linux-tools-generic # Ubuntu/Debian\n\n\nSchritt 1: Kompilierung mit Debug-Informationen
\nDamit perf Funktionsnamen und Codezeilen anzeigen kann, kompilieren Sie das Projekt im Debug-Modus (oder im Release-Modus mit debuginfo-Flags):
cargo build\n# oder\nRUSTFLAGS="-g" cargo build --release\n\n\nSchritt 2: Profilierung starten
\nperf record -g ./target/debug/ihr_programm\nperf report\n\n\nDas Flag -g aktiviert die Aufzeichnung des Aufrufstapels (Call Graph). Nach der Ausführung von perf report sehen Sie eine interaktive Liste der Funktionen, sortiert nach Ausführungszeit.
Beispiel zur Interpretation
\nAngenommen, Sie sehen, dass 70% der Zeit von der Funktion Vec::push belegt wird. Dies könnte bedeuten, dass Sie häufig Speicher neu zuweisen. Lösung: Reservieren Sie die Kapazität des Vektors im Voraus mit Vec::with_capacity.
Tipp: Für Anfänger kann perf aufgrund der Datenfülle komplex erscheinen. Beginnen Sie mit perf top in Echtzeit, um zu sehen, welche Funktionen gerade "brennen".
3. Visualisierung mit cargo-flamegraph
\n\nWenn Sie ein anschauliches Bild benötigen, verwenden Sie cargo-flamegraph. Dieses Tool erstellt Flamegraphs – Diagramme, bei denen die Breite eines Rechtecks die Ausführungszeit einer Funktion und die Tiefe die Ve