Skip to content

Instantly share code, notes, and snippets.

@KodrAus
Last active November 14, 2023 17:19
Show Gist options
  • Save KodrAus/97c92c07a90b1fdd6853654357fd557a to your computer and use it in GitHub Desktop.
Save KodrAus/97c92c07a90b1fdd6853654357fd557a to your computer and use it in GitHub Desktop.
Profiling Rust Applications

Profiling performance

Using perf:

$ perf record -g binary
$ perf script | stackcollapse-perf.pl | rust-unmangle | flamegraph.pl > flame.svg

NOTE: See @GabrielMajeri's comments below about the -g option.

This requires you have flamegraph available in your path. The rust-unmangle script is optional but nice.

Also check out @dlaehnemann's more detailed walkthrough about generating flamegraphs here.

Profiling heap memory

Using valgrind (massif) and massif-visualiser:

$ valgrind --tool=massif binary

Also check out heaptrack, it's similar to massif but more useful out-of-the-box. It also has a nice gui experience:

$ heaptrack binary

Debugging

$ rust-gdb binary

Namespaces are prefixed by the crate name, which is probably also the name of the binary. You can do stuff like:

  • break to set breakpoints
  • print to print a variable
  • step,next,finish to step through calls

Links

@GabrielMajeri
Copy link

GabrielMajeri commented Sep 1, 2018

Great tutorial.

I'd like to point out that using -g with record will, by default, use frame pointers, which are inaccurate in binaries where FPs are not preserved (the default on x86_64).
Using --call-graph dwarf will use DWARF debug info which is much better.
Alternatively, --call-graph lbr (Last Branch Record) can be used on some newer Intel processors, if the call stacks aren't too deep.

Also, it's now possible to use the system allocator on stable: use std::alloc::System;

@anderejd
Copy link

anderejd commented Oct 5, 2018

Thanks GabrielMajeri, --call-graph dwarf makes a huge difference!

@dlaehnemann
Copy link

Jep, thanks to @KodrAus and @GabrielMajeri for your infos on using perf for rust binaries. In the spirit of this gist, I just posted my own more detailed walk-through as a gist after getting flamegraphing to work for my rust project:
https://gist.github.com/dlaehnemann/df31787c41bd50c0fe223df07cf6eb89

Two additions in that walk-through are:

  • using c++filt for demangling (apparently Rust uses some C++ name mangling) further stuff, that rust-unmangle doesn't seem to catch
  • specifying a larger dwarf stack size to accommodate deeper stacks and avoid mis-collapsing of stacks

@hcpl
Copy link

hcpl commented Nov 27, 2018

Please update the example code to:

use std::alloc::System;

#[global_allocator]
static A: System = System;

The current code doesn't compile anymore: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2015&gist=1922d218714af5ccf676452859906b0a.

@HenningTimm
Copy link

@KodrAus Thank you for this post. @hcpl Since Rust 1.32 (January 2019) you no longer need to change the system allocator for heap memory profiling with heaptrack and can use an unmodified binary with heaptrack. I wrote a little tutorial about this: https://gist.github.com/HenningTimm/ab1e5c05867e9c528b38599693d70b35

@hcpl
Copy link

hcpl commented May 14, 2019

Thanks for the notice; you're right, now not even that is needed anymore. And thanks for your tutorial as well, the heaptrack_gui part was new to me!

@anurbol
Copy link

anurbol commented Nov 26, 2019

Is there a similar thing for Windows?

@dlaehnemann
Copy link

Now, there is a cargo subcommand that can be used for flamegraphing Rust code. This should work cross-platform and a little less hacky than the solutions in these gists. Check it out here:
https://github.com/flamegraph-rs/flamegraph

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment