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

Gol*_*nks 5 macos profiling dtrace stack-trace rust

我正在尝试获取Rust代码的漂亮火焰图.不幸的是,Xcode 8.3不再支持导出分析数据了,所以我一直在尝试使用DTrace来获取分析数据.

我在我Cargo.toml的发布二进制文件中启用了调试信息:

[profile.release]
debug = true
Run Code Online (Sandbox Code Playgroud)

然后我运行发布二进制文件(mybinaryname),并使用DTrace示例堆栈跟踪:

sudo dtrace -n 'profile-997 /execname == "mybinaryname"/ { @[ustack(100)] = count(); }' -o out.user_stacks
Run Code Online (Sandbox Code Playgroud)

最终结果是这样的:

          0x10e960500
          0x10e964632
          0x10e9659e0
          0x10e937edd
          0x10e92aae2
          0x10e92d0d7
          0x10e982c8b
          0x10e981fc1
          0x7fff93c70235
          0x1
            1
Run Code Online (Sandbox Code Playgroud)

为了比较,得到的痕迹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
Run Code Online (Sandbox Code Playgroud)

是否可以在Rust代码中获得带有调试信息的堆栈跟踪?(Xcode的仪器肯定可以看到功能名称,所以它们就在那里!)如果可能的话,我是否需要采取一些额外的步骤,或者我只是做错了什么?

Gol*_*nks 5

我找到了一种解决方法,并获得了一些理解,为什么它可能不起作用,但是原因不是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
Run Code Online (Sandbox Code Playgroud)

下面是man-p

抓取指定的进程ID pid,缓存其符号表,并在完成时退出。如果命令行上存在多个-p选项,则dtrace将在所有命令退出后退出,并在每个进程终止时报告退出状态。第一个进程ID可用于命令行上指定的任何D程序,或通过$ target宏变量使用-s选项。

目前尚不清楚为什么默认情况下会显示各种其他二进制文件的调试信息,或者为什么Rust二进制文件需要该-p选项,但是它可以作为一种解决方法。