Rustのderiveはしばしばinlineを暗黙に含む
Rust's derive often implies inline
Rustの#[derive(Debug)]などは自動的に#[inline]を付与する。これは仕様ではないが、リファレンスでも例示されている。筆者はuvのバイナリサイズを約160KB削減できたことから、このinlineがコードサイズを増大させる場合があると指摘。特にネストしたエラー型のDebug実装で顕著になる。
uvのバイナリサイズを約160KB削減できたのは、特定のDebug実装をrustcがインライン化しないようにしたからだ。
HNでの議論
30- Sharlin
Debugは決してインライン化されるべきではないと確信している。Displayもおそらく同様で、fmtの仕組みは十分重いので、シリアライゼーションが多いワークロードでもインライン化しないことがボトルネックになることはおそらくない。自分のDebug/Display実装のいくつかに#[inline(never)]を付ける必要があり、バイナリサイズが数十キロバイト削減された(数百キロバイトのうちなので、相対的にはかなりの削減)。
- vlovich123
Debugは最初に使われたときに遅延生成されるべきだと思う。99%のDebug実装は使われないので、特別なマーカーを付けて展開しないようにし、残りは#[cold]としてインライン化するのは明らかに間違いだ。もちろん実際に実装するのは非常に難しいだろう。
とはいえ、正当化のためのパフォーマンス改善PR自体も改善とリグレッションが混在していた。
- scottlamb
`#[derive(Debug)]`に対して、`facet` [1]のようにテーブル駆動のアプローチを検討したことはあるのだろうか。実行速度よりもバイナリサイズとコンパイル時間が重要な、これほど定型的なものに対しては、私ならまずそう考える。しかし、facetはその約束をこれらの面でまだ果たしていないように思うので、stdでのテーブル駆動アプローチも同様に試されて却下されたのかもしれない。
- zamazan4ik
あるいは、Profile-Guided Optimization (PGO)を使って、実際のアプリケーションの実行プロファイルに基づいてインラインの挿入/削除を行うことで、こうした最適化の推測をすべて避けるようにしてみてはどうか。
- api
LLVMが関数をインライン化するかどうかのヒューリスティックは「return true;」だというジョークがある。LLVMは積極的にインライン化する傾向がある。
この動作は最適化レベル「s」や「z」、あるいは「#[inline(never)]」で制御できるが、インライン化が少なすぎるとパフォーマンスに大きな悪影響が出る可能性があることに注意が必要だ。
プロファイルに基づく最適化なしでインライン化を正確に行うのは難しい。