最近Redditでちょっと話題になっていたcargo-bloatを紹介。
Cargo-bloat
どの関数が重いかがざっくりわかるCargo Subcommand。
こんな感じになります。
$ cargo bloat --release -n 10
Finished ...
File .text Size Name
39.1% 72.8% 1.5MiB [3469 Others]
3.5% 6.4% 132.1KiB clap::app::parser::Parser::add_defaults
2.3% 4.3% 88.7KiB clap::app::parser::Parser::add_env
1.5% 2.8% 56.9KiB <regex::exec::ExecNoSync<'c> as regex::re_trait::Regu...
1.3% 2.4% 50.0KiB clap::app::parser::Parser::get_matches_with
1.3% 2.4% 49.8KiB clap::app::parser::Parser::parse_long_arg
1.3% 2.4% 49.1KiB clap::app::parser::Parser::parse_short_arg
1.1% 2.0% 40.2KiB rg::args::ArgMatches::to_args
0.9% 1.7% 34.5KiB regex_syntax::parser::Parser::parse_expr
0.9% 1.6% 33.4KiB clap::app::validator::Validator::validate_matched_args
0.7% 1.3% 25.8KiB encoding_rs::variant::VariantDecoder::decode_to_utf8_raw
53.8% 100.0% 2.0MiB .text section size, the file size is 3.7MiB
How to Use
Install
まだcrates.ioには置いていないのでgitを介してinstallする感じになる。
cargo install --force --git https://github.com/RazrFalcon/cargo-bloat.git
2017/1/12追記: Publishされました
cargo install cargo-bloat
Command
$ cargo bloat -V
cargo-bloat 0.1.0
$ cargo bloat -h
Find out what takes most of the space in your executable
Usage: cargo bloat [options]
Options:
-h, --help Print this message
-V, --version Print version info and exit
--features FEATURES Space-separated list of features to also build
--all-features Build all available features
--no-default-features Do not build the `default` feature
--manifest-path PATH Path to the manifest to analyze
--release Build artifacts in release mode, with optimizations
--example NAME Build only the specified example
--crates Per crate bloatedness
--filter CRATE Filter functions by crate
--split-std Split the 'std' crate to original crates like core, alloc, etc.
--full-fn Print full function name with hash values
-n NUM Number of lines to show, 0 to show all [default: 20]
-w, --wide Do not trim long function names
-v, --verbose Use verbose output
-q, --quiet No output printed to stdout
--color WHEN Coloring: auto, always, never
--frozen Require Cargo.lock and cache are up to date
--locked Require Cargo.lock is up to date
-Z FLAG ... Unstable (nightly-only) flags to Cargo
見慣れないオプションがいくつかある。
--crates Per crate bloatedness
--filter CRATE Filter functions by crate
--split-std Split the 'std' crate to original crates like core, alloc, etc.
--full-fn Print full function name with hash values
-n NUM Number of lines to show, 0 to show all [default: 20]
-w, --wide Do not trim long function names
使用例
お世話になっているripgrepに使ってみる。
$ git clone https://github.com/BurntSushi/ripgrep
$ cd ripgrep
$ cargo bloat --release
Compiling ...
Finished ...
File .text Size Name
34.5% 64.1% 1.3MiB [3459 Others]
3.5% 6.4% 132.1KiB clap::app::parser::Parser::add_defaults
2.3% 4.3% 88.7KiB clap::app::parser::Parser::add_env
1.5% 2.8% 56.9KiB <regex::exec::ExecNoSync<'c> as regex::re_trait::Regu...
1.3% 2.4% 50.0KiB clap::app::parser::Parser::get_matches_with
1.3% 2.4% 49.8KiB clap::app::parser::Parser::parse_long_arg
1.3% 2.4% 49.1KiB clap::app::parser::Parser::parse_short_arg
1.1% 2.0% 40.2KiB rg::args::ArgMatches::to_args
0.9% 1.7% 34.5KiB regex_syntax::parser::Parser::parse_expr
0.9% 1.6% 33.4KiB clap::app::validator::Validator::validate_matched_args
0.7% 1.3% 25.8KiB encoding_rs::variant::VariantDecoder::decode_to_utf8_raw
0.7% 1.2% 25.5KiB globset::GlobSet::new
0.6% 1.2% 23.7KiB rg::run
0.5% 0.9% 18.6KiB regex::re_bytes::Regex::find_at
0.5% 0.9% 18.5KiB <regex::re_trait::Matches<'t, R> as core::iter::itera...
0.5% 0.9% 17.9KiB ignore::walk::Worker::run
0.4% 0.8% 15.6KiB rg::app::app
0.4% 0.7% 15.1KiB clap::app::help::Help::write_arg
0.4% 0.7% 15.0KiB rg::run_one_thread
0.4% 0.7% 14.9KiB clap::app::usage::get_required_usage_from
0.4% 0.7% 13.8KiB clap::app::validator::Validator::validate
53.8% 100.0% 2.0MiB .text section size, the file size is 3.7MiB
普通に打つとこんな感じ。デフォルトではトップ20が表示され、その他は一つにまとめられる。コマンドラインパーサのclapが目立つ。
Sizeは.textセクションのもの。%はファイル全体に対してと.textセクションの合計に対しての両方を出してくれるようになった。
20は多いので-n 10
でトップ10だけ表示することにする。これが上に載せた例。
$ cargo bloat --release -n 10
Finished ...
File .text Size Name
39.1% 72.8% 1.5MiB [3469 Others]
3.5% 6.4% 132.1KiB clap::app::parser::Parser::add_defaults
2.3% 4.3% 88.7KiB clap::app::parser::Parser::add_env
1.5% 2.8% 56.9KiB <regex::exec::ExecNoSync<'c> as regex::re_trait::Regu...
1.3% 2.4% 50.0KiB clap::app::parser::Parser::get_matches_with
1.3% 2.4% 49.8KiB clap::app::parser::Parser::parse_long_arg
1.3% 2.4% 49.1KiB clap::app::parser::Parser::parse_short_arg
1.1% 2.0% 40.2KiB rg::args::ArgMatches::to_args
0.9% 1.7% 34.5KiB regex_syntax::parser::Parser::parse_expr
0.9% 1.6% 33.4KiB clap::app::validator::Validator::validate_matched_args
0.7% 1.3% 25.8KiB encoding_rs::variant::VariantDecoder::decode_to_utf8_raw
53.8% 100.0% 2.0MiB .text section size, the file size is 3.7MiB
clapが重いのは明らかだが、--crates
オプションを渡して確認する。
$ cargo bloat --release --crates
Finished ...
File .text Size Name
15.3% 28.4% 584.0KiB clap
11.1% 20.7% 426.1KiB [Unknown]
10.7% 20.0% 410.5KiB std
6.2% 11.5% 236.5KiB regex
3.4% 6.4% 131.1KiB regex_syntax
2.5% 4.7% 96.7KiB ignore
1.3% 2.5% 50.8KiB globset
0.8% 1.4% 29.3KiB encoding_rs
0.5% 0.9% 19.0KiB grep
0.4% 0.8% 17.1KiB walkdir
0.3% 0.6% 11.8KiB aho_corasick
0.2% 0.4% 8.0KiB crossbeam
0.2% 0.3% 6.0KiB env_logger
0.2% 0.3% 6.0KiB thread_local
0.1% 0.2% 5.1KiB termcolor
0.1% 0.2% 3.2KiB ansi_term
0.1% 0.1% 2.8KiB vec_map
0.1% 0.1% 2.1KiB utf8_ranges
0.1% 0.1% 2.1KiB memchr
0.1% 0.1% 2.0KiB strsim
53.8% 100.0% 2.0MiB .text section size, the file size is 3.7MiB
28%をclapが占めているという状態。高機能なだけになかなか重い。
軽量版clapを使う
ここでclapのv2.29.1
を使うようにcargo update
してからもう一度実行してみる。
$ cargo bloat --release --crates
Finished ...
File .text Size Name
12.2% 24.8% 423.5KiB [Unknown]
11.7% 23.8% 406.8KiB std
7.0% 14.3% 244.0KiB clap
6.8% 13.8% 236.7KiB regex
3.8% 7.7% 131.1KiB regex_syntax
2.8% 5.7% 96.7KiB ignore
1.5% 3.0% 50.8KiB globset
0.8% 1.7% 29.3KiB encoding_rs
0.5% 1.1% 19.0KiB grep
0.5% 1.0% 17.1KiB walkdir
0.3% 0.7% 11.8KiB aho_corasick
0.2% 0.5% 8.0KiB crossbeam
0.2% 0.4% 6.0KiB env_logger
0.2% 0.3% 6.0KiB thread_local
0.1% 0.3% 5.1KiB termcolor
0.1% 0.2% 3.2KiB ansi_term
0.1% 0.2% 2.8KiB vec_map
0.1% 0.1% 2.1KiB utf8_ranges
0.1% 0.1% 2.1KiB memchr
0.1% 0.1% 2.0KiB strsim
49.2% 100.0% 1.7MiB .text section size, the file size is 3.4MiB
300Kほど軽くなっている。
実は、clapの開発者がcargo-bloatの結果に触発されて軽量化を行ったらしい。開発途中だけど、こんな感じで参考になりそう。
2017/01/12追加: stdライブラリを分割して表示
1/11夜にオプションがいくつか追加されたので--split-std
を使ってみた。--filter
とかは自明なので割愛。
$ cargo bloat --release --crates --split-std
Finished ...
File .text Size Name
12.2% 24.8% 423.5KiB [Unknown]
7.0% 14.3% 244.0KiB clap
6.8% 13.8% 236.7KiB regex
5.5% 11.2% 191.5KiB core
3.8% 7.7% 131.1KiB regex_syntax
3.4% 7.0% 119.6KiB std
2.8% 5.7% 96.7KiB ignore
2.6% 5.3% 91.4KiB alloc
1.5% 3.0% 50.8KiB globset
0.8% 1.7% 29.3KiB encoding_rs
0.5% 1.1% 19.0KiB grep
0.5% 1.0% 17.1KiB walkdir
0.3% 0.7% 11.8KiB aho_corasick
0.2% 0.5% 8.0KiB crossbeam
0.2% 0.4% 6.0KiB env_logger
0.2% 0.3% 6.0KiB thread_local
0.1% 0.3% 5.1KiB termcolor
0.1% 0.2% 3.2KiB std_unicode
0.1% 0.2% 3.2KiB ansi_term
0.1% 0.2% 2.8KiB vec_map
49.2% 100.0% 1.7MiB .text section size, the file size is 3.4MiB
stdライブラリがcore
やalloc
などのcrateに分割されて表示されているのがわかる。
注意点
- RustではなくCで書かれたライブラリ等は
[Unknown]
にまとめられる - Windows未対応