[llvm] [BOLT] Match mmap events by build id (PR #229596)

via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 6 15:49:26 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-bolt

Author: Fabian Parzefall (pzfl)

<details>
<summary>Changes</summary>

Profiling on a host running two versions of the target binary with `perf -a` might result in a profile containing mmap events from the desired target and the second copy of that binary. In this case, perf2bolt will attribute samples from both processes to the target binary. Match by build id to filter samples.

---
Full diff: https://github.com/llvm/llvm-project/pull/229596.diff


3 Files Affected:

- (modified) bolt/include/bolt/Profile/DataAggregator.h (+4-2) 
- (modified) bolt/lib/Profile/DataAggregator.cpp (+40-23) 
- (modified) bolt/unittests/Profile/DataAggregator.cpp (+79) 


``````````diff
diff --git a/bolt/include/bolt/Profile/DataAggregator.h b/bolt/include/bolt/Profile/DataAggregator.h
index fde7187973edde..710a61f19e3407 100644
--- a/bolt/include/bolt/Profile/DataAggregator.h
+++ b/bolt/include/bolt/Profile/DataAggregator.h
@@ -100,6 +100,7 @@ class DataAggregator : public DataReader {
   friend struct PerfSpeEventsTestHelper;
   friend struct PreAggregatedTestHelper;
   friend struct PerfScriptTestHelper;
+  friend struct MMapEventsTestHelper;
 
   struct PerfBranchSample {
     SmallVector<LBREntry, 32> LBR;
@@ -393,8 +394,9 @@ class DataAggregator : public DataReader {
   /// Parse a single line of a PERF_RECORD_MMAP2 event looking for a mapping
   /// between the binary name and its memory layout in a process with a given
   /// PID.
-  /// On success return a <FileName, MMapInfo> pair.
-  ErrorOr<std::pair<StringRef, MMapInfo>> parseMMapEvent();
+  /// On success return a <FileName, BuildId, MMapInfo> pair. BuildId may be
+  /// empty.
+  ErrorOr<std::tuple<StringRef, StringRef, MMapInfo>> parseMMapEvent();
 
   /// Parse PERF_RECORD_FORK event.
   std::optional<ForkInfo> parseForkEvent();
diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp
index dc9ea2719e3151..ca1c18dcaadd3b 100644
--- a/bolt/lib/Profile/DataAggregator.cpp
+++ b/bolt/lib/Profile/DataAggregator.cpp
@@ -90,11 +90,11 @@ static cl::opt<bool> ImputeTraceFallthrough(
     cl::desc("impute missing fall-throughs for branch-only traces"),
     cl::cat(AggregatorCategory));
 
-static cl::opt<bool>
-IgnoreBuildID("ignore-build-id",
-  cl::desc("continue even if build-ids in input binary and perf.data mismatch"),
-  cl::init(false),
-  cl::cat(AggregatorCategory));
+cl::opt<bool> IgnoreBuildID(
+    "ignore-build-id",
+    cl::desc(
+        "continue even if build-ids in input binary and perf.data mismatch"),
+    cl::init(false), cl::cat(AggregatorCategory));
 
 static cl::opt<bool> IgnoreInterruptLBR(
     "ignore-interrupt-lbr",
@@ -2222,7 +2222,7 @@ std::optional<DataAggregator::ForkInfo> DataAggregator::parseForkEvent() {
   return FI;
 }
 
-ErrorOr<std::pair<StringRef, DataAggregator::MMapInfo>>
+ErrorOr<std::tuple<StringRef, StringRef, DataAggregator::MMapInfo>>
 DataAggregator::parseMMapEvent() {
   while (checkAndConsumeFS()) {
   }
@@ -2240,7 +2240,7 @@ DataAggregator::parseMMapEvent() {
   size_t Pos = Line.find("PERF_RECORD_MMAP2");
   if (Pos == StringRef::npos) {
     consumeRestOfLine();
-    return std::make_pair(StringRef(), ParsedInfo);
+    return std::make_tuple(StringRef(), StringRef(), ParsedInfo);
   }
 
   // Line:
@@ -2254,12 +2254,13 @@ DataAggregator::parseMMapEvent() {
   Line = Line.drop_front(Pos);
 
   // Line:
-  //   PERF_RECORD_MMAP2 <pid>/<tid>: [<hexbase>(<hexsize>) .*]: .* <file_name>
+  //   PERF_RECORD_MMAP2 <pid>/<tid>: [<hexbase>(<hexsize>) @ <hexoffset>
+  //   \<<buildid>\>]: .* <file_name>
 
   StringRef FileName = Line.rsplit(FieldSeparator).second;
   if (FileName.starts_with("//") || FileName.starts_with("[")) {
     consumeRestOfLine();
-    return std::make_pair(StringRef(), ParsedInfo);
+    return std::make_tuple(StringRef(), StringRef(), ParsedInfo);
   }
   FileName = sys::path::filename(FileName);
 
@@ -2292,9 +2293,11 @@ DataAggregator::parseMMapEvent() {
     return make_error_code(llvm::errc::io_error);
   }
 
+  const StringRef BuildId = Line.split('<').second.split('>').first;
+
   consumeRestOfLine();
 
-  return std::make_pair(FileName, ParsedInfo);
+  return std::make_tuple(FileName, BuildId, ParsedInfo);
 }
 
 std::error_code DataAggregator::parseMMapEvents() {
@@ -2303,26 +2306,30 @@ std::error_code DataAggregator::parseMMapEvents() {
                      TimerGroupDesc, opts::TimeAggregator);
 
   std::multimap<StringRef, MMapInfo> GlobalMMapInfo;
+  std::multimap<StringRef, MMapInfo *> BuildIdMMapInfo;
   while (hasData()) {
-    ErrorOr<std::pair<StringRef, MMapInfo>> FileMMapInfoRes = parseMMapEvent();
+    ErrorOr<std::tuple<StringRef, StringRef, MMapInfo>> FileMMapInfoRes =
+        parseMMapEvent();
     if (std::error_code EC = FileMMapInfoRes.getError())
       return EC;
 
-    std::pair<StringRef, MMapInfo> FileMMapInfo = FileMMapInfoRes.get();
-    if (FileMMapInfo.second.PID == -1)
+    auto [File, BuildId, MMapInfo] = FileMMapInfoRes.get();
+    if (MMapInfo.PID == -1)
       continue;
-    if (FileMMapInfo.first == "(deleted)")
+    if (File == "(deleted)")
       continue;
 
-    GlobalMMapInfo.insert(FileMMapInfo);
+    auto It = GlobalMMapInfo.emplace(File, MMapInfo);
+    if (!BuildId.empty())
+      BuildIdMMapInfo.emplace(BuildId, &It->second);
   }
 
   LLVM_DEBUG({
     dbgs() << "FileName -> mmap info:\n"
-           << "  Filename : PID [MMapAddr, Size, Offset]\n";
-    for (const auto &[Name, MMap] : GlobalMMapInfo)
-      dbgs() << formatv("  {0} : {1} [{2:x}, {3:x} @ {4:x}]\n", Name, MMap.PID,
-                        MMap.MMapAddress, MMap.Size, MMap.Offset);
+           << "  FileName : PID [MMapAddr, Size, Offset]\n";
+    for (const auto &[FileName, MMap] : GlobalMMapInfo)
+      dbgs() << formatv("  {0} : {1} [{2:x}, {3:x} @ {4:x}]\n", FileName,
+                        MMap.PID, MMap.MMapAddress, MMap.Size, MMap.Offset);
   });
 
   StringRef NameToUse = llvm::sys::path::filename(BC->getFilename());
@@ -2332,8 +2339,7 @@ std::error_code DataAggregator::parseMMapEvents() {
     NameToUse = BuildIDBinaryName;
   }
 
-  auto Range = GlobalMMapInfo.equal_range(NameToUse);
-  for (MMapInfo &MMapInfo : llvm::make_second_range(make_range(Range))) {
+  auto matchMMapInfo = [&](MMapInfo &MMapInfo) {
     if (BC->HasFixedLoadAddress && MMapInfo.MMapAddress) {
       // Check that the binary mapping matches one of the segments.
       bool MatchFound = llvm::any_of(
@@ -2350,7 +2356,7 @@ std::error_code DataAggregator::parseMMapEvents() {
       if (!MatchFound) {
         errs() << "PERF2BOLT-WARNING: ignoring mapping of " << NameToUse
                << " at 0x" << Twine::utohexstr(MMapInfo.MMapAddress) << '\n';
-        continue;
+        return;
       }
     }
 
@@ -2364,7 +2370,7 @@ std::error_code DataAggregator::parseMMapEvents() {
                << Twine::utohexstr(MMapInfo.MMapAddress)
                << " using file offset 0x" << Twine::utohexstr(MMapInfo.Offset)
                << ". Ignoring profile data for this mapping\n";
-        continue;
+        return;
       }
       MMapInfo.BaseAddress = *BaseAddress;
     }
@@ -2381,6 +2387,17 @@ std::error_code DataAggregator::parseMMapEvents() {
     const uint64_t Size = EndAddress - BinaryMMapInfo[MMapInfo.PID].BaseAddress;
     if (Size > BinaryMMapInfo[MMapInfo.PID].Size)
       BinaryMMapInfo[MMapInfo.PID].Size = Size;
+  };
+
+  std::optional<StringRef> BuildId = BC->getFileBuildID();
+  if (!opts::IgnoreBuildID && BuildId && BuildIdMMapInfo.count(*BuildId) > 0) {
+    auto Range = BuildIdMMapInfo.equal_range(*BuildId);
+    for (MMapInfo *MMapInfo : llvm::make_second_range(make_range(Range)))
+      matchMMapInfo(*MMapInfo);
+  } else {
+    auto Range = GlobalMMapInfo.equal_range(NameToUse);
+    for (MMapInfo &MMapInfo : llvm::make_second_range(make_range(Range)))
+      matchMMapInfo(MMapInfo);
   }
 
   if (BinaryMMapInfo.empty()) {
diff --git a/bolt/unittests/Profile/DataAggregator.cpp b/bolt/unittests/Profile/DataAggregator.cpp
index e5e4611a639c92..72207b8f69431f 100644
--- a/bolt/unittests/Profile/DataAggregator.cpp
+++ b/bolt/unittests/Profile/DataAggregator.cpp
@@ -19,6 +19,7 @@ using namespace llvm::bolt;
 
 namespace opts {
 extern cl::opt<bool> ReadPreAggregated;
+extern cl::opt<bool> IgnoreBuildID;
 } // namespace opts
 
 namespace llvm {
@@ -150,6 +151,84 @@ TEST_F(PreAggregatedTestHelper, parseHexField) {
   EXPECT_EQ(*Res, 0ULL);
 }
 
+namespace llvm {
+namespace bolt {
+
+struct MMapEventsTestHelper : PreAggregatedTestHelper {
+  void SetUp() override {
+    PreAggregatedTestHelper::SetUp();
+    initializeBOLTForX86();
+    BC->setFilename("prog");
+    BC->setFileBuildID(BuildID);
+    BC->SegmentMapInfo[0x401000] =
+        SegmentInfo{0x401000, 0x1000, 0x1000, 0x1000, 0x1000, true, false};
+    opts::IgnoreBuildID = false;
+  }
+
+  static constexpr StringRef BuildID =
+      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+
+  DenseSet<uint64_t> parseMMapPIDs(StringRef Input) {
+    DataAggregator DA("<pseudo input>");
+    DA.BC = BC.get();
+    DA.setParsingBuffer(Input);
+    EXPECT_FALSE(DA.parseMMapEvents());
+    DenseSet<uint64_t> PIDs;
+    for (const auto &KV : DA.BinaryMMapInfo)
+      PIDs.insert(KV.first);
+    return PIDs;
+  }
+};
+
+} // namespace bolt
+} // namespace llvm
+
+TEST_F(MMapEventsTestHelper, MatchWithouBuildId) {
+  // Profiles recorded without build-ids match mappings by file name.
+  StringRef Input =
+      "prog 100 160514.108604: PERF_RECORD_MMAP2 100/100: [0x401000(0x1000) @ "
+      "0x1000 00:00 0 0]: r-xp /pkg/mmapptest/1/prog\n"
+      "prog 200 160514.108605: PERF_RECORD_MMAP2 200/200: [0x401000(0x1000) @ "
+      "0x1000 00:00 0 0]: r-xp /pkg/mmapptest/2/prog\n";
+  testing::internal::CaptureStderr();
+  DenseSet<uint64_t> PIDs = parseMMapPIDs(Input);
+  std::string CapturedStderr = testing::internal::GetCapturedStderr();
+  EXPECT_EQ(PIDs.size(), 2u);
+  EXPECT_TRUE(PIDs.count(100));
+  EXPECT_TRUE(PIDs.count(200));
+}
+
+TEST_F(MMapEventsTestHelper, MatchWithBuildId) {
+  BC->setFilename("prog2");
+  StringRef Input =
+      "prog 100 160514.108604: PERF_RECORD_MMAP2 100/100: [0x401000(0x1000) @ "
+      "0x1000 <aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>]: r-xp "
+      "/pkg/mmapptest/1/prog\n"
+      "prog 200 160514.108605: PERF_RECORD_MMAP2 200/200: [0x401000(0x1000) @ "
+      "0x1000 <bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb>]: r-xp "
+      "/pkg/mmapptest/2/prog\n";
+  DenseSet<uint64_t> PIDs = parseMMapPIDs(Input);
+  EXPECT_EQ(PIDs.size(), 1u);
+  EXPECT_TRUE(PIDs.count(100));
+  EXPECT_FALSE(PIDs.count(200));
+}
+
+TEST_F(MMapEventsTestHelper, MatchIgnoreBuildId) {
+  StringRef Input =
+      "prog 100 160514.108604: PERF_RECORD_MMAP2 100/100: [0x401000(0x1000) @ "
+      "0x1000 <aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>]: r-xp "
+      "/pkg/mmapptest/1/prog\n"
+      "prog 200 160514.108605: PERF_RECORD_MMAP2 200/200: [0x401000(0x1000) @ "
+      "0x1000 <bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb>]: r-xp "
+      "/pkg/mmapptest/2/prog\n";
+  opts::IgnoreBuildID = true;
+  DenseSet<uint64_t> PIDs = parseMMapPIDs(Input);
+  opts::IgnoreBuildID = false;
+  EXPECT_EQ(PIDs.size(), 2u);
+  EXPECT_TRUE(PIDs.count(100));
+  EXPECT_TRUE(PIDs.count(200));
+}
+
 #ifdef X86_AVAILABLE
 
 namespace llvm {

``````````

</details>


https://github.com/llvm/llvm-project/pull/229596


More information about the llvm-commits mailing list