关于 rocprofiler-systems-instrumenting-binaries
此技能介绍如何使用 `rocprof-sys-instrument` 选择函数进行运行时插桩或二进制重写,帮助配置插桩范围、预览选择结果,并诊断函数被纳入或跳过的原因。
主要功能
- 01配置运行时或二进制重写插桩
- 02用模式筛选函数和模块
- 03预览已插桩与排除的函数
- 04调整大小阈值和循环插桩
- 05诊断插桩限制因素
适用场景
- 01为应用中的指定函数插桩
- 02重写二进制前预览插桩范围
- 03通过排除库或提高阈值降低开销
- 04排查函数未被插桩的原因
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ amd/ skills --skill rocprofiler-systems-instrumenting-binaries安装后在 Claude Code 中输入/rocprofiler-systems-instrumenting-binaries确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
.federated.jsonskill-card.mdevals/evals.jsonmachine.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 args | rocprof-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 100 | 429 和 3657 条指令的函数 |
-i 20 | 79、429 和 3657 条指令的函数 |
-i 0 | 全部 5 个函数 |
-i 50 -r 1000 | 429 和 3657 条指令的函数(79 条指令的函数仅有 278 字节) |
详细程度越高,开销越大,跟踪数据也越多。降低阈值或添加 -l,以查看热点代码内部情况;提高阈值、限制模块范围,或使用 --exe-only 来降低开销。其他筛选条件(--dynamic-callsites、--traps、--loop-traps、--allow-overlapping、--linkage、--visibility)详见 --help。
为什么缺少某个函数,或者为什么数据太多?
缺少函数:
- 列出被跳过的函数:
--simulate --print-excluded pair或--dump-info --simulate。 - 打开
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 条指令的函数仍会被排除)。
- 能力字段:false 是成因。
- 如果该函数位于共享库中,请记住,二进制重写无法看到它。
数据过多或速度太慢:提高 -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。 |