mcpField
R
rocprofiler-systems-instrumenting-binaries

rocprofiler-systems-instrumenting-binaries

github.com/amd开发482100 次安装2 天前更新
代码仓库

关于 rocprofiler-systems-instrumenting-binaries

此技能介绍如何使用 `rocprof-sys-instrument` 选择函数进行运行时插桩或二进制重写,帮助配置插桩范围、预览选择结果,并诊断函数被纳入或跳过的原因。

主要功能

  1. 01配置运行时或二进制重写插桩
  2. 02用模式筛选函数和模块
  3. 03预览已插桩与排除的函数
  4. 04调整大小阈值和循环插桩
  5. 05诊断插桩限制因素

适用场景

  1. 01为应用中的指定函数插桩
  2. 02重写二进制前预览插桩范围
  3. 03通过排除库或提高阈值降低开销
  4. 04排查函数未被插桩的原因

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/amd/skills --skill rocprofiler-systems-instrumenting-binaries

安装后在 Claude Code 中输入/rocprofiler-systems-instrumenting-binaries确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

.federated.json
skill-card.md
evals/
evals.json
machine.yml

详细介绍

插桩二进制

rocprof-sys-instrument 用于决定程序中哪些函数要进行插桩,并在程序运行时完成插桩,或写入新的插桩二进制文件。要查看完整的最新标志列表,请运行 rocprof-sys-instrument --help(查询单个标志时,使用 --help | grep -A3 -- --<flag>)。

如何作答

回答简短:除非用户要求更多内容,否则控制在约 1200 个字符以内。先给出直接答案和命令,然后只补充与问题相关的本技能注意事项(例如:二进制重写会跳过共享库、-MR 会忽略 -R、-l 需要搭配更小的 -i,以及如何使用 --print-available 列出模块)。不要提供用户未要求的替代方案或背景信息。

前提条件

  • rocprof-sys-instrument 和 rocprof-sys-run 位于 PATH 中;若不在,请运行 source <install-prefix>/share/rocprofiler-systems/setup-env.sh。
  • 尽可能使用 -g 构建目标:这样模块就是源文件,工具也能报告文件和行号信息。若没有调试信息,整个二进制文件会被视为一个以该二进制文件命名的模块。

运行时插桩与二进制重写

运行时插桩二进制重写
选择方式默认(不使用 -o)-o [<output>]
命令rocprof-sys-instrument [opts] -- ./app argsrocprof-sys-instrument [opts] -o app.inst -- ./app
插桩范围可执行文件及其加载的共享库仅目标自身的代码;不对共享库进行插桩
开销(上游建议)内存占用更高、设置较慢、运行时开销更大设置速度快得多,开销更低
是否运行应用是,立即运行,并传入 args否;稍后运行 rocprof-sys-run -- ./app.inst args
目标后面的参数传递给应用忽略(运行结果时再传入)
  • 如果关注应用所加载库的性能,请选择运行时插桩。
  • 如果追求最低开销、需要重复运行,或处理 MPI 应用,请选择二进制重写(上游建议)。
  • --exe-only(仅适用于运行时插桩)会排除所有共享库; --max-library-functions N 会跳过函数数量超过 N 的共享库 (默认值为 20000;0 表示禁用检查)。
  • 如果使用 -o 但未指定文件名,则会在当前目录下写入 <name>.inst(目标位于当前目录时),或写入 instrumented/<name>(目标为库时)。

函数与模块

  • 函数是一个符号,例如 big_a 或 Domain::BuildMesh。
  • 模块是函数定义所在的容器:二进制文件包含调试信息时,模块是其源文件(/path/mod_a.cpp);否则,模块就是二进制文件或库本身(/path/app)。运行时模式下,共享库会各自作为独立模块出现。
rocprof-sys-instrument --simulate -o app.inst --print-available modules   -- ./app
rocprof-sys-instrument --simulate -o app.inst --print-available functions -- ./app
rocprof-sys-instrument --simulate -o app.inst --print-available pair      -- ./app

pair 会为每个函数打印一行 [module] --> [function][#instructions]。 模块选项(-MI、-ME、-MR)会作用于匹配模块中的每个函数;函数选项(-I、-E、-R)则作用于单个函数。

包含、排除和限制

选项含义
-I / -MI(包含)强制包含这些项,即使大小启发式规则会跳过它们也一样。不会缩小其他范围。
-R / -MR(限制)仅检测匹配项,忽略大小启发式规则。
-E / -ME(排除)永不检测这些项。始终生效,且优先级高于包含和限制。

匹配规则(均已验证):

  • 模式是正则表达式,会在名称的任意位置匹配(子串匹配,不锚定)。tiny 会匹配 tiny_a 和 tiny_b;要精确匹配,请写 ^tiny_a$。
  • 一个选项后接多个模式时,按 OR 处理:-I tiny_a medium_b 等同于 -I 'tiny_a|medium_b'。
  • 模块模式匹配模块名称(源文件或二进制路径)。函数模式匹配函数名称;设置 --label args 时,也会匹配签名(因此,-I '\(long int\)$' 仅在同时使用 --label args 时有效)。
  • 任何级别的排除都优先于包含:-ME 'mod_' -I tiny_a 不会检测任何内容。
  • -MR mod_a 会检测 mod_a 中的所有函数,包括较小的函数和包含循环的函数,不受大小阈值影响。

注意:如果同时指定 --module-restrict 和 --function-restrict,函数限制会被静默忽略。-MR mod_a -R '^medium_b$' 会检测 mod_a 中的所有函数,而不是上游文档所述的并集。请使用其中一个,或将 -MR 与 -E 组合使用。

示例:

# Only one source file
rocprof-sys-instrument -o app.inst -MR 'solver\.cpp$' -- ./app
# Everything the heuristics pick, minus one noisy library
rocprof-sys-instrument -o app.inst -ME 'libm\.so' -- ./app
# Add a small function the heuristics skip
rocprof-sys-instrument -o app.inst -I '^small_helper$' -- ./app

试运行

试运行会显示将要检测的内容,但不会实际进行检测。

rocprof-sys-instrument --simulate [options] -- ./app
rocprof-sys-instrument --simulate -o app.inst --print-instrumented pair -- ./app
rocprof-sys-instrument --dump-info --simulate -o app.inst -- ./app

--simulate 的作用(已验证):

  • 分析后退出。它不会运行应用程序,也不会写入重写后的二进制文件,即使指定了 -o 也一样。
  • 输出每个模块的摘要(<module> 中检测了 N 个函数)。
  • 配合 --print-available、--print-instrumented、--print-excluded、--print-coverage 或 --print-overlapping 使用时,也会输出相应列表。每个选项都接受 functions、modules 或 pair;+ 形式(functions+、pair+)还会在使用 --label args 时显示函数签名。

--dump-info 的作用:

  • 将 available、instrumented、excluded 和 overlapping 报告以 .txt 和 .json 格式写入 rocprofsys-<name>-output/instrumentation/,其中 <name> 是目标(运行时)或 -o 输出名称(重写时,例如 rocprofsys-app.inst-output)。
  • --print-format json(或 txt)会限制输出格式。设置 ROCPROFSYS_OUTPUT_PATH 可更改目录位置。在测试的两个构建版本中,--print-dir 均无效果。
  • .txt 文件会列出地址、地址范围、指令数、链接属性、可见性、模块和函数。.json 文件还会包含每个函数的 heuristics 块(参见“为什么缺少某个函数?”)。
  • 未指定 --simulate 时,--dump-info 仍会照常生成重写后的二进制文件。

工作流:先试运行,查看 instrumented 和 excluded,调整正则表达式或阈值后重复试运行,然后移除 --simulate。

粒度

只有同时通过两项大小检查(经验证)的函数才会被插桩:

  • 至少有 --min-instructions 条指令(默认值为 1024),并且
  • 地址范围至少为 --min-address-range 字节(默认为指令数下限的 4 倍,即 4096)。

容易让人意外的交互行为:

  • 只指定 -i N 会将地址范围下限设为 0(只检查指令数);只指定 -r N 会将指令数下限设为 0。同时指定两者时,两项检查都会生效。因此,-i 0 或 -r 0 会禁用两项大小检查。但这不会为每个函数都插桩:函数仍须至少有 2 条指令、可由 Dyninst 插桩,并通过排除、重叠、陷阱、链接和可见性检查;此外,分析器自身或系统模块中的函数永远不会被选中。
  • 环境变量 ROCPROFSYS_DEFAULT_MIN_INSTRUCTIONS 会更改默认指令数下限,并同时更改默认地址范围下限。
  • 包含循环的函数使用 --min-instructions-loop 和 --min-address-range-loop,如果未设置,它们会沿用非循环函数对应的值。这些选项决定包含循环的函数是否会被插桩。
  • -l / --instrument-loops 还会为已插桩函数内部的循环插桩。在性能分析结果中,每个循环都会显示为一个子条目,名称包含其源代码范围,例如 loop_a [{449,54}-{449,83}];相应地,函数自身的自耗时会减少。

一个小型测试程序的示例(指令数:7、16、79、429、3657):

选项插桩的函数
默认仅 3657 条指令的函数
-i 100429 和 3657 条指令的函数
-i 2079、429 和 3657 条指令的函数
-i 0全部 5 个函数
-i 50 -r 1000429 和 3657 条指令的函数(79 条指令的函数仅有 278 字节)

详细程度越高,开销越大,跟踪数据也越多。降低阈值或添加 -l,以查看热点代码内部情况;提高阈值、限制模块范围,或使用 --exe-only 来降低开销。其他筛选条件(--dynamic-callsites、--traps、--loop-traps、--allow-overlapping、--linkage、--visibility)详见 --help。

为什么缺少某个函数,或者为什么数据太多?

缺少函数:

  1. 列出被跳过的函数:--simulate --print-excluded pair 或 --dump-info --simulate。
  2. 打开 excluded.json,找到该函数并查看其 heuristics 块 (should_instrument: false 就是判定结果)。字段分为两类,每类的成因对应不同的值。
    • 能力字段:false 是成因。 is_instrumentable、 can_instrument_entry 和 can_instrument_exit 为 false,表示 Dyninst 没有可用的函数入口或出口点。没有选项可以解决这个问题,因此只能接受这一缺失,或插桩其调用方。
    • 约束字段:true 是成因。
      • is_address_range_constrained、is_num_instructions_constrained(以及 is_loop_* 变体):范围太小。降低 -i/-r,或添加 -I。
      • is_user_excluded:你的某个 -E/-ME 模式与其匹配。
      • is_user_restricted:它与 -R/-MR 模式均不匹配。
      • is_overlapping_constrained:需要 --allow-overlapping。
      • is_entry_trap_constrained、is_exit_trap_constrained:需要 --traps。
      • is_linkage_constrained、is_visibility_constrained:参见 --linkage、--visibility。
      • is_internal_constrained:它属于分析器自身的库。
      • is_module_constrained:其模块属于分析器从不插桩的模块(系统库、Dyninst 或分析器自身的库)。
      • is_routine_constrained:其名称属于分析器从不插桩的名称。
    • 完全没有字段: 指令少于 2 条的函数总是会被跳过。 如果所有能力字段都为 true,且没有约束字段为 true,请检查 num_instructions(已验证:即使使用 -i 0,只有 1 条指令的函数仍会被排除)。
  3. 如果该函数位于共享库中,请记住,二进制重写无法看到它。

数据过多或速度太慢:提高 -i,将范围限制为你关注的模块 (-MR),排除产生噪声的模块(-ME),去掉 -l,或添加 --exe-only。

库、RPATH 和故障排除

重写共享库,使普通可执行文件加载插桩后的副本:

rocprof-sys-instrument -o ./app.inst -- ./app
mkdir inst && rocprof-sys-instrument -o inst/libfoo.so -- ./libfoo.so
LD_LIBRARY_PATH=$PWD/inst:$LD_LIBRARY_PATH rocprof-sys-run -- ./app.inst
ldd ./app.inst | grep libfoo      # must resolve into inst/
  • 重写后的库保留相同的文件名(libfoo.so,或 ldd 显示的 soname),并将其写入另一个目录。
  • RPATH 与 RUNPATH: 加载器会在 LD_LIBRARY_PATH 之前搜索 DT_RPATH 目录,因此,如果原始库位于某个 RPATH 目录中,加载的将是原始库,而不是重写后的副本。 如果 RPATH 目录中没有该库,仍会使用 LD_LIBRARY_PATH;而使用 RUNPATH 的二进制文件会先搜索 LD_LIBRARY_PATH。 使用 objdump -p <exe> | egrep 'RPATH|RUNPATH' 和 ldd 检查。只有当 ldd 显示的是原始库时,才修补二进制文件。使用 -Wl,--enable-new-dtags 重新链接,或使用 patchelf 更改条目: patchelf --remove-rpath <exe> 会让 LD_LIBRARY_PATH 优先,因此能解决问题;patchelf --set-rpath <dir> <exe> 会写入 RUNPATH,效果也相同。添加 --force-rpath 会保留 DT_RPATH,问题便会再次出现。
  • 将库作为运行时目标: rocprof-sys-instrument -- ./libfoo.so 会打印 "is not executable ... Switching to binary rewrite mode and assuming '--simulate --all-functions'",因此你得到的是一次试运行近似结果,不会实际运行。 -f/--force 仅适用于名称看起来像库的可执行文件;测试中,对真正的 .so 强制使用该选项会导致 Dyninst 内部中止。
  • 未找到主函数: 使用 -m <symbol>(或 --main-function)传入主函数。
  • "Failed to transform trace ... in function ''"(上游建议,尚未复现):添加 -E '<f>'。与其共享代码的函数仍可能将其带入;也排除这些函数,或使用 -ME 排除整个模块。

运行改写后的结果并嵌入默认值

  • 使用 rocprof-sys-run -- ./app.inst args 运行改写后的二进制文件;插桩函数随后会像其他函数一样出现在性能分析或跟踪结果中。
  • --env VAR=VALUE ... 会将默认值嵌入新二进制文件,因此后续会话无需导出这些值。运行时设置的变量仍会覆盖嵌入值(已使用 ROCPROFSYS_PROFILE 验证)。
  • --label args file line return 会将这些信息添加到函数名称中(例如,带有 args 时显示为 big_a(long int))。
  • -M sampling 只会对 main 进行插桩,以启动和停止采样器(已验证);此选项在上游已弃用。采样请使用 rocprof-sys-sample 或预设。

常见错误

错误修正方法
以为二进制文件改写会对共享库进行插桩它只覆盖目标自身的代码。请使用运行时模式,或也改写该库。
使用 -I 缩小选择范围-I 只会添加。请使用 -R/-MR 缩小范围,或使用 -E/-ME 排除。
写入 -I tiny 并期待精确匹配模式会匹配未锚定的子字符串。请使用 ^tiny_a$。
同时使用 -MR 和 -R函数限制会被忽略。请只使用其中一个,或使用 -MR 加 -E。
只降低 -i,却期待范围限制仍然生效只提供一个选项时,另一个会被设为 0。要同时应用两者,请同时传入。
改写时在目标后传入应用参数这些参数会被忽略;请将它们传给 rocprof-sys-run -- ./app.inst args。
将改写后的库放在带有 DT_RPATH 的二进制文件旁边LD_LIBRARY_PATH 会被忽略。请使用 objdump -p 检查,并重新链接或修补 rpath。
以为 --simulate -o 会生成二进制文件试运行只会写入报告;请移除 --simulate。
依赖 --print-dir在已测试的构建中,它没有效果;请使用 ROCPROFSYS_OUTPUT_PATH。

评论

支持 Markdown