Was ist Criterion und wozu braucht man es?
Criterion.rs ist eine leistungsstarke und flexible Bibliothek für das Benchmarking (Performance-Testing) in Rust. Sie ist das direkte Pendant zur bekannten Criterion-Bibliothek für Haskell, wurde aber speziell an das Rust-Ökosystem angepasst.
Wozu braucht man Criterion? Im Gegensatz zu einfachen Zeitmessungen mit std::time::Instant bietet Criterion:
- Statistische Analyse: Führt den Code automatisch mehrfach aus, sammelt eine Stichprobe der Ausführungszeiten und berechnet Mittelwert, Median, Standardabweichung und Perzentile.
- Vergleich mit einer Referenz: Ermöglicht den Vergleich der Performance der aktuellen Codeversion mit einer vorherigen (Regressionstests).
- Berichtserstellung: Erstellt ansprechende HTML-Berichte mit Diagrammen und Tabellen.
- Parametrisches Benchmarking: Testet die Performance einer Funktion einfach mit verschiedenen Eingabedaten.
- Robustheit gegenüber Rauschen: Die Algorithmen von Criterion sind unempfindlich gegenüber Laufzeitschwankungen, die durch Hintergrundprozesse des Betriebssystems verursacht werden.
Die Bibliothek ist unverzichtbar für Entwickler, die:
- Kritische Codeabschnitte optimieren möchten.
- Sicherstellen wollen, dass neuer Code die alte Funktionalität nicht verlangsamt.
- Entscheidungen auf Basis von Daten statt Vermutungen treffen möchten.
Installation von Criterion in einem Rust-Projekt
Anders als in Python (pip) oder Node.js (npm) erfolgt die Installation von Bibliotheken in Rust über den Paketmanager Cargo. Criterion ist keine Bibliothek für den Hauptcode, sondern ein Werkzeug zum Testen. Daher wird es im Abschnitt [dev-dependencies] der Datei Cargo.toml hinzugefügt.
Außerdem benötigen Sie ein Verzeichnis benches/ im Stammverzeichnis Ihres Projekts (neben src/).
Schritt 1: Abhängigkeit in Cargo.toml hinzufügen
[dev-dependencies]
criterion = { version = "0.5", features = ["html_reports"] }
Hinweis: Das Flag features = ["html_reports"] aktiviert die Erstellung von HTML-Berichten. Ohne dieses Flag erhalten Sie nur Textausgaben in der Konsole.
Schritt 2: Benchmark-Datei erstellen
Erstellen Sie eine Datei benches/my_benchmark.rs (der Name kann beliebig sein).
Schritt 3: Benchmark ausführen
cargo bench
Dieser Befehl kompiliert Ihr Projekt im Release-Modus (mit Optimierungen) und führt alle Benchmarks aus dem Ordner benches/ aus.
Schnellstart: Erster Benchmark
Schreiben wir einen einfachen Benchmark, der die Geschwindigkeit der Summierung von Zahlen von 0 bis 99 misst.
// benches/my_benchmark.rs
use criterion::{black_box, criterion_group, criterion_main, Criterion};
// Die zu testende Funktion
fn sum_slow(n: u64) -> u64 {
let mut sum = 0;
for i in 0..n {
sum += i;
}
sum
}
fn sum_fast(n: u64) -> u64 {
n * (n - 1) / 2
}
fn criterion_benchmark(c: &mut Criterion) {
// Benchmarks gruppieren
let mut group = c.benchmark_group("sum_comparison");
group.bench_function("slow", |b| b.iter(|| sum_slow(black_box(100))));
group.bench_function("fast", |b| b.iter(|| sum_fast(black_box(100))));
group.finish();
}
// Makros zur Registrierung und Ausführung
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);
Was passiert hier?
black_box()– teilt dem Compiler mit, dass der Wert "wie er ist" übergeben werden soll, und verhindert so eine vorzeitige Optimierung (der Compiler könnte die Konstante zur Kompilierzeit berechnen, was das Ergebnis verfälschen würde).b.iter()– die Hauptschleife des Benchmarks. Criterion ruft dieses Closure mehrfach auf und misst die Zeit.criterion_group!undcriterion_main!– Makros, die
Auch in der Bibliothek
Rate Limiting in Go: Leitfaden zur Begrenzung der Anfragenrate
GraphQL in C# (.NET): Vollständiger Leitfaden zur Bibliothek GraphQL.NET
Arbeiten mit Kafka in TypeScript: Die Bibliothek KafkaJS und Beispiele
Clap für Rust: Vollständige Anleitung mit Beispielen