Skip to content

[llvm-profdata] Fix binary ids with multiple raw profiles in a single… #72740

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 20, 2023

Conversation

ZequanWu
Copy link
Contributor

@ZequanWu ZequanWu commented Nov 18, 2023

Save binary ids when iterating through RawInstrProfReader.

Fixes #72699.

@llvmbot llvmbot added compiler-rt PGO Profile Guided Optimizations labels Nov 18, 2023
@llvmbot
Copy link
Member

llvmbot commented Nov 18, 2023

@llvm/pr-subscribers-pgo

Author: Zequan Wu (ZequanWu)

Changes

Fixes #72699.


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

3 Files Affected:

  • (modified) compiler-rt/test/profile/Linux/binary-id.c (+39-2)
  • (modified) llvm/include/llvm/ProfileData/InstrProfReader.h (+1-5)
  • (modified) llvm/lib/ProfileData/InstrProfReader.cpp (+27-30)
diff --git a/compiler-rt/test/profile/Linux/binary-id.c b/compiler-rt/test/profile/Linux/binary-id.c
index 61b8ed9268496a3..e04b23072a931a0 100644
--- a/compiler-rt/test/profile/Linux/binary-id.c
+++ b/compiler-rt/test/profile/Linux/binary-id.c
@@ -17,16 +17,35 @@
 // RUN: llvm-profdata show --binary-ids  %t.profdir/default_*.profraw > %t.profraw.out
 // RUN: FileCheck %s --check-prefix=BINARY-ID-MERGE-PROF < %t.profraw.out
 
-// RUN: llvm-profdata merge -o %t.profdata %t.profraw %t.profraw
+// RUN: llvm-profdata merge -o %t.profdata %t.profdir/default_*.profraw
 // RUN: llvm-profdata show --binary-ids %t.profdata > %t.profdata.out
-// RUN: FileCheck %s --check-prefix=BINARY-ID-INDEXED-PROF < %t.profraw.out
+// RUN: FileCheck %s --check-prefix=BINARY-ID-INDEXED-PROF < %t.profdata.out
 
+// Test raw profiles with shared libraries.
+// RUN: split-file %s %t.dir
+// RUN: %clang_profgen -Wl,--build-id -fpic -shared -O2 %t.dir/foo.c -o %t.dir/libfoo.so
+// RUN: %clang_profgen -Wl,--build-id -fpic -shared -O2 %t.dir/bar.c -o %t.dir/libbar.so
+// RUN: %clang_profgen -Wl,--build-id -O2 %t.dir/main.c %t.dir/libfoo.so %t.dir/libbar.so -o %t
+// RUN: env LLVM_PROFILE_FILE=%t.profraw LD_LIBRARY_PATH=%t.dir %run %t
+// RUN: llvm-profdata show --binary-ids %t.profraw > %t.profraw.out
+// RUN: llvm-profdata merge -o %t.profdata %t.profraw
+// RUN: FileCheck %s --check-prefix=BINARY-ID-SHARE-RAW-PROF < %t.profraw.out
+
+// RUN: llvm-profdata merge -o %t.profdata %t.profraw 
+// RUN: llvm-profdata show --binary-ids %t.profdata > %t.profdata.out
+// RUN: FileCheck %s --check-prefix=BINARY-ID-SHARE-INDEXED-PROF < %t.profraw.out
+
+//--- foo.c
 void foo() {
 }
 
+//--- bar.c
 void bar() {
 }
 
+//--- main.c
+void foo();
+void bar();
 int main() {
   foo();
   bar();
@@ -59,3 +78,21 @@ int main() {
 // BINARY-ID-INDEXED-PROF-NEXT: Maximum internal block count: 0
 // BINARY-ID-INDEXED-PROF-NEXT: Binary IDs:
 // BINARY-ID-INDEXED-PROF-NEXT: {{[0-9a-f]+}}
+
+// BINARY-ID-SHARE-RAW-PROF: Instrumentation level: Front-end
+// BINARY-ID-SHARE-RAW-PROF-NEXT: Total functions: 3
+// BINARY-ID-SHARE-RAW-PROF-NEXT: Maximum function count: 1
+// BINARY-ID-SHARE-RAW-PROF-NEXT: Maximum internal block count: 0
+// BINARY-ID-SHARE-RAW-PROF-NEXT: Binary IDs:
+// BINARY-ID-SHARE-RAW-PROF-NEXT: {{[0-9a-f]+}}
+// BINARY-ID-SHARE-RAW-PROF-NEXT: {{[0-9a-f]+}}
+// BINARY-ID-SHARE-RAW-PROF-NEXT: {{[0-9a-f]+}}
+
+// BINARY-ID-SHARE-INDEXED-PROF: Instrumentation level: Front-end
+// BINARY-ID-SHARE-INDEXED-PROF-NEXT: Total functions: 3
+// BINARY-ID-SHARE-INDEXED-PROF-NEXT: Maximum function count: 1
+// BINARY-ID-SHARE-INDEXED-PROF-NEXT: Maximum internal block count: 0
+// BINARY-ID-SHARE-INDEXED-PROF-NEXT: Binary IDs:
+// BINARY-ID-SHARE-INDEXED-PROF-NEXT: {{[0-9a-f]+}}
+// BINARY-ID-SHARE-INDEXED-PROF-NEXT: {{[0-9a-f]+}}
+// BINARY-ID-SHARE-INDEXED-PROF-NEXT: {{[0-9a-f]+}}
\ No newline at end of file
diff --git a/llvm/include/llvm/ProfileData/InstrProfReader.h b/llvm/include/llvm/ProfileData/InstrProfReader.h
index 4bbdda25e27a2b0..952cc0d0dc80b93 100644
--- a/llvm/include/llvm/ProfileData/InstrProfReader.h
+++ b/llvm/include/llvm/ProfileData/InstrProfReader.h
@@ -340,11 +340,7 @@ class RawInstrProfReader : public InstrProfReader {
   const uint8_t *ValueDataStart;
   uint32_t ValueKindLast;
   uint32_t CurValueDataSize;
-
-  /// Total size of binary ids.
-  uint64_t BinaryIdsSize{0};
-  /// Start address of binary id length and data pairs.
-  const uint8_t *BinaryIdsStart;
+  std::vector<llvm::object::BuildID> BinaryIds;
 
   std::function<void(Error)> Warn;
 
diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp
index 9d5140da4db248e..78e5329412b9ac2 100644
--- a/llvm/lib/ProfileData/InstrProfReader.cpp
+++ b/llvm/lib/ProfileData/InstrProfReader.cpp
@@ -142,27 +142,15 @@ readBinaryIdsInternal(const MemoryBuffer &DataBuffer,
   return Error::success();
 }
 
-static Error printBinaryIdsInternal(raw_ostream &OS,
-                                    const MemoryBuffer &DataBuffer,
-                                    uint64_t BinaryIdsSize,
-                                    const uint8_t *BinaryIdsStart,
-                                    llvm::endianness Endian) {
-  if (BinaryIdsSize == 0)
-    return Error::success();
-
-  std::vector<llvm::object::BuildID> BinaryIds;
-  if (Error E = readBinaryIdsInternal(DataBuffer, BinaryIdsSize, BinaryIdsStart,
-                                      BinaryIds, Endian))
-    return E;
-
+static void
+printBinaryIdsInternal(raw_ostream &OS,
+                       std::vector<llvm::object::BuildID> &BinaryIds) {
   OS << "Binary IDs: \n";
   for (auto BI : BinaryIds) {
     for (uint64_t I = 0; I < BI.size(); I++)
       OS << format("%02x", BI[I]);
     OS << "\n";
   }
-
-  return Error::success();
 }
 
 Expected<std::unique_ptr<InstrProfReader>>
@@ -571,9 +559,20 @@ Error RawInstrProfReader<IntPtrT>::readHeader(
   if (!useCorrelate() && Correlator)
     return error(instrprof_error::unexpected_debug_info_for_correlation);
 
-  BinaryIdsSize = swap(Header.BinaryIdsSize);
-  if (BinaryIdsSize % sizeof(uint64_t))
+  uint64_t BinaryIdsSize = swap(Header.BinaryIdsSize);
+  // Binary ids start just after the header.
+  const uint8_t *BinaryIdsStart =
+      reinterpret_cast<const uint8_t *>(&Header) + sizeof(RawInstrProf::Header);
+  const uint8_t *BinaryIdEnd = BinaryIdsStart + BinaryIdsSize;
+  const uint8_t *BufferEnd = (const uint8_t *)DataBuffer->getBufferEnd();
+  if (BinaryIdsSize % sizeof(uint64_t) || BinaryIdEnd > BufferEnd)
     return error(instrprof_error::bad_header);
+  if (BinaryIdsSize != 0) {
+    if (Error Err =
+            readBinaryIdsInternal(*DataBuffer, BinaryIdsSize, BinaryIdsStart,
+                                  BinaryIds, getDataEndianness()))
+      return Err;
+  }
 
   CountersDelta = swap(Header.CountersDelta);
   BitmapDelta = swap(Header.BitmapDelta);
@@ -620,19 +619,12 @@ Error RawInstrProfReader<IntPtrT>::readHeader(
     NamesEnd = NamesStart + NamesSize;
   }
 
-  // Binary ids start just after the header.
-  BinaryIdsStart =
-      reinterpret_cast<const uint8_t *>(&Header) + sizeof(RawInstrProf::Header);
   CountersStart = Start + CountersOffset;
   CountersEnd = CountersStart + CountersSize;
   BitmapStart = Start + BitmapOffset;
   BitmapEnd = BitmapStart + NumBitmapBytes;
   ValueDataStart = reinterpret_cast<const uint8_t *>(Start + ValueDataOffset);
 
-  const uint8_t *BufferEnd = (const uint8_t *)DataBuffer->getBufferEnd();
-  if (BinaryIdsStart + BinaryIdsSize > BufferEnd)
-    return error(instrprof_error::bad_header);
-
   std::unique_ptr<InstrProfSymtab> NewSymtab = std::make_unique<InstrProfSymtab>();
   if (Error E = createSymtab(*NewSymtab))
     return E;
@@ -830,14 +822,16 @@ Error RawInstrProfReader<IntPtrT>::readNextRecord(NamedInstrProfRecord &Record)
 template <class IntPtrT>
 Error RawInstrProfReader<IntPtrT>::readBinaryIds(
     std::vector<llvm::object::BuildID> &BinaryIds) {
-  return readBinaryIdsInternal(*DataBuffer, BinaryIdsSize, BinaryIdsStart,
-                               BinaryIds, getDataEndianness());
+  BinaryIds.insert(BinaryIds.begin(), this->BinaryIds.begin(),
+                   this->BinaryIds.end());
+  return Error::success();
 }
 
 template <class IntPtrT>
 Error RawInstrProfReader<IntPtrT>::printBinaryIds(raw_ostream &OS) {
-  return printBinaryIdsInternal(OS, *DataBuffer, BinaryIdsSize, BinaryIdsStart,
-                                getDataEndianness());
+  if (!BinaryIds.empty())
+    printBinaryIdsInternal(OS, BinaryIds);
+  return Error::success();
 }
 
 namespace llvm {
@@ -1473,8 +1467,11 @@ Error IndexedInstrProfReader::readBinaryIds(
 }
 
 Error IndexedInstrProfReader::printBinaryIds(raw_ostream &OS) {
-  return printBinaryIdsInternal(OS, *DataBuffer, BinaryIdsSize, BinaryIdsStart,
-                                llvm::endianness::little);
+  std::vector<llvm::object::BuildID> BinaryIds;
+  if (Error E = readBinaryIds(BinaryIds))
+    return E;
+  printBinaryIdsInternal(OS, BinaryIds);
+  return Error::success();
 }
 
 void InstrProfReader::accumulateCounts(CountSumOrPercent &Sum, bool IsCS) {

Copy link

github-actions bot commented Nov 18, 2023

✅ With the latest revision this PR passed the C/C++ code formatter.

// Binary ids start just after the header.
const uint8_t *BinaryIdsStart =
reinterpret_cast<const uint8_t *>(&Header) + sizeof(RawInstrProf::Header);
const uint8_t *BinaryIdEnd = BinaryIdsStart + BinaryIdsSize;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we call it BinaryIdsEnd for consistency with BinaryIdsStart and BinaryIdsSize?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed BinaryIdsStart and BinaryIdsSize to BinaryIdStart and BinaryIdSize because there can only be up to one binary id after the header.

@ZequanWu ZequanWu merged commit b9951b3 into llvm:main Nov 20, 2023
@ZequanWu ZequanWu deleted the profdata-build-id branch November 20, 2023 19:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler-rt PGO Profile Guided Optimizations
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Profile binary id does not work with shared libraries
3 participants