我正在尝试获取 Rust 代码的漂亮火焰图。不幸的是,Xcode 8.3 不再支持导出分析数据,所以我一直在尝试使用 DTrace 来获取分析数据。
我已在我的
Cargo.toml
中为发布二进制文件启用了调试信息:
[profile.release]
debug = true
然后我运行发布二进制文件 (
mybinaryname
),并使用 DTrace 示例堆栈跟踪:
sudo dtrace -n 'profile-997 /execname == "mybinaryname"/ { @[ustack(100)] = count(); }' -o out.user_stacks
最终结果是这样的:
0x10e960500
0x10e964632
0x10e9659e0
0x10e937edd
0x10e92aae2
0x10e92d0d7
0x10e982c8b
0x10e981fc1
0x7fff93c70235
0x1
1
为了比较,获取
iTerm2
的痕迹可以让我得到像这样的漂亮痕迹:
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
是否可以在 Rust 代码中获取带有调试信息的堆栈跟踪? (Xcode 的 Instruments 肯定可以看到函数名称,所以它们就在那里!)如果可能的话,我是否需要采取一些额外的步骤,或者我只是做错了什么?
我找到了一个解决方法,并了解了为什么它可能不起作用,但原因并不是 100% 清楚。
rustc
生成的调试符号可以在target/release/deps/mybinaryname-hashcode.dSYM
中找到。在同一目录中有一个二进制文件 target/release/deps/mybinaryname-hashcode
与符号对应。
MacOS 上的调试符号查找库非常神奇 - 正如 LLDB 文档中提到的那样,可以使用各种方法找到符号,包括 Spotlight 搜索。我什至不确定 Xcode 的 Instruments 和捆绑的 DTrace 使用的是哪些框架。 (其中提到了名为 DebugSymbols.framework 和 CoreSymbolication.framework 的框架。)由于这种魔力,我放弃了尝试理解为什么它不起作用。
解决方法是传递dtrace
-p
选项以及所检查进程的 PID:
sudo dtrace -p $PID -n 'profile-997 /pid == '$PID'/ { @[ustack(100)] = count(); }' -o $TMPFILE &>/dev/null
这是
man
的
-p
:
获取指定的进程ID pid,缓存其符号表,完成后退出。如果命令行上存在多个 -p 选项,则 dtrace 将在所有命令退出后退出,并在每个进程终止时报告其退出状态。第一个进程 ID 可用于在命令行上指定或通过 $target 宏变量使用 -s 选项的任何 D 程序。尚不清楚为什么默认情况下会显示各种其他二进制文件的调试信息,或者为什么 Rust 二进制文件需要
-p
选项,但它作为一种解决方法发挥了作用。
--release
模式下编译时,Rust 默认会去除调试符号。 这使得在探查器中检查代码变得更加困难。 (您会看到与cargo-flamegraph 类似的内容,它在 mac 上使用 dtrace。) 我所做的事情,由
samply 推荐,是设置一个自定义编译器配置文件,即有效的“释放”+调试符号。
# for use with perf-analysis tools like `samply`
[profile.profiling]
inherits = "release"
debug = true
此外,如果您使用的是 Mac,那么 Instruments 非常有用,并且基于 dtrace 构建。 (这是我最近才发现的东西,除了它非常有前途并且几乎肯定值得使用之外,没有强烈的评论。)