跳到主要内容

V8 的 Linux `perf` 集成

V8 内置支持 Linux perf 工具。可通过 --perf-prof 命令行选项启用。 V8 在代码执行期间写出性能数据到文件,可用于通过 Linux perf 工具分析 V8 的 JIT 编译代码(包括 JS 函数名称)的性能。

要求

  • linux-perf 版本需为 5 或更高(之前的版本不支持 JIT)。(参考末尾的说明)
  • 使用 enable_profiling=true 构建 V8/Chrome,以提供更好地符号化 C++ 代码。

构建 V8

要使用 V8 的 Linux perf 集成,需使用 enable_profiling = true gn 标志构建它:

echo 'enable_profiling = true' >> out/x64.release/args.gn
autoninja -C out/x64.release

使用 linux-perf-d8.pyd8 进行分析

构建 d8 后,即可开始使用 Linux perf:

tools/profiling/linux-perf-d8.py out/x64.release/d8 path/to/test.js;

更完整的示例:

echo '(function f() {
var s = 0; for (var i = 0; i < 1000000000; i++) { s += i; } return s;
})();' > test.js;

# 使用自定义 V8 标志并使用单独的输出目录以减少杂乱:
mkdir perf_results
tools/profiling/linux-perf-d8.py --perf-data-dir=perf_results \
out/x64.release/d8 --expose-gc --allow-natives-syntax test.js;

# 高级用户界面(`-flame` 仅限 Googler 使用,公共替代选项为 `-web`):
pprof -flame perf_results/XXX_perf.data.jitted;
# 基于终端的工具:
perf report -i perf_results/XXX_perf.data.jitted;

查看 linux-perf-d8.py --help 了解更多详情。注意,在 d8 二进制参数后可使用所有 d8 标志。

使用 linux-perf-chrome.py 对 Chrome 或 content_shell 进行分析

  1. 可以使用 linux-perf-chrome.py 脚本对 Chrome 进行分析。请确保添加所需的 Chrome gn 标志,以获得正确的 C++ 符号。

  2. 构建完成后,可以同时为 C++ 和 JS 代码启用完整符号,分析网站性能。

    mkdir perf_results;
    tools/profiling/linux-perf-chrome.py out/x64.release/chrome \
    --perf-data-dir=perf_results --timeout=30
  3. 浏览到您的网站,然后关闭浏览器(或等待 --timeout 完成)

  4. 退出浏览器后,linux-perf.py 会完成文件后处理,并显示每个渲染器进程的结果文件列表:

    chrome_renderer_1583105_3.perf.data.jitted      19.79MiB
    chrome_renderer_1583105_2.perf.data.jitted 8.59MiB
    chrome_renderer_1583105_4.perf.data.jitted 0.18MiB
    chrome_renderer_1583105_1.perf.data.jitted 0.16MiB

解析 Linux perf 结果

最后,可以使用 Linux perf 工具探索 d8 或 Chrome 渲染器进程的性能数据:

perf report -i perf_results/XXX_perf.data.jitted

还可以使用 pprof 生成更多可视化内容:

# 注意:`-flame` 仅限 Google 内部使用,公共替代选项为 `-web`:
pprof -flame perf_results/XXX_perf.data.jitted;

底层 Linux perf 使用方式

直接使用 Linux perf 分析 d8

根据具体使用场景,您可能希望直接使用 Linux perf 分析 d8。 这需要两步完成:首先使用 perf record 创建一个 perf.data 文件,然后使用 perf inject 后处理文件以注入 JS 符号。

perf record --call-graph=fp --clockid=mono --freq=max \
--output=perf.data
out/x64.release/d8 \
--perf-prof --no-write-protect-code-memory \
--interpreted-frames-native-stack \
test.js;
perf inject --jit --input=perf.data --output=perf.data.jitted;
perf report --input=perf.data.jitted;

V8 Linux perf 标志

--perf-prof 用于 V8 命令行以记录 JIT 代码中的性能样本。

--nowrite-protect-code-memory 用于禁用代码内存的写保护。这是必要的,因为当 perf 看到相应事件将写位从代码页移除时,它会丢弃关于代码页的信息。以下是从测试 JavaScript 文件记录样本的示例:

--interpreted-frames-native-stack 用于为解释型函数创建不同的入口点(InterpreterEntryTrampoline 的复制版本),以便基于地址仅用 perf 来区分它们。由于需要复制 InterpreterEntryTrampoline,因此会带来轻微的性能和内存回退。

直接在 Chrome 中使用 linux-perf

  1. 您可以使用相同的 V8 标志来分析 Chrome 本身。按照上面的说明使用正确的 V8 标志,并将 所需的 Chrome gn 标志 添加到您的 Chrome 构建中。

  2. 一旦构建完成,您就可以使用完整的 C++ 和 JS 代码符号来分析网站。

    out/x64.release/chrome \
    --user-data-dir=`mktemp -d` \
    --no-sandbox --incognito --enable-benchmarking \
    --js-flags='--perf-prof --no-write-protect-code-memory --interpreted-frames-native-stack'
  3. 启动 Chrome 后,使用任务管理器找到渲染器进程 ID,并使用它开始分析:

    perf record -g -k mono -p $RENDERER_PID -o perf.data
  4. 浏览您的网站,然后继续下一部分,了解如何评估 perf 输出。

  5. 执行完成后,将从 perf 工具收集的静态信息与 V8 为 JIT 代码输出的性能样本结合:

    perf inject --jit --input=perf.data --output=perf.data.jitted
  6. 最后,您可以使用 Linux 的 perf 工具来探索

构建 perf

如果您使用的是过时的 Linux 内核,可以在本地构建支持 JIT 的 linux-perf。

  • 安装新的 Linux 内核,然后重启您的计算机:

     sudo apt-get install linux-generic-lts-wily;
  • 安装依赖项:

    sudo apt-get install libdw-dev libunwind8-dev systemtap-sdt-dev libaudit-dev \
    libslang2-dev binutils-dev liblzma-dev;
  • 下载包含最新 perf 工具源代码的内核源文件:

    cd some/directory;
    git clone --depth 1 git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git;
    cd tip/tools/perf;
    make

在接下来的步骤中,将 perf 调用为 some/director/tip/tools/perf/perf