diff --git a/compiler-rt/include/profile/InstrProfData.inc b/compiler-rt/include/profile/InstrProfData.inc --- a/compiler-rt/include/profile/InstrProfData.inc +++ b/compiler-rt/include/profile/InstrProfData.inc @@ -129,6 +129,7 @@ #endif INSTR_PROF_RAW_HEADER(uint64_t, Magic, __llvm_profile_get_magic()) INSTR_PROF_RAW_HEADER(uint64_t, Version, __llvm_profile_get_version()) +INSTR_PROF_RAW_HEADER(uint64_t, BinaryIdSize, __llvm_binary_ids_size()) INSTR_PROF_RAW_HEADER(uint64_t, DataSize, DataSize) INSTR_PROF_RAW_HEADER(uint64_t, PaddingBytesBeforeCounters, PaddingBytesBeforeCounters) INSTR_PROF_RAW_HEADER(uint64_t, CountersSize, CountersSize) diff --git a/compiler-rt/lib/profile/InstrProfilingInternal.h b/compiler-rt/lib/profile/InstrProfilingInternal.h --- a/compiler-rt/lib/profile/InstrProfilingInternal.h +++ b/compiler-rt/lib/profile/InstrProfilingInternal.h @@ -9,6 +9,8 @@ #ifndef PROFILE_INSTRPROFILING_INTERNALH_ #define PROFILE_INSTRPROFILING_INTERNALH_ +#include +#include #include #include "InstrProfiling.h" @@ -125,14 +127,14 @@ uint8_t *SiteCountArray[]); /* Function pointer to getValueProfRecordHeader method. */ uint32_t (*GetValueProfRecordHeaderSize)(uint32_t NumSites); - /* Function pointer to getFristValueProfRecord method. */ + /* Function pointer to getFristValueProfRecord method. */ struct ValueProfRecord *(*GetFirstValueProfRecord)(struct ValueProfData *); /* Return the number of value data for site \p Site. */ uint32_t (*GetNumValueDataForSite)(uint32_t VK, uint32_t Site); - /* Return the total size of the value profile data of the + /* Return the total size of the value profile data of the * current function. */ uint32_t (*GetValueProfDataSize)(void); - /*! + /*! * Read the next \p N value data for site \p Site and store the data * in \p Dst. \p StartNode is the first value node to start with if * it is not null. The function returns the pointer to the value @@ -164,7 +166,7 @@ VPDataReaderType *lprofGetVPDataReader(); -/* Internal interface used by test to reset the max number of +/* Internal interface used by test to reset the max number of * tracked values per value site to be \p MaxVals. */ void lprofSetMaxValsPerSite(uint32_t MaxVals); @@ -177,7 +179,7 @@ * to dump merged profile data into its own profile file. */ uint64_t lprofGetLoadModuleSignature(); -/* +/* * Return non zero value if the profile data has already been * dumped to the file. */ @@ -197,4 +199,17 @@ COMPILER_RT_VISIBILITY extern ValueProfNode *EndVNode; extern void (*VPMergeHook)(struct ValueProfData *, __llvm_profile_data *); +/* + * Return binary ids size. + * Declare it weak, so it can be overridden in different platforms. + */ +COMPILER_RT_VISIBILITY COMPILER_RT_WEAK uint64_t __llvm_binary_ids_size(void); + +/* + * Write binary id length and its data into profile. + * Declare it weak, so it can be overridden in different platforms. + */ +COMPILER_RT_VISIBILITY COMPILER_RT_WEAK int +__llvm_write_binary_ids(ProfDataWriter *Writer); + #endif diff --git a/compiler-rt/lib/profile/InstrProfilingInternal.c b/compiler-rt/lib/profile/InstrProfilingInternal.c --- a/compiler-rt/lib/profile/InstrProfilingInternal.c +++ b/compiler-rt/lib/profile/InstrProfilingInternal.c @@ -33,4 +33,21 @@ RuntimeCounterRelocation = Value; } +/* + * The runtime provides the default definition of this function + * for the platforms that do not yet support binary id. + */ +COMPILER_RT_VISIBILITY COMPILER_RT_WEAK uint64_t __llvm_binary_ids_size(void) { + return 0; +} + +/* + * The runtime provides the default definition of this function + * for the platforms that do not yet support binary id. + */ +COMPILER_RT_VISIBILITY COMPILER_RT_WEAK int +__llvm_write_binary_id(ProfDataWriter *Writer) { + return 0; +} + #endif diff --git a/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c b/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c --- a/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c +++ b/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c @@ -12,6 +12,7 @@ #include #include "InstrProfiling.h" +#include "InstrProfilingInternal.h" #define PROF_DATA_START INSTR_PROF_SECT_START(INSTR_PROF_DATA_COMMON) #define PROF_DATA_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_DATA_COMMON) @@ -72,4 +73,78 @@ COMPILER_RT_VISIBILITY ValueProfNode *CurrentVNode = &PROF_VNODES_START; COMPILER_RT_VISIBILITY ValueProfNode *EndVNode = &PROF_VNODES_STOP; +static size_t RoundUp(size_t size, size_t align) { + return (size + align - 1) & ~(align - 1); +} + +COMPILER_RT_VISIBILITY COMPILER_RT_WEAK uint64_t __llvm_binary_ids_size(void) { + uint64_t BinaryIdsSize = 0; + extern const ElfW(Ehdr) __ehdr_start __attribute__((visibility("hidden"))); + const ElfW(Ehdr) *ElfHeader = &__ehdr_start; + const ElfW(Phdr) *ProgramHeader = + (const ElfW(Phdr) *)((uintptr_t)ElfHeader + ElfHeader->e_phoff); + + uint32_t I; + /* Iterate through entries in the program header. */ + for (I = 0; I < ElfHeader->e_phnum; I++) { + /* Look for the note segment in program header entries. */ + if (ProgramHeader[I].p_type != PT_NOTE) + continue; + + const ElfW(Nhdr) *Note = + (const ElfW(Nhdr) *)((uintptr_t)ElfHeader + ProgramHeader[I].p_offset); + const ElfW(Nhdr) *NotesEnd = Note + ProgramHeader[I].p_filesz; + + while (Note < NotesEnd) { + if (Note->n_type == NT_GNU_BUILD_ID) + BinaryIdsSize++; + + Note = Note + sizeof(ElfW(Nhdr)) + RoundUp(Note->n_namesz, 4) + + RoundUp(Note->n_descsz, 4); + } + } + + return BinaryIdsSize; +} + +COMPILER_RT_VISIBILITY COMPILER_RT_WEAK int +__llvm_write_binary_ids(ProfDataWriter *Writer) { + extern const ElfW(Ehdr) __ehdr_start __attribute__((visibility("hidden"))); + const ElfW(Ehdr) *ElfHeader = &__ehdr_start; + const ElfW(Phdr) *ProgramHeader = + (const ElfW(Phdr) *)((uintptr_t)ElfHeader + ElfHeader->e_phoff); + + uint32_t I; + /* Iterate through entries in the program header. */ + for (I = 0; I < ElfHeader->e_phnum; I++) { + /* Look for the note section in program header entries. */ + if (ProgramHeader[I].p_type != PT_NOTE) + continue; + + const ElfW(Nhdr) *Note = + (const ElfW(Nhdr) *)((uintptr_t)ElfHeader + ProgramHeader[I].p_offset); + const ElfW(Nhdr) *NotesEnd = Note + ProgramHeader[I].p_filesz; + + while (Note < NotesEnd) { + if (Note->n_type == NT_GNU_BUILD_ID) { + uint64_t Size = Note->n_descsz; + uint8_t *Data = + (uint8_t *)((uintptr_t)Note + sizeof(ElfW(Nhdr)) + Note->n_namesz); + + ProfDataIOVec BinaryIdIOVec[] = {{&Size, sizeof(uint64_t), 1, 0}, + {Data, sizeof(uint8_t), Size, 0}}; + + if (Writer->Write(Writer, BinaryIdIOVec, + sizeof(BinaryIdIOVec) / sizeof(*BinaryIdIOVec))) + return -1; + } + + Note = Note + sizeof(ElfW(Nhdr)) + RoundUp(Note->n_namesz, 4) + + RoundUp(Note->n_descsz, 4); + } + } + + return 0; +} + #endif diff --git a/compiler-rt/lib/profile/InstrProfilingWriter.c b/compiler-rt/lib/profile/InstrProfilingWriter.c --- a/compiler-rt/lib/profile/InstrProfilingWriter.c +++ b/compiler-rt/lib/profile/InstrProfilingWriter.c @@ -299,5 +299,9 @@ if (__llvm_profile_is_continuous_mode_enabled()) return 0; - return writeValueProfData(Writer, VPDataReader, DataBegin, DataEnd); + if (writeValueProfData(Writer, VPDataReader, DataBegin, DataEnd)) + return -1; + + /* Write binary id length and its data. */ + return __llvm_write_binary_ids(Writer); } diff --git a/compiler-rt/test/profile/binary-id.c b/compiler-rt/test/profile/binary-id.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/profile/binary-id.c @@ -0,0 +1,58 @@ +// RUN: %clang_profgen -O2 -o %t %s +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t +// RUN: llvm-profdata show --binary-ids %t.profraw > %t.out +// RUN: FileCheck %s --check-prefix=NO-BINARY-ID < %t.out +// RUN: llvm-profdata merge -o %t.profdata %t.profraw + +// RUN: %clang_profgen -Wl,-E,--build-id -O2 -o %t %s +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t +// RUN: llvm-profdata show --binary-ids %t.profraw > %t.profraw.out +// RUN: FileCheck %s --check-prefix=BINARY-ID-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-INDEXED-PROF < %t.profdata.out + +// RUN: llvm-profdata merge -o %t.profdata %t.profraw %t.profraw +// RUN: llvm-profdata show --binary-ids %t.profdata > %t.profdata.out +// RUN: FileCheck %s --check-prefix=MULTIPLE-BINARY-ID < %t.profdata.out + +void foo() { +} + +void bar() { +} + +int main() { + foo(); + bar(); + + return 0; +} + +// NO-BINARY-ID: Instrumentation level: Front-end +// NO-BINARY-ID-NEXT: Total functions: 3 +// NO-BINARY-ID-NEXT: Maximum function count: 1 +// NO-BINARY-ID-NEXT: Maximum internal block count: 0 +// NO-BINARY-ID-NOT: Binary IDs: + +// BINARY-ID-RAW-PROF: Instrumentation level: Front-end +// BINARY-ID-RAW-PROF-NEXT: Total functions: 3 +// BINARY-ID-RAW-PROF-NEXT: Maximum function count: 1 +// BINARY-ID-RAW-PROF-NEXT: Maximum internal block count: 0 +// BINARY-ID-RAW-PROF-NEXT: Binary IDs: +// BINARY-ID-RAW-PROF-NEXT: {{[0-9a-f]+}} + +// BINARY-ID-INDEXED-PROF: Instrumentation level: Front-end +// BINARY-ID-INDEXED-PROF-NEXT: Total functions: 3 +// BINARY-ID-INDEXED-PROF-NEXT: Maximum function count: 1 +// 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]+}} + +// MULTIPLE-BINARY-ID: Instrumentation level: Front-end +// MULTIPLE-BINARY-ID-NEXT: Total functions: 3 +// MULTIPLE-BINARY-ID-NEXT: Maximum function count: 2 +// MULTIPLE-BINARY-ID-NEXT: Maximum internal block count: 0 +// MULTIPLE-BINARY-ID-NEXT: Binary IDs: +// MULTIPLE-BINARY-ID-NEXT: {{[0-9a-f]+}} +// MULTIPLE-BINARY-ID-NEXT: {{[0-9a-f]+}} diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h --- a/llvm/include/llvm/ProfileData/InstrProf.h +++ b/llvm/include/llvm/ProfileData/InstrProf.h @@ -999,6 +999,7 @@ struct Header { uint64_t Magic; uint64_t Version; + uint64_t BinaryIdSize; uint64_t Unused; // Becomes unused since version 4 uint64_t HashType; uint64_t HashOffset; diff --git a/llvm/include/llvm/ProfileData/InstrProfData.inc b/llvm/include/llvm/ProfileData/InstrProfData.inc --- a/llvm/include/llvm/ProfileData/InstrProfData.inc +++ b/llvm/include/llvm/ProfileData/InstrProfData.inc @@ -129,6 +129,7 @@ #endif INSTR_PROF_RAW_HEADER(uint64_t, Magic, __llvm_profile_get_magic()) INSTR_PROF_RAW_HEADER(uint64_t, Version, __llvm_profile_get_version()) +INSTR_PROF_RAW_HEADER(uint64_t, BinaryIdSize, __llvm_binary_ids_size()) INSTR_PROF_RAW_HEADER(uint64_t, DataSize, DataSize) INSTR_PROF_RAW_HEADER(uint64_t, PaddingBytesBeforeCounters, PaddingBytesBeforeCounters) INSTR_PROF_RAW_HEADER(uint64_t, CountersSize, CountersSize) diff --git a/llvm/include/llvm/ProfileData/InstrProfReader.h b/llvm/include/llvm/ProfileData/InstrProfReader.h --- a/llvm/include/llvm/ProfileData/InstrProfReader.h +++ b/llvm/include/llvm/ProfileData/InstrProfReader.h @@ -82,6 +82,17 @@ /// Read a single record. virtual Error readNextRecord(NamedInstrProfRecord &Record) = 0; + // Get number of binary ids. + /// TODO: Can we implement the following three functions + /// in InstrProfReader class. + virtual uint64_t getBinaryIdsSize() { return 0; }; + + // Get binary ids start position. + virtual const uint8_t *getBinaryIds() { return nullptr; }; + + /// Print binary ids on stream OS. + virtual void printBinaryIds(raw_ostream &OS){}; + /// Iterator over profile data. InstrProfIterator begin() { return InstrProfIterator(this); } InstrProfIterator end() { return InstrProfIterator(); } @@ -222,6 +233,9 @@ uint32_t ValueKindLast; uint32_t CurValueDataSize; + uint64_t BinaryIdsSize; + const uint8_t *BinaryIdsStart; + public: RawInstrProfReader(std::unique_ptr DataBuffer) : DataBuffer(std::move(DataBuffer)) {} @@ -231,6 +245,11 @@ static bool hasFormat(const MemoryBuffer &DataBuffer); Error readHeader() override; Error readNextRecord(NamedInstrProfRecord &Record) override; + Error readBinaryIds(); + + uint64_t getBinaryIdsSize() override; + const uint8_t *getBinaryIds() override; + void printBinaryIds(raw_ostream &OS) override; bool isIRLevelProfile() const override { return (Version & VARIANT_MASK_IR_PROF) != 0; @@ -465,12 +484,21 @@ // Index to the current record in the record array. unsigned RecordIndex; + uint64_t BinaryIdsSize; + const uint8_t *BinaryIdsStart; + // Read the profile summary. Return a pointer pointing to one byte past the // end of the summary data if it exists or the input \c Cur. // \c UseCS indicates whether to use the context-sensitive profile summary. const unsigned char *readSummary(IndexedInstrProf::ProfVersion Version, const unsigned char *Cur, bool UseCS); + // Read binary ids. + // If binary ids exists, return a pointer pointing next to binary ids. + // Otherwise, returns the input Cur + // const unsigned char *readBinaryIdikos(const unsigned char *Cur); + const unsigned char *readBinaryIds(const unsigned char *Cur); + public: IndexedInstrProfReader( std::unique_ptr DataBuffer, @@ -548,6 +576,10 @@ return *(Summary.get()); } } + + uint64_t getBinaryIdsSize() override; + const uint8_t *getBinaryIds() override; + void printBinaryIds(raw_ostream &OS) override; }; } // end namespace llvm diff --git a/llvm/include/llvm/ProfileData/InstrProfWriter.h b/llvm/include/llvm/ProfileData/InstrProfWriter.h --- a/llvm/include/llvm/ProfileData/InstrProfWriter.h +++ b/llvm/include/llvm/ProfileData/InstrProfWriter.h @@ -44,6 +44,9 @@ // Use raw pointer here for the incomplete type object. InstrProfRecordWriterTrait *InfoObj; + std::vector BinaryIdsSizes; + std::vector BinaryIdsList; + public: InstrProfWriter(bool Sparse = false, bool InstrEntryBBEnabled = false); ~InstrProfWriter(); @@ -112,6 +115,8 @@ OverlapStats &FuncLevelOverlap, const OverlapFuncFilters &FuncFilter); + void addBinaryIds(uint64_t BinaryIdsSize, const uint8_t *BinaryIds); + private: void addRecord(StringRef Name, uint64_t Hash, InstrProfRecord &&I, uint64_t Weight, function_ref Warn); diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp --- a/llvm/lib/ProfileData/InstrProfReader.cpp +++ b/llvm/lib/ProfileData/InstrProfReader.cpp @@ -24,8 +24,8 @@ #include "llvm/Support/Error.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/SymbolRemappingReader.h" #include "llvm/Support/SwapByteOrder.h" +#include "llvm/Support/SymbolRemappingReader.h" #include #include #include @@ -366,6 +366,7 @@ if (GET_VERSION(Version) != RawInstrProf::Version) return error(instrprof_error::unsupported_version); + BinaryIdsSize = swap(Header.BinaryIdSize); CountersDelta = swap(Header.CountersDelta); NamesDelta = swap(Header.NamesDelta); auto DataSize = swap(Header.DataSize); @@ -478,12 +479,34 @@ return success(); } +template Error RawInstrProfReader::readBinaryIds() { + BinaryIdsStart = reinterpret_cast(ValueDataStart); + + for (uint64_t I = 0; I < BinaryIdsSize; I++) { + // Read binary id length. + uint64_t BinaryIdLen = + swap(*reinterpret_cast(ValueDataStart)); + + // Increment ValueDataStart by binary id length and its data. + ValueDataStart += sizeof(BinaryIdLen); + ValueDataStart += BinaryIdLen; + } + + return success(); +} + template Error RawInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) { - if (atEnd()) + if (atEnd()) { + // Read binary ids that starts after record. + // TODO: In which cases there are multiple headers? + if (Error E = readBinaryIds()) + return error(std::move(E)); + // At this point, ValueDataStart field points to the next header. if (Error E = readNextHeader(getNextHeaderPos())) return error(std::move(E)); + } // Read name ad set it in Record. if (Error E = readName(Record)) @@ -506,6 +529,36 @@ return success(); } +template +uint64_t RawInstrProfReader::getBinaryIdsSize() { + return BinaryIdsSize; +} + +template +const uint8_t *RawInstrProfReader::getBinaryIds() { + return BinaryIdsStart; +} + +template +void RawInstrProfReader::printBinaryIds(raw_ostream &OS) { + if (BinaryIdsSize == 0) + return; + + OS << "Binary IDs: \n"; + const uint8_t *BinaryId = BinaryIdsStart; + + for (uint64_t I = 0; I < BinaryIdsSize; I++) { + uint64_t BinaryIdLen = swap(*reinterpret_cast(BinaryId)); + BinaryId += sizeof(BinaryIdLen); + + for (uint64_t J = 0; J < BinaryIdLen; J++) + OS << format("%02x", BinaryId[J]); + OS << "\n"; + + BinaryId += BinaryIdLen; + } +} + namespace llvm { template class RawInstrProfReader; @@ -805,6 +858,24 @@ } } +const unsigned char * +IndexedInstrProfReader::readBinaryIds(const unsigned char *Cur) { + using namespace support; + + if (BinaryIdsSize == 0) + return Cur; + + BinaryIdsStart = Cur; + for (uint64_t I = 0; I < BinaryIdsSize; I++) { + uint64_t BinaryIdLen = endian::byte_swap( + *reinterpret_cast(Cur)); + Cur += sizeof(BinaryIdLen); + Cur += BinaryIdLen; + } + + return Cur; +} + Error IndexedInstrProfReader::readHeader() { using namespace support; @@ -828,12 +899,18 @@ IndexedInstrProf::ProfVersion::CurrentVersion) return error(instrprof_error::unsupported_version); + // Read number of binary ids. + BinaryIdsSize = endian::byte_swap(Header->BinaryIdSize); + Cur = readSummary((IndexedInstrProf::ProfVersion)FormatVersion, Cur, /* UseCS */ false); if (FormatVersion & VARIANT_MASK_CSIR_PROF) Cur = readSummary((IndexedInstrProf::ProfVersion)FormatVersion, Cur, /* UseCS */ true); + // Read binary ids. + Cur = readBinaryIds(Cur); + // Read the hash type and start offset. IndexedInstrProf::HashT HashType = static_cast( endian::byte_swap(Header->HashType)); @@ -931,3 +1008,29 @@ } Sum.NumEntries = NumFuncs; } + +uint64_t IndexedInstrProfReader::getBinaryIdsSize() { return BinaryIdsSize; } + +const uint8_t *IndexedInstrProfReader::getBinaryIds() { return BinaryIdsStart; } + +void IndexedInstrProfReader::printBinaryIds(raw_ostream &OS) { + using namespace support; + + if (BinaryIdsSize == 0) + return; + + OS << "Binary IDs: \n"; + const uint8_t *BinaryId = BinaryIdsStart; + + for (uint64_t I = 0; I < BinaryIdsSize; I++) { + uint64_t BinaryIdLen = endian::byte_swap( + *reinterpret_cast(BinaryId)); + BinaryId += sizeof(BinaryIdLen); + + for (uint64_t J = 0; J < BinaryIdLen; J++) + OS << format("%02x", BinaryId[J]); + OS << "\n"; + + BinaryId += BinaryIdLen; + } +} diff --git a/llvm/lib/ProfileData/InstrProfWriter.cpp b/llvm/lib/ProfileData/InstrProfWriter.cpp --- a/llvm/lib/ProfileData/InstrProfWriter.cpp +++ b/llvm/lib/ProfileData/InstrProfWriter.cpp @@ -54,6 +54,7 @@ uint64_t tell() { return OS.tell(); } void write(uint64_t V) { LE.write(V); } + void writeByte(uint8_t V) { LE.write(V); } // \c patch can only be called when all data is written and flushed. // For raw_string_ostream, the patch is done on the target string @@ -287,6 +288,7 @@ Error InstrProfWriter::writeImpl(ProfOStream &OS) { using namespace IndexedInstrProf; + using namespace support; OnDiskChainedHashTableGenerator Generator; @@ -312,6 +314,11 @@ if (InstrEntryBBEnabled) Header.Version |= VARIANT_MASK_INSTR_ENTRY; + uint64_t TotalBinaryIdSizes = 0; + for (uint64_t BinaryIdSize : BinaryIdsSizes) + TotalBinaryIdSizes += BinaryIdSize; + + Header.BinaryIdSize = TotalBinaryIdSizes; Header.Unused = 0; Header.HashType = static_cast(IndexedInstrProf::HashType); Header.HashOffset = 0; @@ -344,6 +351,24 @@ OS.write(0); } + // Write binary id lengths and its data. + for (unsigned I = 0; I < BinaryIdsList.size(); I++) { + uint64_t BinaryIdsSize = BinaryIdsSizes[I]; + const uint8_t *BinaryId = BinaryIdsList[I]; + + for (uint64_t J = 0; J < BinaryIdsSize; J++) { + uint64_t BinaryIdLen = endian::byte_swap( + *reinterpret_cast(BinaryId)); + OS.write(BinaryIdLen); + BinaryId += sizeof(BinaryIdLen); + + for (uint64_t K = 0; K < BinaryIdLen; K++) + OS.writeByte(BinaryId[K]); + + BinaryId += BinaryIdLen; + } + } + // Write the hash table. uint64_t HashTableStart = Generator.Emit(OS.OS, *InfoObj); @@ -510,3 +535,9 @@ return Error::success(); } + +void InstrProfWriter::addBinaryIds(uint64_t BinaryIdsSize, + const uint8_t *BinaryIds) { + BinaryIdsSizes.push_back(BinaryIdsSize); + BinaryIdsList.push_back(BinaryIds); +} diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp --- a/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -281,6 +281,10 @@ FuncName, firstTime); }); } + + // TODO: Can we have multiple Writer Contexts? + WC->Writer.addBinaryIds(Reader->getBinaryIdsSize(), Reader->getBinaryIds()); + if (Reader->hasError()) if (Error E = Reader->getError()) WC->Errors.emplace_back(std::move(E), Filename); @@ -2040,7 +2044,7 @@ bool ShowAllFunctions, bool ShowCS, uint64_t ValueCutoff, bool OnlyListBelow, const std::string &ShowFunction, bool TextFormat, - raw_fd_ostream &OS) { + bool ShowBinaryIds, raw_fd_ostream &OS) { auto ReaderOrErr = InstrProfReader::create(Filename); std::vector Cutoffs = std::move(DetailedSummaryCutoffs); if (ShowDetailedSummary && Cutoffs.empty()) { @@ -2222,6 +2226,10 @@ OS << "Total count: " << PS->getTotalCount() << "\n"; PS->printDetailedSummary(OS); } + + if (ShowBinaryIds) + Reader->printBinaryIds(OS); + return 0; } @@ -2472,6 +2480,9 @@ cl::desc("Show the information of each section in the sample profile. " "The flag is only usable when the sample profile is in " "extbinary format")); + cl::opt ShowBinaryIds( + "binary-ids", cl::init(false), + cl::desc("Show binary ids in the instruction profile. ")); cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n"); @@ -2493,11 +2504,11 @@ WithColor::warning() << "-function argument ignored: showing all functions\n"; if (ProfileKind == instr) - return showInstrProfile(Filename, ShowCounts, TopNFunctions, - ShowIndirectCallTargets, ShowMemOPSizes, - ShowDetailedSummary, DetailedSummaryCutoffs, - ShowAllFunctions, ShowCS, ValueCutoff, - OnlyListBelow, ShowFunction, TextFormat, OS); + return showInstrProfile( + Filename, ShowCounts, TopNFunctions, ShowIndirectCallTargets, + ShowMemOPSizes, ShowDetailedSummary, DetailedSummaryCutoffs, + ShowAllFunctions, ShowCS, ValueCutoff, OnlyListBelow, ShowFunction, + TextFormat, ShowBinaryIds, OS); else return showSampleProfile(Filename, ShowCounts, ShowAllFunctions, ShowDetailedSummary, ShowFunction,