{fmt} の縮小: バイナリサイズを14kに削減し、C++ランタイムを除去
(vitaut.net){fmt} ライブラリのバイナリサイズ最適化
-
{fmt} ライブラリの紹介
- {fmt} は小さなバイナリサイズで知られるフォーマットライブラリ
- IOStreams、Boost Format、tinyformat などと比べて、関数呼び出しあたりのコードサイズがはるかに小さい
- 型消去(type erasure)によってテンプレートの負荷を最小化する
-
型消去によるフォーマット
format関数は処理をvformat関数に委譲する- 出力イテレータやその他の出力型も、特別に設計されたバッファAPIを通じて型消去される
- テンプレートの使用を最小限にして、バイナリサイズとビルド時間を削減する
-
サンプルコード
#include <fmt/base.h> int main() { fmt::print("The answer is {}.", 42); }- 上のコードは、IOStreams のコードよりもはるかに小さいサイズでコンパイルされる
printfと比べてもサイズは同程度で、実行時の型安全性を提供する
-
バイナリサイズの最適化
- 2020年にライブラリサイズを100kB以下に抑える作業を実施した
- 最新版(11.0.2)のバイナリサイズは75kB
- ロケールサポートを無効化すると、サイズを71kBまで縮小できる
-
Bloaty ツールを使った分析
- 数値フォーマット、とくに浮動小数点数のフォーマットが大きな割合を占める
- 浮動小数点サポートが不要であれば、これを無効化できる
-
型別フォーマットの最適化
FMT_BUILTIN_TYPESマクロを 0 に設定し、int 型だけを特別扱いし、残りの型は拡張API経由で処理する- この方法でバイナリサイズを31kBまで削減できる
-
ロケールアーティファクトの除去
FMT_USE_LOCALEマクロを使ってロケールアーティファクトを除去すると、サイズを27kBまで縮小できる
-
速度とサイズのトレードオフ
FMT_OPTIMIZE_SIZEマクロを使ってサイズ最適化を行うと、バイナリサイズを23kBまで削減できる
-
C++標準ライブラリ依存の除去
- 例外を無効化し、
-nodefaultlibsオプションを使って C++ ランタイム依存を除去する mallocとfreeを使うカスタムアロケータを導入することで、バイナリサイズを14kBまで削減できる
- 例外を無効化し、
-
結果の確認
lddコマンドを使って、C++ ランタイム依存が除去されたことを確認する
GN⁺のまとめ
- {fmt} ライブラリは、小さなバイナリサイズと実行時の型安全性を提供するフォーマットライブラリ
- 型消去とマクロ設定によって、バイナリサイズを大幅に削減できる
- C++標準ライブラリ依存を除去することで、組み込みシステムでも効率的に利用できる
- 類似の機能を提供するライブラリには、IOStreams、Boost Format、tinyformat などがある
1件のコメント
Hacker Newsのコメント
printf("Hello, World!\n")を実行ファイルサイズ 1008 バイトで実現するプロジェクトがある