I'm trying to get a nice flamegraph of my Rust code. Unfortunately, Xcode 8.3 doesn't support exporting profiling data anymore, so I've been trying to use DTrace to get the profiling data.
I have enabled debug info in my Cargo.toml
for the release binaries:
[profile.release]
debug = true
Then I run the release binary (mybinaryname
), and sample stack traces using DTrace:
sudo dtrace -n 'profile-997 /execname == "mybinaryname"/ { @[ustack(100)] = count(); }' -o out.user_stacks
The end result is something like this:
0x10e960500
0x10e964632
0x10e9659e0
0x10e937edd
0x10e92aae2
0x10e92d0d7
0x10e982c8b
0x10e981fc1
0x7fff93c70235
0x1
1
For comparison, getting traces of iTerm2
gets me nice traces like this:
CoreFoundation`-[__NSArrayM removeAllObjects]
AppKit`_NSGestureRecognizerUpdate+0x769
CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__+0x17
CoreFoundation`__CFRunLoopDoObservers+0x187
CoreFoundation`__CFRunLoopRun+0x4be
CoreFoundation`CFRunLoopRunSpecific+0x1a4
HIToolbox`RunCurrentEventLoopInMode+0xf0
HIToolbox`ReceiveNextEventCommon+0x1b0
HIToolbox`_BlockUntilNextEventMatchingListInModeWithFilter+0x47
AppKit`_DPSNextEvent+0x460
AppKit`-[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:]+0xaec
AppKit`-[NSApplication run]+0x39e
AppKit`NSApplicationMain+0x4d5
iTerm2`main+0x6e
libdyld.dylib`start+0x1
iTerm2`0x1
1
Is it possible to get stack traces with debug info in Rust code? (Xcode's Instruments for sure can see the function names, so they are there!) If it is possible, do I need to do take some additional steps, or am I just doing something wrong?
I found a workaround and got some insight why it might not have worked, but the reason why is not 100% clear.
The debug symbols that rustc
produces can be found in target/release/deps/mybinaryname-hashcode.dSYM
. In the same directory there is a binary file target/release/deps/mybinaryname-hashcode
to which the symbols correspond to.
The debug symbol finding library on MacOS is highly magical – as is mentioned in the LLDB docs, symbols are found using various methods, including Spotlight search. I'm not even sure which Frameworks are the ones being used by Xcode's Instruments and the bundled DTrace. (There are mentions about frameworks called DebugSymbols.framework and CoreSymbolication.framework.) Because of this magic, I gave up trying to understand why didn't it work.
The workaround is to pass dtrace
the -p
option along with the PID of the inspected process:
sudo dtrace -p $PID -n 'profile-997 /pid == '$PID'/ { @[ustack(100)] = count(); }' -o $TMPFILE &>/dev/null
Here's the man
of -p
:
Grab the specified process-ID pid, cache its symbol tables, and exit upon its completion. If more than one -p option is present on the command line, dtrace exits when all commands have exited, reporting the exit status for each process as it terminates. The first process-ID is made available to any D programs specified on the command line or using the -s option through the $target macro variable.
It's not clear why the debug info of various other binaries is shown by default, or why Rust binaries need the -p
option, but it does its job as a workaround.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With