> [!NOTE] > 本文档由 WeHub 基于上游 README 翻译整理,属于社区翻译,非官方中文文档。 > [English](./README.en.md) · [原始项目](https://github.com/janestreet/magic-trace) · [上游 README](https://github.com/janestreet/magic-trace/blob/HEAD/README.md) > 原作者、版权与许可证归属以原始项目及本仓库 LICENSE 文件为准。


magic-trace

# 概述 magic-trace 收集并展示进程正在执行内容的高分辨率追踪(trace)记录。人们用它来: - 查明为何生产环境中运行的应用在处理某些请求时很慢,同时又在应付海量无趣请求, - 看清代码*实际*在做什么,而不是*以为*它在做什么, - 获取应用崩溃前的执行历史,而不只是最后时刻的一张堆栈跟踪(stacktrace), - ……以及更多用途! magic-trace: - 具有 [2%-10% 开销](https://github.com/janestreet/magic-trace/wiki/Overhead), - 使用时不需修改应用, - 以约 40ns 分辨率追踪*每一次函数调用*,并且 - 渲染可回溯约 10ms(可配置)的调用栈时间线。 用法类似 [`perf`](https://en.wikipedia.org/wiki/Perf_(Linux)): 指向一个进程即可开始运行。与 `perf` 的关键区别在于:magic-trace 不是随时间对调用栈采样,而是使用 [Intel Processor Trace](https://man7.org/linux/man-pages/man1/perf-intel-pt.1.html) 对截至某一选定时刻的*全部控制流*环形缓冲区做快照[^1]。然后你可以交互式地浏览时间线上发生的事。 你可以让 magic-trace 盯住某个函数,这样当应用调用它时,magic-trace 就会拍一张快照。或者附加到正在运行的进程上,用 Ctrl+C 分离,以查看程序任意时刻的追踪记录。 [^1]:`perf` 也能做到这一点,但多数人并不这么用它。事实上,若深入底层,你会发现 magic-trace 使用 `perf` 来驱动 Intel PT。 # 用户评价 > "Magic-trace 是我用过的最简单的命令行调试工具之一。" - Francis Ricci, Jane Street > "Magic-trace 不仅用于性能分析。它能直接揭示程序中发生了什么、何时发生以及为何发生。建议为满足一切自省(introspective)目标时都考虑使用它!" - Andrew Hunter, Jane Street > 我经常用 perf,我认为 perf 和 magic-trace 各自提供了对方没有的视角。我从 magic-trace 获益,完全是因为它能在任意缩放级别下按切片展示,因此我能看到某个 70ns 函数执行的所有函数调用,而在 perf 中这些内容完全不可见。 - Doug Patti, Jane Street [更多用户评价……](https://github.com/janestreet/magic-trace/wiki/Unsolicited-reviews) # 安装 1. 确保要追踪的系统[受支持](https://github.com/janestreet/magic-trace/wiki/Supported-platforms,-programming-languages,-and-runtimes). 最容易让人栽跟头的限制是:虚拟机大多不受支持、仅支持 Intel(Skylake[^3] 或更新)、仅支持 Linux。 2. 从[最新发布页](https://github.com/janestreet/magic-trace/releases/latest). 获取发布版二进制文件。 1. 若下载的是预编译二进制文件(非软件包),`chmod +x magic-trace`[^4] 1. 若下载的是软件包,运行 `sudo dpkg -i magic-trace*.deb` 然后运行 `magic-trace -help` 进行测试,应会显示一些帮助文本。 [^3]:严格来说,任何比 Broadwell 更新的平台都可以,但我们不会定期在该平台上测试,且时间分辨率更差(约 1us)。 [^4]:https://github.com/actions/upload-artifact/issues/38 # 快速入门 1. [这里](https://raw.githubusercontent.com/janestreet/magic-trace/master/demo/demo.c)'s 有一份可供试用的示例 C 程序。它是 `man 3 dlopen` 中示例的轻微修改版。下载后,用 `gcc demo.c -ldl -o demo` 编译,再以 `./demo` 保持运行。我们将用该程序学习 `dlopen` 的用法。 2. 运行 `magic-trace attach -pid $(pidof demo)`。看到已成功附加的提示后,等待几秒,然后对 `magic-trace` 按 Ctrl+C。它会在当前工作目录输出名为 `trace.fxt.gz` 的文件。

3. 打开 [magic-trace.org](https://magic-trace.org/), 点击左上角的 _"Open trace file"_(打开追踪文件),并选择上一步生成的追踪文件。

4. 此时应已展开为一条追踪记录。放大直到能看到 `dlopen`/`dlsym`/`cos`/`printf`/`dlclose` 的单次循环。 - W 向鼠标光标所在位置放大(需要多次放大才能看到有用内容), - S 缩小, - A 向左移动, - D 向右移动,以及 - 滚轮在调用栈上下移动视口。只有查看特别深的堆栈跟踪时才需要滚动,对本示例可能用处不大。

5. 在调用栈周围的空白处点击拖动以进行测量。在时间线顶部点击可插旗标。使用测量工具,测量运行 `cos` 的耗时。在我的屏幕上约为 ~5.7us。

恭喜,你刚刚神奇地完成了第一次程序追踪! 与传统 `perf` 工作流相比,magic-trace 擅长生成假设。例如,你可能会注意到运行 `cos` 耗时 6us 实在太长了!若再放大,你会看到其中实际上有五个粉色的 "\[untraced\]" 单元格。若以 root 重新运行 magic-trace 并传入 `-trace-include-kernel`,就能看到它们的堆栈跟踪。它们是页错误(page fault)处理程序!演示程序实际上调用了 `cos` 两次。若在 6us 的 `cos` 调用末尾附近再放大,你会看到第二次调用耗时*远*更少且不会发生页错误。 # 使用方法 magic-trace 将持续把控制流记录到环形缓冲区。在某种触发条件下,它对缓冲区拍快照并重建调用栈。 有两种拍快照的方式: 我们刚才做的就是其中一种:Ctrl+C 结束 magic-trace。若 magic-trace 在未拍过快照的情况下终止,会对程序末尾拍一张快照。 你也可以在应用调用某个函数时触发快照。做法是向 magic-trace 传入 `-trigger` 标志。 - `-trigger '?'` 会弹出模糊查找选择器,让你从可执行文件中的所有符号里选择, - `-trigger SYMBOL` 选择你事先知道的某个具体、完整修饰(mangled)符号,以及 - `-trigger .` 选择默认符号 `magic_trace_stop_indicator`。 停止指示器(stop indicator)很强大。以下是一些你可能想放置它的场景: - 若使用异步运行时,可在调度器周期耗时过长时放置。 - 在服务器中,当某个请求耗时出奇地长时。 - 垃圾回收器运行之后,查看它在做什么以及它打断了什么。 - 某个编译器 pass 完成之后。 你可以把停止指示器留在生产代码中。它不必执行任何特定操作,magic-trace 只需要函数名。它只是一个空函数,但不会被内联。调用它大约耗费 ~10us,但*仅在 magic-trace 实际用它拍快照时*才会产生该开销。 # 文档 更多文档可在 [magic-trace wiki](https://github.com/janestreet/magic-trace/wiki). 上查阅。 # 讨论 加入我们的 [Discord](https://discord.gg/vkzPYeZ292) 进行实时交流,或前往 [GitHub 讨论组](https://github.com/janestreet/magic-trace/discussions) 进行异步讨论。 # 贡献 如果你想贡献代码: 1. [阅读构建说明](https://github.com/janestreet/magic-trace/wiki/Build-instructions), 1. [配置你的编辑器](https://ocaml.org/learn/tutorials/up_and_running.html#Editor-support-for-OCaml), 1. [快速浏览代码库](https://github.com/janestreet/magic-trace/wiki/A-quick-tour-of-the-codebase),,然后 1. [查看 issue 跟踪器](https://github.com/janestreet/magic-trace/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) 寻找合适的入门项目。 # 隐私政策 magic-trace 不会将你的代码或其衍生内容(包括 traces)发送到任何地方。 [magic-trace.org](https://magic-trace.org) 是 [Perfetto](https://github.com/janestreet/magic-trace/wiki/About-the-UI), 的轻度修改 fork,完全在浏览器中运行。据我们所知,它不会将 trace 发送到任何地方。如果你担心这一点日后可能改变,可以 [搭建本地 Perfetto UI 副本](https://github.com/janestreet/magic-trace/wiki/Setting-up-a-local-copy-of-the-UI) 并使用它。 # 致谢 [Tristan Hume](https://github.com/trishume) 是 magic-trace 的原始作者。他在 [Jane Street](https://www.janestreet.com/join-jane-street/), 工作期间编写了该项目,Jane Street 目前负责维护。 Intel PT(Intel Processor Trace)是 magic-trace 所依赖的基础技术。我们要感谢 Intel 的同仁多年来为使其可用所做的努力,尽管它在更广泛的软件社区中普及缓慢。 如果没有 `perf` 对 Intel PT 的广泛支持,magic-trace 就不可能存在。`perf` 承担了大部分解读 Intel PT 输出数据的工作,若没有他们的努力,magic-trace 很可能根本不会问世。感谢你们,`perf` 开发者。 [magic-trace.org](https://magic-trace.org) 是 [Perfetto](https://github.com/janestreet/magic-trace/wiki/About-the-UI), 的 fork,仅做了少量修改。我们要感谢 Google 负责该项目的同仁。这是一个高质量的代码库,很好地解决了一个难题。 magic-trace 背后的思想绝非独创。我们整理了一份 [先前工作](https://github.com/janestreet/magic-trace/wiki/Prior-art) 列表,记录了影响其设计的内容。