源码和二进制插桩
【摘要】 先上表:Sanitizer 类插桩BOLT 插桩操作对象源码已编译好的二进制何时插桩编译期编译之后、运行之前需要源码吗需要不需要典型工具ASan / TSan / MSanllvm-bolt -instrumentSanitizer 是源码级插桩:编译器在生成代码时,往每个函数入口、每个内存访问前后插入检查逻辑,然后重新编译。所以你必须有源码。BOLT 是二进制级插桩:拿到的已经是编译好的 ...
先上表:
| Sanitizer 类插桩 | BOLT 插桩 | |
|---|---|---|
| 操作对象 | 源码 | 已编译好的二进制 |
| 何时插桩 | 编译期 | 编译之后、运行之前 |
| 需要源码吗 | 需要 | 不需要 |
| 典型工具 | ASan / TSan / MSan | llvm-bolt -instrument |
Sanitizer 是源码级插桩:编译器在生成代码时,往每个函数入口、每个内存访问前后插入检查逻辑,然后重新编译。所以你必须有源码。
BOLT 是二进制级插桩:拿到的已经是编译好的 ELF 文件(如mysqld),BOLT 直接读它的机器码,在每条分支指令处插入计数逻辑,生成一个新的二进制(mysqld.inst)。整个过程不碰源码。
BOLT 具体怎么做
- 读二进制:解析 ELF,找到所有基本块和分支指令。
- 插入计数代码:在每个基本块入口或分支处,写一段额外的机器码,用来记录"这个块被执行了多少次"“这条分支跳去了哪里”。这些计数数据写到一块单独的内存区域。
- 生成新二进制:
mysqld.inst体积比原版大,运行也慢一些,但它会在退出时把计数数据写进.fdata文件。 - 跑负载:正常运行
mysqld.inst,它一边干活一边计数。 - 优化:BOLT 读
.fdata,知道哪些块热、哪些分支常走,再对原始二进制做重排,生成最终优化版。
为什么它能做到不改源码
因为机器码本身携带了足够的信息:函数边界、基本块划分、跳转指令的目标地址,都在 ELF 的符号表和指令流里。BOLT 不需要知道"这行 C 代码是什么意思",它只需要知道"这条 b.eq 跳去了哪个地址,那个地址被执行了多少次"。
这也是 BOLT 相比 PGO 的独特之处:PGO (Profile-Guided Optimization,剖面引导优化)是源码级/编译期优化,BOLT 是二进制级/链接后优化。两者可以叠加,比如先 PGO 编译,再用 BOLT 对产物二次重排。
鲲鹏场景
Sanitizer 改源码,BOLT 改二进制。在鲲鹏 920 假设没有 BRBE 的情况下,那就用软件来帮忙,这种二进制级插桩恰好绕开了硬件限制——不需要硬件帮忙记录分支,BOLT 自己在代码里埋计数器。代价就是插桩版跑得慢一些,且只适合离线采集 Profile,不能直接上生产。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)