Skip to content

Commit d5a5aaa

Browse files
[BOLT] Fix heatmaps on large BOLTE'd binaries.
Large binaries get two text segments mapped when loaded in memory. BOLT processes only the first, which is not having a correct BaseAddress, causing a wrong computation of a BinaryMMapInfo's size. Consequently, BOLT wrongly thinks that many of the samples fall outside the binary and ignores them. As a result, the computed heatmap is incomplete, and the section hotness statistics are wrong. This bug is present in both the AArch64 and x86 backends. --- This patch introduces flag 'perf-script-events' that allows passing perf events without BOLT having to parse them using 'perf script'. The flag is used to pass a mock perf profile that has two memory mappings for a mock binary that has two text segments. The size of the mapping is updated as `parseMMapEvents` now processes all text segments. --- Example used in unit tests: From `/proc/<BINARY PID>/maps`, we have 2 text mappings, say A and B. ``` abc0000000-abc1000000 r-xp 011c0000 103:01 1573523 BINARY abc2000000-abca000000 r-xp 031d0000 103:01 1573523 BINARY ``` Size of text mappings: | Mapping | Size | | ------- | ------ | | A | ~15MB | | B | ~135MB | --- Example on a real program: ``` 2f7200000-2fabca000 r--p 00000000 bolted-binary 2fabd9000-2fe47c000 r-xp 039c9000 bolted-binary <- 1st txt segment 2fe48b000-2fe61d000 r--p 0727b000 bolted-binary 2fe62c000-2fe660000 rw-p 0740c000 bolted-binary 2fe660000-2fea4c000 rw-p 00000000 2fec00000-303dad000 r-xp 07a00000 bolted-binary <- 2nd (appears only on the bolted binary) ```
1 parent 505e186 commit d5a5aaa

File tree

1 file changed

+8
-11
lines changed

1 file changed

+8
-11
lines changed

bolt/lib/Profile/DataAggregator.cpp

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2017,15 +2017,6 @@ std::error_code DataAggregator::parseMMapEvents() {
20172017
if (FileMMapInfo.first == "(deleted)")
20182018
continue;
20192019

2020-
// Consider only the first mapping of the file for any given PID
2021-
auto Range = GlobalMMapInfo.equal_range(FileMMapInfo.first);
2022-
bool PIDExists = llvm::any_of(make_range(Range), [&](const auto &MI) {
2023-
return MI.second.PID == FileMMapInfo.second.PID;
2024-
});
2025-
2026-
if (PIDExists)
2027-
continue;
2028-
20292020
GlobalMMapInfo.insert(FileMMapInfo);
20302021
}
20312022

@@ -2076,12 +2067,18 @@ std::error_code DataAggregator::parseMMapEvents() {
20762067
<< " using file offset 0x" << Twine::utohexstr(MMapInfo.Offset)
20772068
<< ". Ignoring profile data for this mapping\n";
20782069
continue;
2079-
} else {
2080-
MMapInfo.BaseAddress = *BaseAddress;
20812070
}
2071+
MMapInfo.BaseAddress = *BaseAddress;
20822072
}
20832073

2074+
// Try to add MMapInfo to the map and update its size. Large binaries
2075+
// may span multiple text segments, so the mapping is inserted only on the
2076+
// first occurrence. If a larger section size is found, it will be updated.
20842077
BinaryMMapInfo.insert(std::make_pair(MMapInfo.PID, MMapInfo));
2078+
uint64_t EndAddress = MMapInfo.MMapAddress + MMapInfo.Size;
2079+
uint64_t Size = EndAddress - BinaryMMapInfo[MMapInfo.PID].BaseAddress;
2080+
if (Size > BinaryMMapInfo[MMapInfo.PID].Size)
2081+
BinaryMMapInfo[MMapInfo.PID].Size = Size;
20852082
}
20862083

20872084
if (BinaryMMapInfo.empty()) {

0 commit comments

Comments
 (0)