How to use cargo llvm-lines?

I'm trying to use GitHub - dtolnay/cargo-llvm-lines: Count lines of LLVM IR per generic function to gain insight on where rustc/llvm time is spent. For a multi crate project, the documentation suggets:

CARGO_PROFILE_RELEASE_LTO=fat cargo llvm-lines --release

However, when I try it all I get is:

CARGO_PROFILE_RELEASE_LTO=fat cargo llvm-lines --release
777 (100%)  62 (100%)  (TOTAL)
   89 (11.5%)  1 (1.6%)  alloc::alloc::Global::alloc_impl
   59 (7.6%)   1 (1.6%)  std::sync::once::Once::call_once
   49 (6.3%)   1 (1.6%)  core::fmt::Arguments::new_v1
   42 (5.4%)   1 (1.6%)  core::mem::replace
   42 (5.4%)   1 (1.6%)  core::sync::atomic::atomic_load
   39 (5.0%)   2 (3.2%)  core::ops::function::FnOnce::call_once
   31 (4.0%)   1 (1.6%)  core::ptr::metadata::from_raw_parts_mut
   28 (3.6%)   1 (1.6%)  alloc::alloc::exchange_malloc
   28 (3.6%)   1 (1.6%)  core::option::Option<T>::ok_or
   24 (3.1%)   1 (1.6%)  alloc::boxed::Box<T>::new
   22 (2.8%)   1 (1.6%)  <core::result::Result<T,E> as core::ops::try_trait::Try>::branch
   17 (2.2%)   2 (3.2%)  core::ops::function::FnOnce::call_once{{vtable.shim}}
   17 (2.2%)   2 (3.2%)  core::ptr::non_null::NonNull<T>::new_unchecked
   14 (1.8%)   1 (1.6%)  <core::result::Result<T,F> as core::ops::try_trait::FromResidual<core::result::Result<core::convert::Infallible,E>>>::from_residual
   14 (1.8%)   1 (1.6%)  core::alloc::layout::Layout::from_size_align_unchecked
   14 (1.8%)   1 (1.6%)  core::ptr::non_null::NonNull<T>::new
   13 (1.7%)   1 (1.6%)  core::ptr::non_null::NonNull<[T]>::slice_from_raw_parts
   13 (1.7%)   1 (1.6%)  core::ptr::read
   12 (1.5%)   1 (1.6%)  alloc::alloc::alloc
   12 (1.5%)   1 (1.6%)  alloc::alloc::alloc_zeroed
   12 (1.5%)   1 (1.6%)  core::option::Option<T>::unwrap
   12 (1.5%)   1 (1.6%)  std::sync::once::Once::is_completed
   10 (1.3%)   1 (1.6%)  core::ptr::mut_ptr::<impl *mut T>::guaranteed_eq
    9 (1.2%)   1 (1.6%)  core::mem::valid_align::ValidAlign::new_unchecked
    9 (1.2%)   1 (1.6%)  core::option::Option<T>::take
    9 (1.2%)   1 (1.6%)  core::ptr::non_null::NonNull<[T]>::as_non_null_ptr
    9 (1.2%)   1 (1.6%)  core::ptr::slice_from_raw_parts_mut
    8 (1.0%)   1 (1.6%)  core::ops::function::Fn::call
    8 (1.0%)   1 (1.6%)  core::ops::function::FnMut::call_mut
    8 (1.0%)   1 (1.6%)  std::sync::once::Once::call_once::{{closure}}
    7 (0.9%)   1 (1.6%)  <alloc::alloc::Global as core::alloc::Allocator>::allocate
    7 (0.9%)   1 (1.6%)  console_error_panic_hook::set_once::{{closure}}
    7 (0.9%)   1 (1.6%)  core::alloc::layout::Layout::align
    7 (0.9%)   1 (1.6%)  core::alloc::layout::Layout::dangling
    7 (0.9%)   1 (1.6%)  core::mem::valid_align::ValidAlign::as_nonzero
    6 (0.8%)   1 (1.6%)  core::sync::atomic::AtomicPtr<T>::load
    5 (0.6%)   2 (3.2%)  core::ptr::non_null::NonNull<T>::as_ptr
    5 (0.6%)   1 (1.6%)  core::mem::maybe_uninit::MaybeUninit<T>::assume_init
    5 (0.6%)   1 (1.6%)  core::ptr::mut_ptr::<impl *mut T>::is_null
    5 (0.6%)   1 (1.6%)  core::ptr::non_null::NonNull<[T]>::as_mut_ptr
    5 (0.6%)   1 (1.6%)  core::ptr::write
    4 (0.5%)   1 (1.6%)  core::mem::maybe_uninit::MaybeUninit<T>::uninit
    4 (0.5%)   1 (1.6%)  core::num::nonzero::NonZeroUsize::new_unchecked
    3 (0.4%)   1 (1.6%)  client_w::main
    3 (0.4%)   1 (1.6%)  client_w::set_panic_hook
    3 (0.4%)   1 (1.6%)  console_error_panic_hook::set_once
    3 (0.4%)   1 (1.6%)  core::alloc::layout::Layout::size
    3 (0.4%)   1 (1.6%)  core::ptr::null_mut
    2 (0.3%)   1 (1.6%)  core::cell::UnsafeCell<T>::get
    2 (0.3%)   1 (1.6%)  core::ptr::invalid_mut
    2 (0.3%)   1 (1.6%)  core::ptr::mut_ptr::<impl *mut T>::addr
    2 (0.3%)   1 (1.6%)  core::ptr::mut_ptr::<impl *mut T>::cast
    2 (0.3%)   1 (1.6%)  core::ptr::mut_ptr::<impl *mut [T]>::as_mut_ptr
    1 (0.1%)   1 (1.6%)  core::mem::manually_drop::ManuallyDrop<T>::into_inner
    1 (0.1%)   1 (1.6%)  core::mem::maybe_uninit::MaybeUninit<T>::as_mut_ptr
    1 (0.1%)   1 (1.6%)  core::num::nonzero::NonZeroUsize::get
    1 (0.1%)   1 (1.6%)  core::ptr::drop_in_place<console_error_panic_hook::hook>
    1 (0.1%)   1 (1.6%)  core::ptr::drop_in_place<std::sync::once::Once::call_once<console_error_panic_hook::set_once::{{closure}}>::{{closure}}>

It is not obvious to me how to interpret this, as I'm getting functions in std/core, not the crates I wrote. How do I use llvm-lines ?

This is expected behaviour because of the way monomorphisation works. It looks like the biggest individual contributors to your code size are those functions from the standard library.

If you only care about the lines in your crate, can't you just use grep to filter the output?

Filter what? The only two lines I see related to my code are:

    3 (0.4%)   1 (1.6%)  client_w::main
    3 (0.4%)   1 (1.6%)  client_w::set_panic_hook

which are not particularly useful, set_panic_hook is for setting up the wasm32 panic hook to print out useful data.

It seems in the data llvm-lines generated (unless there is an option for more verbose data), there is only std/core/alloc lines, so after I filter them, I have nothing left.

Are you sure the compiler hasn't optimised everything down to those two functions?

Another tool that is often used for detecting bloat in your WebAssembly binaries is twiggy.

1 Like

Resolved, see Is a 6000 line enum, included ~125 times, likely to trigger a 5s compile time increase? - #7 by zeroexcuses