主要实现文件: bolt/lib/Passes/ReorderData.cpp
支持 X86/Arm
测试用例: bolt/test/reorder-data-writable-ptload.c
int a1,a2,a3,a4;
// 待补充
默认关闭,开启选项:
# 指定要重排的数据段
--reorder-data=<section1,section2,section3,...>
# 重排算法
--reorder-data-algo=count/funcs
# 重排后原地替换,暂不支持
--reorder-data-inplace
# 限制新的数据段的大小
--reorder-data-max-bytes=<uint> -- default std::numeric_limits<unsigned>::max()
# 限制新的数据段的符号数量
--reorder-data-max-symbols=<uint> -- default std::numeric_limits<unsigned>::max()
注: objdump -D 命令把 .data 段当成指令来解析了,看起来分成奇怪,我们只要看数据就行,这里想要展示的是常用的 .data 段数据被放到一起了,减少 dcache miss
void ReorderData::assignMemData(BinaryContext &BC) {
// 采样文件需要包含下面这种 Memory Profile
// 4 _start 0 4 hot1 0 100
// 查找包含 "MemoryAccessProfile" 注释的指令
BC.MIB->tryGetAnnotationAs<MemoryAccessProfile>(Inst, "MemoryAccessProfile");
/********************************
.LBB00:
00000000: incl hot1(%rip) # MemoryAccessProfile: 100 total counts :
{ hot1 + 0x0: 100 }
00000006: jmp .LBB00
preds: .LBB00
succs: .LBB00
********************************/
// 遍历指令访问的所有数据段
for (const AddressAccess &AccessInfo : MemAccessProfile.AddressAccessInfo) {
// 存储数据段的访问计数
BinaryDataCounts[BD->getAtomicRoot()] += AccessInfo.Count;
}
void ReorderData::runOnFunctions(BinaryContext &BC) {
// 必须指定要重排的数据段
if (!BC.HasRelocations || opts::ReorderData.empty())
// 不能与跳转表优化一起工作
if (opts::JumpTables > JTS_BASIC)
assignMemData(BC);
// 根据选项提供的名字找到实际 Section 地址
for (const std::string &SectionName : opts::ReorderData)
for (BinarySection *Section : Sections) {
// 检查 "PG." 开头的 Section 和 有重叠的 Section
// 当前私有符号无法移动,因为数据可能会在一个符号的边界之间"泄露"到另一个符号,例如,一个具有共同后缀的字符串可能从一个私有符号开始,并在另一个符号中以共同的后缀结尾
const bool FoundUnmoveable = markUnmoveableSymbols(BC, *Section);
std::tie(Order, SplitPointIdx) = sortedByCount(BC, *Section);
std::tie(Order, SplitPointIdx) = sortedByFunc(BC, *Section, BC.getBinaryFunctions());
setSectionOrder(BC, Hot, Order.begin(), SplitPoint);
}
遗留问题:
- 怎么产生内存相关的采样数据 - 检查了 mysql 的采样文件未发现这种数据
- 能否通过增强插桩生成这种数据