Rheaper is a in-process heap profiler for rust, that plugs in place and collect allocation data, and later stores it in a SQLite database for analysis. It supports runtime activation/deactivation.
To enable heaptrack in you project, set the global allocator:
#[global_allocator]
static GLOBAL: Rheaper::Allocator<mimalloc::MiMalloc> =
rheaper::Allocator::from_allocator(mimalloc::MiMalloc);
at any point, tracking can be enabled:
let profile_path = rheaper::enable_tracking(Rheaper::TrackerConfig {
/// how deep should the call stack be sampled
max_stack_depth: 30,
/// each thread that allocates acquire a local tracker from the global pool. That's how many trackers can be created
max_trackers: 200,
/// How many alloc events are buffered per local tracker
tracker_event_buffer_size: 5_000,
/// How often to sample backtraces, 1.0 is always, 0.0 is never.
sample_rate: 1.0,
/// where th profile will be written
profile_dir: PathBuf::new(),
});
Recording is stopped with:
rheaper::disable_tracking();
This will resolve pending backtraces, and flush profiling data to disk. After than, the profile can be analyzed
rheaper rip-4744532 profile.db
this will create a profile.db
sqlite database. This database can be opened with sqlite to perform analytics.
show the 10 biggest contributor by callsites:
SELECT bt, sum(size) FROM allocations GROUP BY bt ORDER BY sum(size) DESC LIMIT 10;
bt sum(size)
-------------------- ---------
14887427388493581654 61044456
6831336122721510729 52678176
2113490791341760087 52678176
15757739337697011469 31692912
3437328128932597320 24435936
15830995416840919940 10029120
7763277092675977093 9981504
10258202288105587101 9981504
12697966346495929209 3928320
4493127380101385995 3883680
show allocations, by callsites, that lives for more than 10 seconds:
SELECT bt, count(0), sum(size) FROM allocations where dealloc_after NOT NULL AND dealloc_after - alloc_after < 10000 GROUP BY bt ORDER BY sum(size) DESC LIMIT 5;
bt count(0) sum(size)
-------------------- -------- ---------
14887427388493581654 372 61044456
6831336122721510729 372 52678176
2113490791341760087 372 52678176
15757739337697011469 372 31692912
3437328128932597320 372 24435936
bt can be used to query the backtraces table
:
select frame_no, sym from backtraces where id = '14887427388493581654' limit 10;
frame_no sym
-------- ------------------------------------------------------------
0 backtrace::backtrace::libunwind::trace::h313fcf731c1ed43a
1 <rheaper::alloc::Allocator<A> as core::alloc::global::Glob
alAlloc>::alloc::{{closure}}::hd945306712c35cdc
2 rheaper::alloc::with_local::{{closure}}::{{closure}}::{{cl
osure}}::{{closure}}::h984dd2b94bca5c66
3 rheaper::alloc::TrackerGuard::with::h2f7bcd4120d6efa7
4 rheaper::alloc::with_local::{{closure}}::{{closure}}::{{cl
osure}}::h51d6f70563022314
5 std::thread::local::LocalKey<T>::try_with::hff003d76feecb4a9
6 rheaper::alloc::with_local::{{closure}}::{{closure}}::h233
b8e1d7f3eb3c5
7 rheaper::alloc::untracked::{{closure}}::hc0fb5ce1fd3deaf9
8 std::thread::local::LocalKey<T>::try_with::h8850e1a558f39df6
9 std::thread::local::LocalKey<T>::with::hcab5ce8347c6de7c
thanks you @gmourier for the logo!