blondie
Collect CPU callstack samples from a windows process.
Since the "SampledProfile" ETW events we use come from a "kernel event provider"(PerfInfo) we must use the ETW "Kernel Logger session", which requires elevated priviledges. Therefore, you must run blondie as administrator in order for it to work.
The blondie
binary can be used to generate a text file with the sample count of each call stack, or a flamegraph using the inferno
library.
The blondie_dtrace
binary can be used as a dtrace replacement in cargo-flamegraph via the DTRACE environment variable.
Examples:
./blondie.exe flamegraph ./target/debug/some_binary_with_debuginfo.exe arg1 arg2
./flamegraph.svg
cargo build --release --bin blondie_dtrace
$ENV:DTRACE = "current_dir/target/release/blondie_dtrace.exe" # Or set DTRACE="current_dir/target/release/blondie_dtrace.exe" in cmd.exe
cd some/other/project
cargo flamegraph ; ./flamegraph.svg
I wrote this to be able to get flamegraphs using https://github.com/flamegraph-rs on windows.
This is built using the ETW(Event Tracing for Windows) API to collect CPU samples and DLL/EXE load events, and the DbgHelp Symbol Handler API to translate the virtual addresses ETW gives us to symbol names.
Future work?
Example output
Example flamegraph from a hello world rust program:
Here's a bit of example output from running blondie on dust:
Example output
```
dust`__chkstk+0x37
dust`std::sys::windows::fs::File::file_attr+0x11
dust`std::sys::windows::fs::stat+0x6E
dust`std::fs::metadata[ >+0x4C
dust`std::path::Path::metadata+0x1B
dust`dust::platform::get_metadata+0x47
dust`dust::node::build_node+0x10B
dust`dust::dir_walker::walk::closure$0+0x2AF
dust`rayon::iter::filter_map::impl$6::consume >,dust::node::Node,rayon::iter::fold::FoldFolder > (*)(alloc::collections::linked_list::LinkedList >,alloc::collections::linked_list::LinkedList >),alloc::collections::linked_list::LinkedList > >,alloc::collections::linked_list::LinkedList > (*)(alloc::vec::Vec)>,alloc::vec::Vec,alloc::vec::Vec (*)(alloc::vec::Vec,dust::node::Node)>,dust::dir_walker::walk::closure_env$0>+0x96
dust`rayon::iter::par_bridge::impl$3::fold_with > (*)(alloc::collections::linked_list::LinkedList >,alloc::collections::linked_list::LinkedList >),alloc::collections::linked_list::LinkedList > >,alloc::collections::linked_list::LinkedList > (*)(alloc::vec::Vec)>,alloc::vec::Vec,alloc::vec::Vec (*)(alloc::vec::Vec,dust::node::Node)>,dust::dir_walker::walk::closure_env$0> >+0x13F
dust`rayon::iter::plumbing::bridge_unindexed_producer_consumer,rayon::iter::filter_map::FilterMapConsumer > (*)(alloc::collections::linked_list::LinkedList >,alloc::collections::linked_list::LinkedList >),alloc::collections::linked_list::LinkedList > (*)()>,alloc::collections::linked_list::LinkedList > (*)(alloc::vec::Vec)>,alloc::vec::Vec (*)(),alloc::vec::Vec (*)(alloc::vec::Vec,dust::node::Node)>,dust::dir_walker::walk::closure_env$0> >+0x664
dust`rayon::iter::plumbing::bridge_unindexed_producer_consumer::closure$0,rayon::iter::filter_map::FilterMapConsumer > (*)(alloc::collections::linked_list::LinkedList >,alloc::collections::linked_list::LinkedList >),alloc::collections::linked_list::LinkedList > (*)()>,alloc::collections::linked_list::LinkedList > (*)(alloc::vec::Vec)>,alloc::vec::Vec (*)(),alloc::vec::Vec (*)(alloc::vec::Vec,dust::node::Node)>,dust::dir_walker::walk::closure_env$0> >+0xC5
dust`rayon_core::join::join_context::call_a::closure$0 >,rayon::iter::plumbing::bridge_unindexed_producer_consumer::closure_env$0,rayon::iter::filter_map::FilterMapConsumer > (*)(alloc::collections::linked_list::LinkedList >,alloc::collections::linked_list::LinkedList >),alloc::collections::linked_list::LinkedList > (*)()>,alloc::collections::linked_list::LinkedList > (*)(alloc::vec::Vec)>,alloc::vec::Vec (*)(),alloc::vec::Vec (*)(alloc::vec::Vec,dust::node::Node)>,dust::dir_walker::walk::closure_env$0> > >+0x98
dust`core::panic::unwind_safe::impl$23::call_once >,rayon_core::join::join_context::call_a::closure_env$0 >,rayon::iter::plumbing::bridge_unindexed_producer_consumer::closure_env$0,rayon::iter::filter_map::FilterMapConsumer > (*)(alloc::collections::linked_list::LinkedList >,alloc::collections::linked_list::LinkedList >),alloc::collections::linked_list::LinkedList > (*)()>,alloc::collections::linked_list::LinkedList > (*)(alloc::vec::Vec)>,alloc::vec::Vec (*)(),alloc::vec::Vec (*)(alloc::vec::Vec,dust::node::Node)>,dust::dir_walker::walk::closure_env$0> > > >+0x30
dust`std::panicking::try::do_call >,rayon::iter::plumbing::bridge_unindexed_producer_consumer::closure_env$0,rayon::iter::filter_map::FilterMapConsumer > (*)(alloc::collections::linked_list::LinkedList >,alloc::collections::linked_list::LinkedList >),alloc::collections::linked_list::LinkedList > (*)()>,alloc::collections::linked_list::LinkedList > (*)(alloc::vec::Vec)>,alloc::vec::Vec (*)(),alloc::vec::Vec (*)(alloc::vec::Vec,dust::node::Node)>,dust::dir_walker::walk::closure_env$0> > > >,alloc::collections::linked_list::LinkedList > >+0x5E
dust`std::panicking::try::do_catch,rayon::iter::collect::consumer::CollectResult >,rayon_core::registry::impl$6::in_worker_cold::closure$0::closure_env$0,rayon::iter::filter_map::FilterMapConsumer,dust::dir_walker::walk::closure_env$0> >,rayon::iter::plumbing::bridge_unindexed_producer_consumer::closure_env$1,rayon::iter::filter_map::FilterMapConsumer,dust::dir_walker::walk::closure_env$0> >,rayon::iter::collect::consumer::CollectResult,rayon::iter::collect::consumer::CollectResult >,tuple$,rayon::iter::collect::consumer::CollectResult > > > >,tuple$,rayon::iter::collect::consumer::CollectResult > >+0xD3
dust`std::panicking::try >,core::panic::unwind_safe::AssertUnwindSafe >,rayon::iter::plumbing::bridge_unindexed_producer_consumer::closure_env$0,rayon::iter::filter_map::FilterMapConsumer > (*)(alloc::collections::linked_list::LinkedList >,alloc::collections::linked_list::LinkedList >),alloc::collections::linked_list::LinkedList > (*)()>,alloc::collections::linked_list::LinkedList > (*)(alloc::vec::Vec)>,alloc::vec::Vec (*)(),alloc::vec::Vec (*)(alloc::vec::Vec,dust::node::Node)>,dust::dir_walker::walk::closure_env$0> > > > >+0x92
dust`std::panic::catch_unwind >,rayon::iter::plumbing::bridge_unindexed_producer_consumer::closure_env$0,rayon::iter::filter_map::FilterMapConsumer > (*)(alloc::collections::linked_list::LinkedList >,alloc::collections::linked_list::LinkedList >),alloc::collections::linked_list::LinkedList > (*)()>,alloc::collections::linked_list::LinkedList > (*)(alloc::vec::Vec)>,alloc::vec::Vec (*)(),alloc::vec::Vec (*)(alloc::vec::Vec,dust::node::Node)>,dust::dir_walker::walk::closure_env$0> > > >,alloc::collections::linked_list::LinkedList > >+0x30
dust`rayon_core::unwind::halt_unwinding >,rayon::iter::plumbing::bridge_unindexed_producer_consumer::closure_env$0,rayon::iter::filter_map::FilterMapConsumer > (*)(alloc::collections::linked_list::LinkedList >,alloc::collections::linked_list::LinkedList >),alloc::collections::linked_list::LinkedList > (*)()>,alloc::collections::linked_list::LinkedList > (*)(alloc::vec::Vec)>,alloc::vec::Vec (*)(),alloc::vec::Vec (*)(alloc::vec::Vec,dust::node::Node)>,dust::dir_walker::walk::closure_env$0> > >,alloc::collections::linked_list::LinkedList > >+0x4B
dust`rayon_core::join::join_context::closure$0,rayon::iter::filter_map::FilterMapConsumer > (*)(alloc::collections::linked_list::LinkedList >,alloc::collections::linked_list::LinkedList >),alloc::collections::linked_list::LinkedList > (*)()>,alloc::collections::linked_list::LinkedList > (*)(alloc::vec::Vec)>,alloc::vec::Vec (*)(),alloc::vec::Vec (*)(alloc::vec::Vec,dust::node::Node)>,dust::dir_walker::walk::closure_env$0> >,rayon::iter::plumbing::bridge_unindexed_producer_consumer::closure_env$1,rayon::iter::filter_map::FilterMapConsumer > (*)(alloc::collections::linked_list::LinkedList >,alloc::collections::linked_list::LinkedList >),alloc::collections::linked_list::LinkedList > (*)()>,alloc::collections::linked_list::LinkedList > (*)(alloc::vec::Vec)>,alloc::vec::Vec (*)+0x1F3
dust`rayon_core::registry::in_worker,rayon::iter::filter_map::FilterMapConsumer > (*)(alloc::collections::linked_list::LinkedList >,alloc::collections::linked_list::LinkedList >),alloc::collections::linked_list::LinkedList > (*)()>,alloc::collections::linked_list::LinkedList > (*)(alloc::vec::Vec)>,alloc::vec::Vec (*)(),alloc::vec::Vec (*)(alloc::vec::Vec,dust::node::Node)>,dust::dir_walker::walk::closure_env$0> >,rayon::iter::plumbing::bridge_unindexed_producer_consumer::closure_env$1,rayon::iter::filter_map::FilterMapConsumer > (*)(alloc::collections::linked_list::LinkedList >,alloc::collections::linked_list::LinkedList >),alloc::collections::linked_list::LinkedList > (*)()>,alloc::collections::linked_list::LinkedList > (*)(alloc::vec::Vec)>,alloc::vec::Vec,rayon::iter::filter_map::FilterMapConsumer > (*)(alloc::collections::linked_list::LinkedList >,alloc::collections::linked_list::LinkedList >),alloc::collections::linked_list::LinkedList > (*)()>,alloc::collections::linked_list::LinkedList > (*)(alloc::vec::Vec)>,alloc::vec::Vec (*)(),alloc::vec::Vec (*)(alloc::vec::Vec,dust::node::Node)>,dust::dir_walker::walk::closure_env$0> >,rayon::iter::plumbing::bridge_unindexed_producer_consumer::closure_env$1,rayon::iter::filter_map::FilterMapConsumer > (*)(alloc::collections::linked_list::LinkedList >,alloc::collections::linked_list::LinkedList >),alloc::collections::linked_list::LinkedList > (*)()>,alloc::collections::linked_list::LinkedList > (*)(alloc::vec::Vec)>,alloc::vec::Vec (*)(),alloc::v+0x5B
dust`rayon::iter::plumbing::bridge_unindexed_producer_consumer,rayon::iter::filter_map::FilterMapConsumer > (*)(alloc::collections::linked_list::LinkedList >,alloc::collections::linked_list::LinkedList >),alloc::collections::linked_list::LinkedList > (*)()>,alloc::collections::linked_list::LinkedList > (*)(alloc::vec::Vec)>,alloc::vec::Vec (*)(),alloc::vec::Vec (*)(alloc::vec::Vec,dust::node::Node)>,dust::dir_walker::walk::closure_env$0> >+0x54E
dust`rayon::iter::plumbing::bridge_unindexed_producer_consumer::closure$0,rayon::iter::filter_map::FilterMapConsumer > (*)(alloc::collections::linked_list::LinkedList >,alloc::collections::linked_list::LinkedList >),alloc::collections::linked_list::LinkedList > (*)()>,alloc::collections::linked_list::LinkedList > (*)(alloc::vec::Vec)>,alloc::vec::Vec (*)(),alloc::vec::Vec (*)(alloc::vec::Vec,dust::node::Node)>,dust::dir_walker::walk::closure_env$0> >+0xC5
dust`rayon_core::join::join_context::call_a::closure$0 >,rayon::iter::plumbing::bridge_unindexed_producer_consumer::closure_env$0,rayon::iter::filter_map::FilterMapConsumer > (*)(alloc::collections::linked_list::LinkedList >,alloc::collections::linked_list::LinkedList >),alloc::collections::linked_list::LinkedList > (*)()>,alloc::collections::linked_list::LinkedList > (*)(alloc::vec::Vec)>,alloc::vec::Vec (*)(),alloc::vec::Vec (*)(alloc::vec::Vec,dust::node::Node)>,dust::dir_walker::walk::closure_env$0> > >+0x98
dust`core::panic::unwind_safe::impl$23::call_once >,rayon_core::join::join_context::call_a::closure_env$0 >,rayon::iter::plumbing::bridge_unindexed_producer_consumer::closure_env$0,rayon::iter::filter_map::FilterMapConsumer > (*)(alloc::collections::linked_list::LinkedList >,alloc::collections::linked_list::LinkedList >),alloc::collections::linked_list::LinkedList > (*)()>,alloc::collections::linked_list::LinkedList > (*)(alloc::vec::Vec)>,alloc::vec::Vec (*)(),alloc::vec::Vec (*)(alloc::vec::Vec,dust::node::Node)>,dust::dir_walker::walk::closure_env$0> > > >+0x30
dust`std::panicking::try::do_call >,rayon::iter::plumbing::bridge_unindexed_producer_consumer::closure_env$0,rayon::iter::filter_map::FilterMapConsumer > (*)(alloc::collections::linked_list::LinkedList >,alloc::collections::linked_list::LinkedList >),alloc::collections::linked_list::LinkedList > (*)()>,alloc::collections::linked_list::LinkedList > (*)(alloc::vec::Vec)>,alloc::vec::Vec (*)(),alloc::vec::Vec (*)(alloc::vec::Vec,dust::node::Node)>,dust::dir_walker::walk::closure_env$0> > > >,alloc::collections::linked_list::LinkedList > >+0x5E
dust`std::panicking::try::do_catch,rayon::iter::collect::consumer::CollectResult >,rayon_core::registry::impl$6::in_worker_cold::closure$0::closure_env$0,rayon::iter::filter_map::FilterMapConsumer,dust::dir_walker::walk::closure_env$0> >,rayon::iter::plumbing::bridge_unindexed_producer_consumer::closure_env$1,rayon::iter::filter_map::FilterMapConsumer,dust::dir_walker::walk::closure_env$0> >,rayon::iter::collect::consumer::CollectResult,rayon::iter::collect::consumer::CollectResult >,tuple$,rayon::iter::collect::consumer::CollectResult > > > >,tuple$,rayon::iter::collect::consumer::CollectResult > >+0xD3
dust`std::panicking::try >,core::panic::unwind_safe::AssertUnwindSafe >,rayon::iter::plumbing::bridge_unindexed_producer_consumer::closure_env$0,rayon::iter::filter_map::FilterMapConsumer > (*)(alloc::collections::linked_list::LinkedList >,alloc::collections::linked_list::LinkedList >),alloc::collections::linked_list::LinkedList > (*)()>,alloc::collections::linked_list::LinkedList > (*)(alloc::vec::Vec)>,alloc::vec::Vec]