Blazing Rust
Verbessern Sie die gemessene Leistung bei gleichbleibendem Verhalten. Behalten Sie die einfachste Änderung, die einen reproduzierbaren Gewinn für repräsentative Eingaben bringt.
Messen vor dem Bearbeiten
- Identifizieren Sie die Arbeitslast, die Zielmetrik und die Korrektheitsbeschränkungen. Lesen Sie den heißen Pfad und seine Aufrufer. Respektieren Sie die Toolchain des Projekts, die minimale unterstützte Rust-Version, Features und die Zielplattformen. Ein Erklärungsantrag autorisiert die Messung und Profilerstellung, nicht die Bearbeitung.
- Erfassen Sie einen Basiswert mit dem optimierten Produktionsprofil des Projekts, normalerweise
release. Notieren Sie die Eingabe, den genauen Befehl, die Toolchain, Flags, CPU und die Anzahl der Threads. Verwenden Sie realistische Eingabegrößen und -verteilungen, einschließlich kleiner und ungünstiger Fälle. - Finden Sie heraus, was die Leistung begrenzt. Profilieren Sie die CPU-Zeit, Allokationen, I/O oder Lock-Wartezeiten, je nach Bedarf. Untersuchen Sie bei asynchronen Stalls die Aufgabenplanung und das Warteschlangenwachstum mit laufzeitbewusstem Tracing. Verwenden Sie zuerst vorhandene Tools; der Profilierungsabschnitt listet gängige Tools auf und zeigt, wie Symbole in Release-Builds erhalten bleiben. Wenn keine Profilerstellung verfügbar ist, verwenden Sie gezielte Messungen und geben Sie die Grenzen der Evidenz an.
- Stellen Sie eine Hypothese auf und führen Sie eine messbare Änderung durch. Führen Sie fokussierte Korrektheitstests durch und wiederholen Sie denselben Benchmark. Überprüfen Sie das Ergebnis in der vollständigen Arbeitslast, bevor Sie eine für den Benutzer sichtbare Verbesserung behaupten.
- Behalten Sie nachgewiesene Gewinne. Machen Sie nur Ihre erfolglosen Bearbeitungen rückgängig und bewahren Sie unabhängige Arbeit. Hören Sie auf, wenn das Ziel erreicht ist oder es für weitere Änderungen an Evidenz mangelt.
Machen Sie den Benchmark glaubwürdig
- Trennen Sie Setup, Kompilierung, Eingabegenerierung und Prozessstart von der Operation, es sei denn, sie gehören zur Zielmetrik. Verbrauchen Sie Ergebnisse. Verwenden Sie für Mikrobenchmarks die Optimierungsbarrieren der Benchmark-Bibliothek oder
std::hint::black_boxfür Ein- und Ausgaben. Diese Barrieren sind ein guter Versuch, daher überprüfen Sie unplausible Ergebnisse. - Vergleichen Sie gleichwertige Arbeit und Ergebnisse. Halten Sie Toolchain, Profil, Features, Allokator, CPU-Einstellungen und Thread-Anzahl fest, es sei denn, eine davon ist die getestete Variable. Wärmen Sie auf, wenn Sie den stationären Zustand messen. Messen Sie Kaltstarts separat, wenn relevant.
- Wiederholen Sie Durchläufe und berichten Sie die Stichprobenanzahl, den Median und die Variabilität. Wechseln Sie Basis- und Kandidatenläufe ab, wenn Drift eine Rolle spielt. Ein Unterschied im Rauschen begründet keinen Gewinn.
- Passen Sie die Metriken an die Aufgabe an. Messen Sie für Dienste die p95/p99-Latenz bei einer angegebenen Last, den Durchsatz, Fehler und die Ressourcennutzung. Überprüfen Sie, ob eine reduzierte Latenz nicht auf Kosten von verworfenen Arbeiten oder einer wachsenden Warteschlange ging.
- Verwenden Sie vorhandene Benchmarks wieder. Fügen Sie einen kleinen Regressionsfall hinzu, wenn eine neue Logik einen benötigt. Installieren Sie keine Tools, fügen Sie keine Abhängigkeiten hinzu oder ändern Sie Buildeinstellungen ohne Autorisierung der Aufgabe. Erfinden Sie niemals Messungen.
Wählen Sie Änderungen basierend auf Evidenz
Beginnen Sie mit unnötiger Arbeit und Algorithmen. Ziehen Sie Änderungen auf niedrigerer Ebene nur in Betracht, wenn der verbleibende Engpass sie erfordert. Lesen Sie den entsprechenden Abschnitt des Technikleitfadens, wenn ein gemessener Engpass mehr Details benötigt.
| Beobachtete Kosten | Änderungsvorschlag und Prüfungen |
|---|---|
| Wiederholte Durchläufe oder Berechnungen | Verbessern Sie den Algorithmus oder die Auswahl der Sammlung. Entfernen Sie doppeltes Parsen, Sortieren, Serialisieren und Lookups. Berücksichtigen Sie Cache-Invalidierung und Speicher, wenn Caching hilft. |
| Allokation oder Kopieren | Verwenden Sie &str und Slices, verschieben Sie eigene Werte, verwenden Sie Puffer wieder und reservieren Sie glaubwürdige Kapazitäten. Versuchen Sie clone_from, wenn Sie einen allokierten Wert ersetzen. Vermeiden Sie Zwischensammlungen. clone kann für gemeinsame Handles billig sein, messen Sie daher seine Kosten. |
| Lookups in Sammlungen | Verwenden Sie ausgeliehene Schlüssel und Entry-APIs, wenn sie wiederholte Arbeit vermeiden. Vergleichen Sie dichte Vektoren oder sortierte Daten, wenn das Zugriffsmuster passt. Bewahren Sie den Kollisions-Angriffsschutz für nicht vertrauenswürdige Schlüssel beim Wechseln von Hashern. |
| Sortierung oder Entfernung | Verwenden Sie select_nth_unstable für die Auswahl, sort_unstable, wenn die Reihenfolge gleicher Elemente irrelevant ist, und sort_by_cached_key für teure Schlüssel. Verwenden Sie swap_remove nur, wenn die Elementreihenfolge irrelevant ist. |
| Cache-Fehler oder große Werte | Vergleichen Sie Arrays von Strukturen mit Strukturen von Arrays. Überprüfen Sie size_of, align_of und Cache-Fehler. Inline-Speicher kann das Kopieren erhöhen. Ziehen Sie das Boxen seltener großer Enum-Payloads in Betracht, unter Berücksichtigung von Allokationen und Indirektion. |
| Kleine heiße Aufrufe oder Schleifen | Bevorzugen Sie normale Iteration. Helfen Sie dem Compiler, Grenzprüfungen mit Slices, Iteration oder Bereichsassertionen zu entfernen. Überprüfen Sie die optimierte Assembly vor dem Inlining oder Unrolling. Testen Sie leere Eingaben, Enden, Überläufe und Codegröße. |
| Textsuche | Verwenden Sie kompilierte reguläre Ausdrücke wieder und fordern Sie nur benötigte Übereinstimmungsinformationen an. Vergleichen Sie spezialisierte Bytsuchen, wenn die Kodierungssemantik es erlaubt. Vermeiden Sie den Neuaufbau des Suchstatus innerhalb heißer Schleifen. |
| Vektorisierbare Berechnungen | Überprüfen Sie die Auto-Vektorisierung vor explizitem SIMD. Überprüfen Sie den generierten Code. Schützen Sie zielspezifische Anweisungen, wo nötig, und behalten Sie einen skalaren Fallback bei. Testen Sie Enden und repräsentative CPUs. Bewahren Sie Ausrichtung, Grenzen und numerisches Verhalten. |
| Unabhängige CPU-Arbeit | Vergleichen Sie die serielle Ausführung mit begrenztem Parallelismus. Messen Sie Kosten für Scheduling, Kontention, Bandbreite, Thread-Anzahl und gesamten CPU-Verbrauch. Passen Sie die Aufgabengröße nur an, wenn der Overhead wichtig ist. Bewahren Sie die Reduktionssemantik. |
| I/O oder asynchrone Stalls | Verwenden Sie Zeilenpuffer wieder, bündeln Sie kleine I/Os und behandeln Sie Leerungsfehler. Bewahren Sie Latenz, Newline-Handling und Haltbarkeit. Halten Sie blockierende oder schwere CPU-Arbeit von asynchronen Workern fern. Begrenzen Sie Parallelität und Warteschlangen. Bewahren Sie die Reihenfolge, den Gegendruck und die Stornierung. |
| Build- oder Code-Generierungs-Limits | Vergleichen Sie vorhandene Einstellungen mit Thin-LTO. Testen Sie Fat-LTO und codegen-units = 1 separat, bevor Sie sie kombinieren. Schließen Sie Build-Zeit und Binärgröße ein. Verwenden Sie CPU-spezifische Flags nur, wenn dies die Zielhardware zulässt. |
Bewahren Sie die Korrektheit
Halten Sie öffentliche APIs, Fehlerbehandlung, Validierung, Reihenfolge, Serialisierung und FFI-Verträge intakt. Bewahren Sie das Verhalten bei Integer-Überlauf und Gleitkommaoperationen. Die Darstellung von Enums oder die Variantenreihenfolge kann das Layout und die Diskriminanten ändern; keines garantiert eine kleinere oder schnellere Enum.
Bevorzugen Sie sicheres Rust und vorhandene Abhängigkeiten. Das Einführen von unsicherem Code erfordert einen gemessenen Bedarf, explizite Sicherheitsinvarianten und fokussierte Tests. Verwenden Sie Miri oder Sanitizer, wo unterstützt und relevant. Tauschen Sie niemals Validierung oder Solidität gegen Benchmark-Geschwindigkeit ein, und behandeln Sie bestandene Tests nicht als Beweis für Solidität.
Berichten Sie das Ergebnis
Geben Sie den Engpass, die Änderung und die Entscheidung zum Behalten oder Rückgängigmachen an. Enthalten Sie reproduzierbare Befehle, Vorher-/Nachher-Ergebnisse mit Variabilität, relevante Allokations- oder Speicherzahlen, Korrektheitsprüfungen und Kompromisse. Unterscheiden Sie Multikern-Wallclock-Gewinne von Single-Core-Effizienz. Nennen Sie nicht gemessene Behauptungen und nicht überprüfte Plattformen.