Wann sollte Inline in Rust verwendet werden?

80

Rust hat ein "Inline" -Attribut, das in einer dieser drei Varianten verwendet werden kann:

#[inline]

#[inline(always)]

#[inline(never)]

Wann sollten sie verwendet werden?

In der Rust-Referenz sehen wir einen Abschnitt mit Inline-Attributen , in dem steht

Der Compiler fügt Funktionen basierend auf internen Heuristiken automatisch ein. Falsches Inlining kann das Programm tatsächlich verlangsamen, daher sollte es mit Vorsicht verwendet werden.

Im Rust Internals Forum war Huon auch konservativ in Bezug auf die Angabe von Inline .

Wir sehen jedoch eine beträchtliche Verwendung in der Rust-Quelle, einschließlich der Standardbibliothek. Einzeiligen Funktionen werden viele Inline-Attribute hinzugefügt, die für die Compiler leicht zu erkennen und durch Heuristiken gemäß der Referenz zu optimieren sein sollten. Werden diese tatsächlich nicht benötigt?

WiSaGaN
quelle

Antworten:

66

Eine Einschränkung des aktuellen Rust-Compilers besteht darin, dass eine Funktion, die nicht #[inline]über Kisten hinweg markiert ist, niemals inline wird, wenn Sie LTO (Link-Time Optimization) nicht verwenden . Rust verwendet ein separates Kompilierungsmodell ähnlich wie C ++, da die LTO-Implementierung von LLVM nicht gut auf große Projekte skaliert werden kann. Daher müssen kleine Funktionen, die anderen Kisten ausgesetzt sind, von Hand markiert werden. Dies ist keine großartige Situation und wird wahrscheinlich in Zukunft durch eine Kombination von Verbesserungen an LTO- und MIR-Inlining behoben.

#[inline(never)]ist manchmal nützlich zum Debuggen (Trennen eines Codes, der nicht wie erwartet funktioniert). Theoretisch kann es für das Benchmarking verwendet werden, aber das ist normalerweise eine schlechte Idee: Das Deaktivieren von Inlining verhindert nicht andere prozedurale Optimierungen wie die ständige Weitergabe. In Bezug auf normalen Code kann die Codegröße reduziert werden, wenn Sie über eine häufig verwendete Hilfsfunktion verfügen, die nur zur Fehlerbehandlung verwendet wird.

#[inline(always)]ist im Allgemeinen eine schlechte Idee; Wenn eine Funktion groß genug ist, dass der Compiler sie standardmäßig nicht einbindet, ist sie groß genug, damit der Overhead des Aufrufs keine Rolle spielt (und übermäßiges Inlining erhöht den Befehls-Cache-Druck). Es gibt Ausnahmen, aber Sie benötigen Leistungsmessungen, um dies zu rechtfertigen. Dieses Beispiel ist eine Situation, in der es sich zu überlegen lohnt. #[inline(always)]kann auch verwendet werden, um die -O0Codequalität zu verbessern , aber das ist normalerweise keine Sorge wert.

Eli Friedman
quelle
17
Beachten Sie, dass dies inline(never)für die Panik-Intrinsics verwendet wird, um sicherzustellen, dass das Optimierungsprogramm keine Funktionen integriert, die nur im Panikfall aufgerufen werden.
oli_obk
4
-1, weil bis zum ersten Punkt etwas fehlt. Generische Elemente können über Kisten hinweg inline eingefügt werden, da sie beim Instanziieren effektiv kompiliert werden, sodass der für das Inlining erforderliche Code leicht verfügbar ist. Und dies bedeutet, dass eine große Anzahl solcher Gegenstände, die nicht markiert sind, immer noch in einer Kreuzkiste eingelegt werden können. In einigen Arten von einfachen Bibliothekskisten ist jedes Element generisch!
Bluss