From 82672e4cd7cb37989a28e2ea65c99008a82794c3 Mon Sep 17 00:00:00 2001 From: Wei Mi Date: Mon, 11 Jun 2018 22:40:43 +0000 Subject: [PATCH] [SampleFDO] Add a new compact binary format for sample profile. Name table occupies a big chunk of size in current binary format sample profile. In order to reduce its size, the patch changes the sample writer/reader to save/restore MD5Hash of names in the name table. Sample annotation phase will also use MD5Hash of name to query samples accordingly. Experiment shows compact binary format can reduce the size of sample profile by 2/3 compared with binary format generally. Differential Revision: https://reviews.llvm.org/D47955 llvm-svn: 334447 --- include/llvm/ProfileData/SampleProf.h | 27 +++- include/llvm/ProfileData/SampleProfReader.h | 80 +++++++++--- include/llvm/ProfileData/SampleProfWriter.h | 32 +++-- lib/ProfileData/SampleProfReader.cpp | 92 ++++++++++--- lib/ProfileData/SampleProfWriter.cpp | 78 ++++++++--- lib/Transforms/IPO/SampleProfile.cpp | 13 +- .../Inputs/inline.compactbinary.afdo | Bin 0 -> 172 bytes .../SampleProfile/compact-binary-profile.ll | 121 ++++++++++++++++++ tools/llvm-profdata/llvm-profdata.cpp | 28 ++-- unittests/ProfileData/SampleProfTest.cpp | 35 +++-- 10 files changed, 419 insertions(+), 87 deletions(-) create mode 100644 test/Transforms/SampleProfile/Inputs/inline.compactbinary.afdo create mode 100644 test/Transforms/SampleProfile/compact-binary-profile.ll diff --git a/include/llvm/ProfileData/SampleProf.h b/include/llvm/ProfileData/SampleProf.h index e5bbf34566e..5103751da35 100644 --- a/include/llvm/ProfileData/SampleProf.h +++ b/include/llvm/ProfileData/SampleProf.h @@ -78,11 +78,27 @@ struct is_error_code_enum : std::true_type {}; 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 @@ public: /// 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 @@ public: 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. diff --git a/include/llvm/ProfileData/SampleProfReader.h b/include/llvm/ProfileData/SampleProfReader.h index f1ef76af0e7..f15336fefea 100644 --- a/include/llvm/ProfileData/SampleProfReader.h +++ b/include/llvm/ProfileData/SampleProfReader.h @@ -264,8 +264,9 @@ namespace sampleprof { /// 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 @@ public: // 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 @@ public: /// 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 @@ protected: /// 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 @@ public: 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 @@ public: /// 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 @@ protected: /// \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 @@ protected: /// 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 @@ enum HistType { 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; diff --git a/include/llvm/ProfileData/SampleProfWriter.h b/include/llvm/ProfileData/SampleProfWriter.h index 3c5293f13e5..f76c14f7c09 100644 --- a/include/llvm/ProfileData/SampleProfWriter.h +++ b/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 @@ private: 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 diff --git a/lib/ProfileData/SampleProfReader.cpp b/lib/ProfileData/SampleProfReader.cpp index e192b58de9c..345549e4668 100644 --- a/lib/ProfileData/SampleProfReader.cpp +++ b/lib/ProfileData/SampleProfReader.cpp @@ -319,16 +319,33 @@ ErrorOr SampleProfileReaderBinary::readString() { 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 @@ std::error_code SampleProfileReaderBinary::read() { 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 @@ std::error_code SampleProfileReaderBinary::readHeader() { 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 @@ std::error_code SampleProfileReaderBinary::readHeader() { 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 @@ std::error_code SampleProfileReaderBinary::readSummary() { 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 @@ SampleProfileReader::create(const Twine &Filename, LLVMContext &C) { 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)) diff --git a/lib/ProfileData/SampleProfWriter.cpp b/lib/ProfileData/SampleProfWriter.cpp index 45c81782a0c..092139d4aa9 100644 --- a/lib/ProfileData/SampleProfWriter.cpp +++ b/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 @@ void SampleProfileWriterBinary::addNames(const FunctionSamples &S) { } } -std::error_code SampleProfileWriterBinary::writeHeader( - const StringMap &ProfileMap) { - auto &OS = *OutputStream; +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 @@ std::error_code SampleProfileWriterBinary::writeHeader( 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 @@ ErrorOr> 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 @@ SampleProfileWriter::create(std::unique_ptr &OS, 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) diff --git a/lib/Transforms/IPO/SampleProfile.cpp b/lib/Transforms/IPO/SampleProfile.cpp index 1c53a82cf8a..357a7d1148c 100644 --- a/lib/Transforms/IPO/SampleProfile.cpp +++ b/lib/Transforms/IPO/SampleProfile.cpp @@ -638,6 +638,8 @@ SampleProfileLoader::findCalleeFunctionSamples(const Instruction &Inst) const { 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 @@ bool SampleProfileLoader::inlineHotFunctions( 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 @@ bool SampleProfileLoader::inlineHotFunctions( 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 @@ bool SampleProfileLoader::inlineHotFunctions( // 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 @@ bool SampleProfileLoader::inlineHotFunctions( LocalChanged = true; } else if (IsThinLTOPreLink) { findCalleeFunctionSamples(*I)->findInlinedFunctions( - InlinedGUIDs, F.getParent(), PSI->getOrCompHotCountThreshold()); + InlinedGUIDs, F.getParent(), PSI->getOrCompHotCountThreshold(), + isCompact); } } if (LocalChanged) { diff --git a/test/Transforms/SampleProfile/Inputs/inline.compactbinary.afdo b/test/Transforms/SampleProfile/Inputs/inline.compactbinary.afdo new file mode 100644 index 0000000000000000000000000000000000000000..805809952f012721fa12f931a9415f8d8969285a GIT binary patch literal 172 zcmZpAa$)0_lT%g%rymI2sLjB{C@{fqqc-D$UN#_kU=|OMe6U;yNH%Ph0Er)x1Bstk z>DOX +; +; 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) diff --git a/tools/llvm-profdata/llvm-profdata.cpp b/tools/llvm-profdata/llvm-profdata.cpp index cb043837134..842f30fc3e9 100644 --- a/tools/llvm-profdata/llvm-profdata.cpp +++ b/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 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs, 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 void mergeInstrProfile(const WeightedFileVector &Inputs, } 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 @@ static int merge_main(int argc, const char *argv[]) { 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( diff --git a/unittests/ProfileData/SampleProfTest.cpp b/unittests/ProfileData/SampleProfTest.cpp index 412f36f5c9c..bc19eb5f07c 100644 --- a/unittests/ProfileData/SampleProfTest.cpp +++ b/unittests/ProfileData/SampleProfTest.cpp @@ -77,9 +77,11 @@ struct SampleProfTest : ::testing::Test { 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 @@ struct SampleProfTest : ::testing::Test { 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 @@ TEST_F(SampleProfTest, roundtrip_text_profile) { 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) {