使用 DTrace 获取 Rust 上的堆栈跟踪/分析数据

问题描述 投票:0回答:2

我正在尝试获取 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 肯定可以看到函数名称,所以它们就在那里!)如果可能的话,我是否需要采取一些额外的步骤,或者我只是做错了什么?

macos rust profiling stack-trace dtrace
2个回答
6
投票

我找到了一个解决方法,并了解了为什么它可能不起作用,但原因并不是 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

 选项,但它作为一种解决方法发挥了作用。


0
投票

--release

 模式下编译时,Rust 默认会去除调试符号。  这使得在探查器中检查代码变得更加困难。  (您会看到与 
cargo-flamegraph 类似的内容,它在 mac 上使用 dtrace。)

我所做的事情,由

samply 推荐,是设置一个自定义编译器配置文件,即有效的“释放”+调试符号。

# for use with perf-analysis tools like `samply` [profile.profiling] inherits = "release" debug = true
此外,如果您使用的是 Mac,那么 

Instruments 非常有用,并且基于 dtrace 构建。 (这是我最近才发现的东西,除了它非常有前途并且几乎肯定值得使用之外,没有强烈的评论。)

© www.soinside.com 2019 - 2024. All rights reserved.