Index: include/llvm/ProfileData/SampleProf.h =================================================================== --- include/llvm/ProfileData/SampleProf.h +++ include/llvm/ProfileData/SampleProf.h @@ -78,11 +78,27 @@ namespace llvm { namespace sampleprof { -static inline uint64_t SPMagic() { +enum SampleProfileFormat { + SPF_None = 0, + SPF_Text = 0x1, + SPF_Compact_Binary = 0x2, + SPF_GCC = 0x3, + SPF_Raw_Binary = 0xff +}; + +static inline uint64_t SPMagic(SampleProfileFormat Format = SPF_Raw_Binary) { return uint64_t('S') << (64 - 8) | uint64_t('P') << (64 - 16) | uint64_t('R') << (64 - 24) | uint64_t('O') << (64 - 32) | uint64_t('F') << (64 - 40) | uint64_t('4') << (64 - 48) | - uint64_t('2') << (64 - 56) | uint64_t(0xff); + uint64_t('2') << (64 - 56) | uint64_t(Format); +} + +// Get the proper representation of a string in the input Format. +static inline StringRef getRepInFormat(StringRef Name, + SampleProfileFormat Format, + std::string &GUIDBuf) { + GUIDBuf = std::to_string(Function::getGUID(Name)); + return (Format == SPF_Compact_Binary) ? StringRef(GUIDBuf) : Name; } static inline uint64_t SPVersion() { return 103; } @@ -359,7 +375,7 @@ /// GUID to \p S. Also traverse the BodySamples to add hot CallTarget's GUID /// to \p S. void findInlinedFunctions(DenseSet &S, const Module *M, - uint64_t Threshold) const { + uint64_t Threshold, bool isCompact) const { if (TotalSamples <= Threshold) return; S.insert(Function::getGUID(Name)); @@ -370,11 +386,12 @@ if (TS.getValue() > Threshold) { Function *Callee = M->getFunction(TS.getKey()); if (!Callee || !Callee->getSubprogram()) - S.insert(Function::getGUID(TS.getKey())); + S.insert(isCompact ? std::stol(TS.getKey().data()) + : Function::getGUID(TS.getKey())); } for (const auto &CS : CallsiteSamples) for (const auto &NameFS : CS.second) - NameFS.second.findInlinedFunctions(S, M, Threshold); + NameFS.second.findInlinedFunctions(S, M, Threshold, isCompact); } /// Set the name of the function. Index: include/llvm/ProfileData/SampleProfReader.h =================================================================== --- include/llvm/ProfileData/SampleProfReader.h +++ include/llvm/ProfileData/SampleProfReader.h @@ -264,8 +264,9 @@ /// compact and I/O efficient. They can both be used interchangeably. class SampleProfileReader { public: - SampleProfileReader(std::unique_ptr B, LLVMContext &C) - : Profiles(0), Ctx(C), Buffer(std::move(B)) {} + SampleProfileReader(std::unique_ptr B, LLVMContext &C, + SampleProfileFormat Format = SPF_None) + : Profiles(0), Ctx(C), Buffer(std::move(B)), Format(Format) {} virtual ~SampleProfileReader() = default; @@ -286,8 +287,11 @@ // The function name may have been updated by adding suffix. In sample // profile, the function names are all stripped, so we need to strip // the function name suffix before matching with profile. - if (Profiles.count(F.getName().split('.').first)) - return &Profiles[(F.getName().split('.').first)]; + StringRef Fname = F.getName().split('.').first; + std::string FGUID; + Fname = getRepInFormat(Fname, getFormat(), FGUID); + if (Profiles.count(Fname)) + return &Profiles[Fname]; return nullptr; } @@ -311,6 +315,9 @@ /// Return the profile summary. ProfileSummary &getSummary() { return *(Summary.get()); } + /// \brief Return the profile format. + SampleProfileFormat getFormat() { return Format; } + protected: /// Map every function to its associated profile. /// @@ -330,12 +337,15 @@ /// Compute summary for this profile. void computeSummary(); + + /// \brief The format of sample. + SampleProfileFormat Format = SPF_None; }; class SampleProfileReaderText : public SampleProfileReader { public: SampleProfileReaderText(std::unique_ptr B, LLVMContext &C) - : SampleProfileReader(std::move(B), C) {} + : SampleProfileReader(std::move(B), C, SPF_Text) {} /// Read and validate the file header. std::error_code readHeader() override { return sampleprof_error::success; } @@ -349,8 +359,9 @@ class SampleProfileReaderBinary : public SampleProfileReader { public: - SampleProfileReaderBinary(std::unique_ptr B, LLVMContext &C) - : SampleProfileReader(std::move(B), C) {} + SampleProfileReaderBinary(std::unique_ptr B, LLVMContext &C, + SampleProfileFormat Format = SPF_None) + : SampleProfileReader(std::move(B), C, Format) {} /// Read and validate the file header. std::error_code readHeader() override; @@ -358,9 +369,6 @@ /// Read sample profiles from the associated file. std::error_code read() override; - /// Return true if \p Buffer is in the format supported by this class. - static bool hasFormat(const MemoryBuffer &Buffer); - protected: /// Read a numeric value of type T from the profile. /// @@ -378,8 +386,8 @@ /// \returns the read value. ErrorOr readString(); - /// Read a string indirectly via the name table. - ErrorOr readStringFromTable(); + /// Read the string index and check whether it overflows the table. + template inline ErrorOr readStringIndex(T &Table); /// Return true if we've reached the end of file. bool at_eof() const { return Data >= End; } @@ -393,14 +401,53 @@ /// Points to the end of the buffer. const uint8_t *End = nullptr; - /// Function name table. - std::vector NameTable; - private: std::error_code readSummaryEntry(std::vector &Entries); + virtual std::error_code verifySPMagic(uint64_t Magic) = 0; /// Read profile summary. std::error_code readSummary(); + + /// Read the whole name table. + virtual std::error_code readNameTable() = 0; + + /// Read a string indirectly via the name table. + virtual ErrorOr readStringFromTable() = 0; +}; + +class SampleProfileReaderRawBinary : public SampleProfileReaderBinary { +private: + /// Function name table. + std::vector NameTable; + virtual std::error_code verifySPMagic(uint64_t Magic) override; + virtual std::error_code readNameTable() override; + /// Read a string indirectly via the name table. + virtual ErrorOr readStringFromTable() override; + +public: + SampleProfileReaderRawBinary(std::unique_ptr B, LLVMContext &C) + : SampleProfileReaderBinary(std::move(B), C, SPF_Raw_Binary) {} + + /// \brief Return true if \p Buffer is in the format supported by this class. + static bool hasFormat(const MemoryBuffer &Buffer); +}; + +class SampleProfileReaderCompactBinary : public SampleProfileReaderBinary { +private: + /// Function name table. + std::vector NameTable; + virtual std::error_code verifySPMagic(uint64_t Magic) override; + virtual std::error_code readNameTable() override; + /// Read a string indirectly via the name table. + virtual ErrorOr readStringFromTable() override; + +public: + SampleProfileReaderCompactBinary(std::unique_ptr B, + LLVMContext &C) + : SampleProfileReaderBinary(std::move(B), C, SPF_Compact_Binary) {} + + /// \brief Return true if \p Buffer is in the format supported by this class. + static bool hasFormat(const MemoryBuffer &Buffer); }; using InlineCallStack = SmallVector; @@ -421,7 +468,8 @@ class SampleProfileReaderGCC : public SampleProfileReader { public: SampleProfileReaderGCC(std::unique_ptr B, LLVMContext &C) - : SampleProfileReader(std::move(B), C), GcovBuffer(Buffer.get()) {} + : SampleProfileReader(std::move(B), C, SPF_GCC), + GcovBuffer(Buffer.get()) {} /// Read and validate the file header. std::error_code readHeader() override; Index: include/llvm/ProfileData/SampleProfWriter.h =================================================================== --- include/llvm/ProfileData/SampleProfWriter.h +++ include/llvm/ProfileData/SampleProfWriter.h @@ -23,13 +23,12 @@ #include #include #include +#include #include namespace llvm { namespace sampleprof { -enum SampleProfileFormat { SPF_None = 0, SPF_Text, SPF_Binary, SPF_GCC }; - /// Sample-based profile writer. Base class. class SampleProfileWriter { public: @@ -105,28 +104,45 @@ class SampleProfileWriterBinary : public SampleProfileWriter { public: std::error_code write(const FunctionSamples &S) override; - -protected: SampleProfileWriterBinary(std::unique_ptr &OS) : SampleProfileWriter(OS) {} - std::error_code - writeHeader(const StringMap &ProfileMap) override; +protected: + virtual std::error_code writeNameTable() = 0; + virtual std::error_code writeMagicIdent() = 0; + std::error_code writeHeader(const StringMap &ProfileMap); std::error_code writeSummary(); std::error_code writeNameIdx(StringRef FName); std::error_code writeBody(const FunctionSamples &S); + inline void stablizeNameTable(std::set &V); + + MapVector NameTable; private: void addName(StringRef FName); void addNames(const FunctionSamples &S); - MapVector NameTable; - friend ErrorOr> SampleProfileWriter::create(std::unique_ptr &OS, SampleProfileFormat Format); }; +class SampleProfileWriterRawBinary : public SampleProfileWriterBinary { + using SampleProfileWriterBinary::SampleProfileWriterBinary; + +protected: + virtual std::error_code writeNameTable() override; + virtual std::error_code writeMagicIdent() override; +}; + +class SampleProfileWriterCompactBinary : public SampleProfileWriterBinary { + using SampleProfileWriterBinary::SampleProfileWriterBinary; + +protected: + virtual std::error_code writeNameTable() override; + virtual std::error_code writeMagicIdent() override; +}; + } // end namespace sampleprof } // end namespace llvm Index: lib/ProfileData/SampleProfReader.cpp =================================================================== --- lib/ProfileData/SampleProfReader.cpp +++ lib/ProfileData/SampleProfReader.cpp @@ -319,16 +319,33 @@ return Str; } -ErrorOr SampleProfileReaderBinary::readStringFromTable() { +template +inline ErrorOr SampleProfileReaderBinary::readStringIndex(T &Table) { std::error_code EC; auto Idx = readNumber(); if (std::error_code EC = Idx.getError()) return EC; - if (*Idx >= NameTable.size()) + if (*Idx >= Table.size()) return sampleprof_error::truncated_name_table; + return *Idx; +} + +ErrorOr SampleProfileReaderRawBinary::readStringFromTable() { + auto Idx = readStringIndex(NameTable); + if (std::error_code EC = Idx.getError()) + return EC; + return NameTable[*Idx]; } +ErrorOr SampleProfileReaderCompactBinary::readStringFromTable() { + auto Idx = readStringIndex(NameTable); + if (std::error_code EC = Idx.getError()) + return EC; + + return StringRef(NameTable[*Idx]); +} + std::error_code SampleProfileReaderBinary::readProfile(FunctionSamples &FProfile) { auto NumSamples = readNumber(); @@ -429,6 +446,48 @@ return sampleprof_error::success; } +std::error_code SampleProfileReaderRawBinary::verifySPMagic(uint64_t Magic) { + if (Magic == SPMagic()) + return sampleprof_error::success; + return sampleprof_error::bad_magic; +} + +std::error_code +SampleProfileReaderCompactBinary::verifySPMagic(uint64_t Magic) { + if (Magic == SPMagic(SPF_Compact_Binary)) + return sampleprof_error::success; + return sampleprof_error::bad_magic; +} + +std::error_code SampleProfileReaderRawBinary::readNameTable() { + auto Size = readNumber(); + if (std::error_code EC = Size.getError()) + return EC; + NameTable.reserve(*Size); + for (uint32_t I = 0; I < *Size; ++I) { + auto Name(readString()); + if (std::error_code EC = Name.getError()) + return EC; + NameTable.push_back(*Name); + } + + return sampleprof_error::success; +} + +std::error_code SampleProfileReaderCompactBinary::readNameTable() { + auto Size = readNumber(); + if (std::error_code EC = Size.getError()) + return EC; + NameTable.reserve(*Size); + for (uint32_t I = 0; I < *Size; ++I) { + auto FID = readNumber(); + if (std::error_code EC = FID.getError()) + return EC; + NameTable.push_back(std::to_string(*FID)); + } + return sampleprof_error::success; +} + std::error_code SampleProfileReaderBinary::readHeader() { Data = reinterpret_cast(Buffer->getBufferStart()); End = Data + Buffer->getBufferSize(); @@ -437,7 +496,7 @@ auto Magic = readNumber(); if (std::error_code EC = Magic.getError()) return EC; - else if (*Magic != SPMagic()) + else if (std::error_code EC = verifySPMagic(*Magic)) return sampleprof_error::bad_magic; // Read the version number. @@ -450,18 +509,8 @@ if (std::error_code EC = readSummary()) return EC; - // Read the name table. - auto Size = readNumber(); - if (std::error_code EC = Size.getError()) + if (std::error_code EC = readNameTable()) return EC; - NameTable.reserve(*Size); - for (uint32_t I = 0; I < *Size; ++I) { - auto Name(readString()); - if (std::error_code EC = Name.getError()) - return EC; - NameTable.push_back(*Name); - } - return sampleprof_error::success; } @@ -521,13 +570,20 @@ return sampleprof_error::success; } -bool SampleProfileReaderBinary::hasFormat(const MemoryBuffer &Buffer) { +bool SampleProfileReaderRawBinary::hasFormat(const MemoryBuffer &Buffer) { const uint8_t *Data = reinterpret_cast(Buffer.getBufferStart()); uint64_t Magic = decodeULEB128(Data); return Magic == SPMagic(); } +bool SampleProfileReaderCompactBinary::hasFormat(const MemoryBuffer &Buffer) { + const uint8_t *Data = + reinterpret_cast(Buffer.getBufferStart()); + uint64_t Magic = decodeULEB128(Data); + return Magic == SPMagic(SPF_Compact_Binary); +} + std::error_code SampleProfileReaderGCC::skipNextWord() { uint32_t dummy; if (!GcovBuffer.readInt(dummy)) @@ -813,8 +869,10 @@ ErrorOr> SampleProfileReader::create(std::unique_ptr &B, LLVMContext &C) { std::unique_ptr Reader; - if (SampleProfileReaderBinary::hasFormat(*B)) - Reader.reset(new SampleProfileReaderBinary(std::move(B), C)); + if (SampleProfileReaderRawBinary::hasFormat(*B)) + Reader.reset(new SampleProfileReaderRawBinary(std::move(B), C)); + else if (SampleProfileReaderCompactBinary::hasFormat(*B)) + Reader.reset(new SampleProfileReaderCompactBinary(std::move(B), C)); else if (SampleProfileReaderGCC::hasFormat(*B)) Reader.reset(new SampleProfileReaderGCC(std::move(B), C)); else if (SampleProfileReaderText::hasFormat(*B)) Index: lib/ProfileData/SampleProfWriter.cpp =================================================================== --- lib/ProfileData/SampleProfWriter.cpp +++ lib/ProfileData/SampleProfWriter.cpp @@ -25,6 +25,7 @@ #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/LEB128.h" +#include "llvm/Support/MD5.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -144,13 +145,61 @@ } } -std::error_code SampleProfileWriterBinary::writeHeader( - const StringMap &ProfileMap) { +void SampleProfileWriterBinary::stablizeNameTable(std::set &V) { + // Sort the names to make NameTable deterministic. + for (const auto &I : NameTable) + V.insert(I.first); + int i = 0; + for (const StringRef &N : V) + NameTable[N] = i++; +} + +std::error_code SampleProfileWriterRawBinary::writeNameTable() { auto &OS = *OutputStream; + std::set V; + stablizeNameTable(V); + + // Write out the name table. + encodeULEB128(NameTable.size(), OS); + for (auto N : V) { + OS << N; + encodeULEB128(0, OS); + } + return sampleprof_error::success; +} + +std::error_code SampleProfileWriterCompactBinary::writeNameTable() { + auto &OS = *OutputStream; + std::set V; + stablizeNameTable(V); + + // Write out the name table. + encodeULEB128(NameTable.size(), OS); + for (auto N : V) { + encodeULEB128(MD5Hash(N), OS); + } + return sampleprof_error::success; +} +std::error_code SampleProfileWriterRawBinary::writeMagicIdent() { + auto &OS = *OutputStream; // Write file magic identifier. encodeULEB128(SPMagic(), OS); encodeULEB128(SPVersion(), OS); + return sampleprof_error::success; +} + +std::error_code SampleProfileWriterCompactBinary::writeMagicIdent() { + auto &OS = *OutputStream; + // Write file magic identifier. + encodeULEB128(SPMagic(SPF_Compact_Binary), OS); + encodeULEB128(SPVersion(), OS); + return sampleprof_error::success; +} + +std::error_code SampleProfileWriterBinary::writeHeader( + const StringMap &ProfileMap) { + writeMagicIdent(); computeSummary(ProfileMap); if (auto EC = writeSummary()) @@ -162,20 +211,7 @@ addNames(I.second); } - // Sort the names to make NameTable is deterministic. - std::set V; - for (const auto &I : NameTable) - V.insert(I.first); - int i = 0; - for (const StringRef &N : V) - NameTable[N] = i++; - - // Write out the name table. - encodeULEB128(NameTable.size(), OS); - for (auto N : V) { - OS << N; - encodeULEB128(0, OS); - } + writeNameTable(); return sampleprof_error::success; } @@ -258,7 +294,7 @@ SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) { std::error_code EC; std::unique_ptr OS; - if (Format == SPF_Binary) + if (Format == SPF_Raw_Binary || Format == SPF_Compact_Binary) OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::F_None)); else OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::F_Text)); @@ -281,8 +317,10 @@ std::error_code EC; std::unique_ptr Writer; - if (Format == SPF_Binary) - Writer.reset(new SampleProfileWriterBinary(OS)); + if (Format == SPF_Raw_Binary) + Writer.reset(new SampleProfileWriterRawBinary(OS)); + else if (Format == SPF_Compact_Binary) + Writer.reset(new SampleProfileWriterCompactBinary(OS)); else if (Format == SPF_Text) Writer.reset(new SampleProfileWriterText(OS)); else if (Format == SPF_GCC) Index: lib/Transforms/IPO/SampleProfile.cpp =================================================================== --- lib/Transforms/IPO/SampleProfile.cpp +++ lib/Transforms/IPO/SampleProfile.cpp @@ -638,6 +638,8 @@ if (FS == nullptr) return nullptr; + std::string CalleeGUID; + CalleeName = getRepInFormat(CalleeName, Reader->getFormat(), CalleeGUID); return FS->findFunctionSamplesAt(LineLocation(FunctionSamples::getOffset(DIL), DIL->getBaseDiscriminator()), CalleeName); @@ -753,6 +755,7 @@ Function &F, DenseSet &InlinedGUIDs) { DenseSet PromotedInsns; bool Changed = false; + bool isCompact = (Reader->getFormat() == SPF_Compact_Binary); while (true) { bool LocalChanged = false; SmallVector CIS; @@ -784,7 +787,8 @@ for (const auto *FS : findIndirectCallFunctionSamples(*I, Sum)) { if (IsThinLTOPreLink) { FS->findInlinedFunctions(InlinedGUIDs, F.getParent(), - PSI->getOrCompHotCountThreshold()); + PSI->getOrCompHotCountThreshold(), + isCompact); continue; } auto CalleeFunctionName = FS->getName(); @@ -793,7 +797,9 @@ // clone the caller first, and inline the cloned caller if it is // recursive. As llvm does not inline recursive calls, we will // simply ignore it instead of handling it explicitly. - if (CalleeFunctionName == F.getName()) + std::string FGUID; + auto Fname = getRepInFormat(F.getName(), Reader->getFormat(), FGUID); + if (CalleeFunctionName == Fname) continue; const char *Reason = "Callee function not available"; @@ -823,7 +829,8 @@ LocalChanged = true; } else if (IsThinLTOPreLink) { findCalleeFunctionSamples(*I)->findInlinedFunctions( - InlinedGUIDs, F.getParent(), PSI->getOrCompHotCountThreshold()); + InlinedGUIDs, F.getParent(), PSI->getOrCompHotCountThreshold(), + isCompact); } } if (LocalChanged) { Index: test/Transforms/SampleProfile/compact-binary-profile.ll =================================================================== --- test/Transforms/SampleProfile/compact-binary-profile.ll +++ test/Transforms/SampleProfile/compact-binary-profile.ll @@ -0,0 +1,121 @@ +; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/inline.prof -S | FileCheck %s +; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/inline.prof -S | FileCheck %s +; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/inline.compactbinary.afdo -S | FileCheck %s +; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/inline.compactbinary.afdo -S | FileCheck %s + +; Original C++ test case +; +; #include +; +; int sum(int x, int y) { +; return x + y; +; } +; +; int main() { +; int s, i = 0; +; while (i++ < 20000 * 20000) +; if (i != 100) s = sum(i, s); else s = 30; +; printf("sum is %d\n", s); +; return 0; +; } +; +@.str = private unnamed_addr constant [11 x i8] c"sum is %d\0A\00", align 1 + +; Check sample-profile phase using compactbinary format profile will annotate +; the IR with exactly the same result as using text format. +; CHECK: br i1 %cmp, label %while.body, label %while.end{{.*}} !prof ![[IDX1:[0-9]*]] +; CHECK: br i1 %cmp1, label %if.then, label %if.else{{.*}} !prof ![[IDX2:[0-9]*]] +; CHECK: call i32 (i8*, ...) @printf{{.*}} !prof ![[IDX3:[0-9]*]] +; CHECK: = !{!"TotalCount", i64 10944} +; CHECK: = !{!"MaxCount", i64 5553} +; CHECK: ![[IDX1]] = !{!"branch_weights", i32 5392, i32 163} +; CHECK: ![[IDX2]] = !{!"branch_weights", i32 5280, i32 113} +; CHECK: ![[IDX3]] = !{!"branch_weights", i32 1} + +; Function Attrs: nounwind uwtable +define i32 @_Z3sumii(i32 %x, i32 %y) !dbg !4 { +entry: + %x.addr = alloca i32, align 4 + %y.addr = alloca i32, align 4 + store i32 %x, i32* %x.addr, align 4 + store i32 %y, i32* %y.addr, align 4 + %0 = load i32, i32* %x.addr, align 4, !dbg !11 + %1 = load i32, i32* %y.addr, align 4, !dbg !11 + %add = add nsw i32 %0, %1, !dbg !11 + ret i32 %add, !dbg !11 +} + +; Function Attrs: uwtable +define i32 @main() !dbg !7 { +entry: + %retval = alloca i32, align 4 + %s = alloca i32, align 4 + %i = alloca i32, align 4 + store i32 0, i32* %retval + store i32 0, i32* %i, align 4, !dbg !12 + br label %while.cond, !dbg !13 + +while.cond: ; preds = %if.end, %entry + %0 = load i32, i32* %i, align 4, !dbg !14 + %inc = add nsw i32 %0, 1, !dbg !14 + store i32 %inc, i32* %i, align 4, !dbg !14 + %cmp = icmp slt i32 %0, 400000000, !dbg !14 + br i1 %cmp, label %while.body, label %while.end, !dbg !14 + +while.body: ; preds = %while.cond + %1 = load i32, i32* %i, align 4, !dbg !16 + %cmp1 = icmp ne i32 %1, 100, !dbg !16 + br i1 %cmp1, label %if.then, label %if.else, !dbg !16 + + +if.then: ; preds = %while.body + %2 = load i32, i32* %i, align 4, !dbg !18 + %3 = load i32, i32* %s, align 4, !dbg !18 + %call = call i32 @_Z3sumii(i32 %2, i32 %3), !dbg !18 + store i32 %call, i32* %s, align 4, !dbg !18 + br label %if.end, !dbg !18 + +if.else: ; preds = %while.body + store i32 30, i32* %s, align 4, !dbg !20 + br label %if.end + +if.end: ; preds = %if.else, %if.then + br label %while.cond, !dbg !22 + +while.end: ; preds = %while.cond + %4 = load i32, i32* %s, align 4, !dbg !24 + %call2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str, i32 0, i32 0), i32 %4), !dbg !24 + ret i32 0, !dbg !25 +} + +declare i32 @printf(i8*, ...) #2 + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!8, !9} +!llvm.ident = !{!10} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, producer: "clang version 3.5 ", isOptimized: false, emissionKind: NoDebug, file: !1, enums: !2, retainedTypes: !2, globals: !2, imports: !2) +!1 = !DIFile(filename: "calls.cc", directory: ".") +!2 = !{} +!4 = distinct !DISubprogram(name: "sum", line: 3, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 3, file: !1, scope: !5, type: !6, retainedNodes: !2) +!5 = !DIFile(filename: "calls.cc", directory: ".") +!6 = !DISubroutineType(types: !2) +!7 = distinct !DISubprogram(name: "main", line: 7, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 7, file: !1, scope: !5, type: !6, retainedNodes: !2) +!8 = !{i32 2, !"Dwarf Version", i32 4} +!9 = !{i32 1, !"Debug Info Version", i32 3} +!10 = !{!"clang version 3.5 "} +!11 = !DILocation(line: 4, scope: !4) +!12 = !DILocation(line: 8, scope: !7) +!13 = !DILocation(line: 9, scope: !7) +!14 = !DILocation(line: 9, scope: !15) +!15 = !DILexicalBlockFile(discriminator: 2, file: !1, scope: !7) +!16 = !DILocation(line: 10, scope: !17) +!17 = distinct !DILexicalBlock(line: 10, column: 0, file: !1, scope: !7) +!18 = !DILocation(line: 10, scope: !19) +!19 = !DILexicalBlockFile(discriminator: 2, file: !1, scope: !17) +!20 = !DILocation(line: 10, scope: !21) +!21 = !DILexicalBlockFile(discriminator: 4, file: !1, scope: !17) +!22 = !DILocation(line: 10, scope: !23) +!23 = !DILexicalBlockFile(discriminator: 6, file: !1, scope: !17) +!24 = !DILocation(line: 11, scope: !7) +!25 = !DILocation(line: 12, scope: !7) Index: tools/llvm-profdata/llvm-profdata.cpp =================================================================== --- tools/llvm-profdata/llvm-profdata.cpp +++ tools/llvm-profdata/llvm-profdata.cpp @@ -34,7 +34,13 @@ using namespace llvm; -enum ProfileFormat { PF_None = 0, PF_Text, PF_Binary, PF_GCC }; +enum ProfileFormat { + PF_None = 0, + PF_Text, + PF_Compact_Binary, + PF_GCC, + PF_Raw_Binary +}; static void warn(Twine Message, std::string Whence = "", std::string Hint = "") { @@ -236,7 +242,8 @@ if (OutputFilename.compare("-") == 0) exitWithError("Cannot write indexed profdata format to stdout."); - if (OutputFormat != PF_Binary && OutputFormat != PF_Text) + if (OutputFormat != PF_Raw_Binary && OutputFormat != PF_Compact_Binary && + OutputFormat != PF_Text) exitWithError("Unknown format is specified."); std::error_code EC; @@ -316,8 +323,8 @@ } static sampleprof::SampleProfileFormat FormatMap[] = { - sampleprof::SPF_None, sampleprof::SPF_Text, sampleprof::SPF_Binary, - sampleprof::SPF_GCC}; + sampleprof::SPF_None, sampleprof::SPF_Text, sampleprof::SPF_Compact_Binary, + sampleprof::SPF_GCC, sampleprof::SPF_Raw_Binary}; static void mergeSampleProfile(const WeightedFileVector &Inputs, StringRef OutputFilename, @@ -464,11 +471,14 @@ cl::values(clEnumVal(instr, "Instrumentation profile (default)"), clEnumVal(sample, "Sample profile"))); cl::opt OutputFormat( - cl::desc("Format of output profile"), cl::init(PF_Binary), - cl::values(clEnumValN(PF_Binary, "binary", "Binary encoding (default)"), - clEnumValN(PF_Text, "text", "Text encoding"), - clEnumValN(PF_GCC, "gcc", - "GCC encoding (only meaningful for -sample)"))); + cl::desc("Format of output profile"), cl::init(PF_Raw_Binary), + cl::values( + clEnumValN(PF_Raw_Binary, "binary", "Binary encoding (default)"), + clEnumValN(PF_Compact_Binary, "compbinary", + "Compact binary encoding (default)"), + clEnumValN(PF_Text, "text", "Text encoding"), + clEnumValN(PF_GCC, "gcc", + "GCC encoding (only meaningful for -sample)"))); cl::opt OutputSparse("sparse", cl::init(false), cl::desc("Generate a sparse profile (only meaningful for -instr)")); cl::opt NumThreads( Index: unittests/ProfileData/SampleProfTest.cpp =================================================================== --- unittests/ProfileData/SampleProfTest.cpp +++ unittests/ProfileData/SampleProfTest.cpp @@ -77,9 +77,11 @@ BarSamples.addTotalSamples(20301); BarSamples.addHeadSamples(1437); BarSamples.addBodySamples(1, 0, 1437); - BarSamples.addCalledTargetSamples(1, 0, "_M_construct", 1000); - BarSamples.addCalledTargetSamples( - 1, 0, "string_view >", 437); + // Test how reader/writer handles unmangled names. + StringRef MconstructName("_M_construct"); + StringRef StringviewName("string_view >"); + BarSamples.addCalledTargetSamples(1, 0, MconstructName, 1000); + BarSamples.addCalledTargetSamples(1, 0, StringviewName, 437); StringMap Profiles; Profiles[FooName] = std::move(FooSamples); @@ -100,18 +102,29 @@ StringMap &ReadProfiles = Reader->getProfiles(); ASSERT_EQ(2u, ReadProfiles.size()); - FunctionSamples &ReadFooSamples = ReadProfiles[FooName]; + std::string FooGUID; + StringRef FooRep = getRepInFormat(FooName, Format, FooGUID); + FunctionSamples &ReadFooSamples = ReadProfiles[FooRep]; ASSERT_EQ(7711u, ReadFooSamples.getTotalSamples()); ASSERT_EQ(610u, ReadFooSamples.getHeadSamples()); - FunctionSamples &ReadBarSamples = ReadProfiles[BarName]; + std::string BarGUID; + StringRef BarRep = getRepInFormat(BarName, Format, BarGUID); + FunctionSamples &ReadBarSamples = ReadProfiles[BarRep]; ASSERT_EQ(20301u, ReadBarSamples.getTotalSamples()); ASSERT_EQ(1437u, ReadBarSamples.getHeadSamples()); ErrorOr CTMap = ReadBarSamples.findCallTargetMapAt(1, 0); ASSERT_FALSE(CTMap.getError()); - ASSERT_EQ(1000u, CTMap.get()["_M_construct"]); - ASSERT_EQ(437u, CTMap.get()["string_view >"]); + + std::string MconstructGUID; + StringRef MconstructRep = + getRepInFormat(MconstructName, Format, MconstructGUID); + std::string StringviewGUID; + StringRef StringviewRep = + getRepInFormat(StringviewName, Format, StringviewGUID); + ASSERT_EQ(1000u, CTMap.get()[MconstructRep]); + ASSERT_EQ(437u, CTMap.get()[StringviewRep]); auto VerifySummary = [](ProfileSummary &Summary) mutable { ASSERT_EQ(ProfileSummary::PSK_Sample, Summary.getKind()); @@ -166,8 +179,12 @@ testRoundTrip(SampleProfileFormat::SPF_Text); } -TEST_F(SampleProfTest, roundtrip_binary_profile) { - testRoundTrip(SampleProfileFormat::SPF_Binary); +TEST_F(SampleProfTest, roundtrip_raw_binary_profile) { + testRoundTrip(SampleProfileFormat::SPF_Raw_Binary); +} + +TEST_F(SampleProfTest, roundtrip_compact_binary_profile) { + testRoundTrip(SampleProfileFormat::SPF_Compact_Binary); } TEST_F(SampleProfTest, sample_overflow_saturation) {