cargo-llvm-lines 0.4.26

Count the number of lines of LLVM IR across all instantiations of a generic function.
cargo-llvm-lines-0.4.26 is not a library.

cargo-llvm-lines

Count the number of lines of LLVM IR across all instantiations of a generic function. Based on a suggestion from @eddyb on how to count monomorphized functions in order to debug compiler memory usage, executable size and compile time.

<eddyb> unoptimized LLVM IR <eddyb> first used grep '^define' to get only the lines defining function bodies <eddyb> then regex replace in my editor to remove everything before @ and everything after ( <eddyb> then sort | uniq -c

Installation

Install with cargo install cargo-llvm-lines.

Output

One line per function with three columns of output:

  1. Total number of lines of LLVM IR generated across all instantiations of the function (plus the percentage of the total and the cumulative percentage of all functions so far).
  2. Number of instantiations of the function (plus the percentage of the total and the cumulative percentage of all functions so far). For a generic function, the number of instantiations is roughly the number of distinct combinations of generic type parameters it is called with.
  3. Name of the function.
$ cargo llvm-lines | head -20

  Lines                Copies              Function name
  -----                ------              -------------
  52262                1872                (TOTAL)
   1815 (3.5%,  3.5%)     1 (0.1%,  0.1%)  <cargo_llvm_lines::Opt as clap::derive::Subcommand>::augment_subcommands
   1806 (3.5%,  6.9%)     1 (0.1%,  0.1%)  <cargo_llvm_lines::Opt as clap::derive::FromArgMatches>::from_arg_matches_mut
   1546 (3.0%,  9.9%)    34 (1.8%,  1.9%)  core::option::Option<T>::map
   1045 (2.0%, 11.9%)     5 (0.3%,  2.2%)  clap::parser::matches::arg_matches::ArgMatches::try_remove_arg_t
    738 (1.4%, 13.3%)     2 (0.1%,  2.3%)  alloc::slice::merge_sort
    648 (1.2%, 14.5%)     4 (0.2%,  2.5%)  alloc::raw_vec::RawVec<T,A>::grow_amortized
    645 (1.2%, 15.8%)     6 (0.3%,  2.8%)  <alloc::vec::Vec<T> as alloc::vec::spec_from_iter_nested::SpecFromIterNested<T,I>>::from_iter
    636 (1.2%, 17.0%)    43 (2.3%,  5.1%)  <cargo_llvm_lines::Opt as clap::derive::FromArgMatches>::from_arg_matches_mut::{{closure}}
    587 (1.1%, 18.1%)    15 (0.8%,  5.9%)  <core::result::Result<T,E> as core::ops::try_trait::Try>::branch
    565 (1.1%, 19.2%)     6 (0.3%,  6.2%)  core::iter::traits::iterator::Iterator::try_fold
    533 (1.0%, 20.2%)     1 (0.1%,  6.3%)  cargo_llvm_lines::print_table
    520 (1.0%, 21.2%)     6 (0.3%,  6.6%)  alloc::vec::Vec<T,A>::extend_desugared
    509 (1.0%, 22.2%)     5 (0.3%,  6.9%)  clap::parser::matches::any_value::AnyValue::downcast_into
    504 (1.0%, 23.1%)     5 (0.3%,  7.2%)  alloc::sync::Arc<T>::try_unwrap
    470 (0.9%, 24.0%)    11 (0.6%,  7.7%)  core::option::Option<T>::ok_or_else
    438 (0.8%, 24.9%)     2 (0.1%,  7.9%)  alloc::slice::merge
    414 (0.8%, 25.7%)     9 (0.5%,  8.3%)  core::result::Result<T,E>::and_then

Multicrate Projects

Interpreting the output in the presence of multiple crates and generics can be tricky. cargo llvm-lines only shows the contribution of the root crate; dependencies are not included. To assess the contribution of an intermediate crate, use the -p flag:

$ cargo llvm-lines -p some-depenency

Note however, that Rust generics are monomorphised — a generic function will be accounted for in the crates that use it, rather than in the defining crate.

There is a trick to get a holistic view: enabling link time optimization causes all code generation to happen in the root crate. So you can use the following invocation to get a full picture:

$ CARGO_PROFILE_RELEASE_LTO=fat cargo llvm-lines --release

License