diff --git a/include/llvm/IR/ProfileSummary.h b/include/llvm/IR/ProfileSummary.h new file mode 100644 index 00000000000..5da87f3b5fe --- /dev/null +++ b/include/llvm/IR/ProfileSummary.h @@ -0,0 +1,129 @@ +//===-- ProfileSummary.h - Profile summary data structure. ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the profile summary data structure. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_PROFILE_SUMMARY_H +#define LLVM_SUPPORT_PROFILE_SUMMARY_H + +#include +#include + +#include "llvm/Support/Casting.h" + +namespace llvm { + +class LLVMContext; +class Metadata; +class MDTuple; +class MDNode; + +// The profile summary is one or more (Cutoff, MinCount, NumCounts) triplets. +// The semantics of counts depend on the type of profile. For instrumentation +// profile, counts are block counts and for sample profile, counts are +// per-line samples. Given a target counts percentile, we compute the minimum +// number of counts needed to reach this target and the minimum among these +// counts. +struct ProfileSummaryEntry { + uint32_t Cutoff; ///< The required percentile of counts. + uint64_t MinCount; ///< The minimum count for this percentile. + uint64_t NumCounts; ///< Number of counts >= the minimum count. + ProfileSummaryEntry(uint32_t TheCutoff, uint64_t TheMinCount, + uint64_t TheNumCounts) + : Cutoff(TheCutoff), MinCount(TheMinCount), NumCounts(TheNumCounts) {} +}; + +typedef std::vector SummaryEntryVector; + +class ProfileSummary { +public: + enum Kind { PSK_Instr, PSK_Sample }; + +private: + const Kind PSK; + static const char *KindStr[2]; + +protected: + SummaryEntryVector DetailedSummary; + uint64_t TotalCount, MaxCount, MaxFunctionCount; + uint32_t NumCounts, NumFunctions; + ProfileSummary(Kind K, SummaryEntryVector DetailedSummary, + uint64_t TotalCount, uint64_t MaxCount, + uint64_t MaxFunctionCount, uint32_t NumCounts, + uint32_t NumFunctions) + : PSK(K), DetailedSummary(DetailedSummary), TotalCount(TotalCount), + MaxCount(MaxCount), MaxFunctionCount(MaxFunctionCount), + NumCounts(NumCounts), NumFunctions(NumFunctions) {} + ~ProfileSummary() = default; + /// \brief Return metadata specific to the profile format. + /// Derived classes implement this method to return a vector of Metadata. + virtual std::vector getFormatSpecificMD(LLVMContext &Context) = 0; + /// \brief Return detailed summary as metadata. + Metadata *getDetailedSummaryMD(LLVMContext &Context); + +public: + static const int Scale = 1000000; + Kind getKind() const { return PSK; } + const char *getKindStr() const { return KindStr[PSK]; } + /// \brief Return summary information as metadata. + Metadata *getMD(LLVMContext &Context); + /// \brief Construct profile summary from metdata. + static ProfileSummary *getFromMD(Metadata *MD); + SummaryEntryVector &getDetailedSummary() { return DetailedSummary; } + uint32_t getNumFunctions() { return NumFunctions; } + uint64_t getMaxFunctionCount() { return MaxFunctionCount; } +}; + +class InstrProfSummary final : public ProfileSummary { + uint64_t MaxInternalBlockCount; + +protected: + std::vector getFormatSpecificMD(LLVMContext &Context) override; + +public: + InstrProfSummary(uint64_t TotalCount, uint64_t MaxBlockCount, + uint64_t MaxInternalBlockCount, uint64_t MaxFunctionCount, + uint32_t NumBlocks, uint32_t NumFunctions, + SummaryEntryVector Summary) + : ProfileSummary(PSK_Instr, Summary, TotalCount, MaxBlockCount, + MaxFunctionCount, NumBlocks, NumFunctions), + MaxInternalBlockCount(MaxInternalBlockCount) {} + static bool classof(const ProfileSummary *PS) { + return PS->getKind() == PSK_Instr; + } + uint32_t getNumBlocks() { return NumCounts; } + uint64_t getTotalCount() { return TotalCount; } + uint64_t getMaxBlockCount() { return MaxCount; } + uint64_t getMaxInternalBlockCount() { return MaxInternalBlockCount; } +}; + +class SampleProfileSummary final : public ProfileSummary { +protected: + std::vector getFormatSpecificMD(LLVMContext &Context) override; + +public: + uint32_t getNumLinesWithSamples() { return NumCounts; } + uint64_t getTotalSamples() { return TotalCount; } + uint64_t getMaxSamplesPerLine() { return MaxCount; } + SampleProfileSummary(uint64_t TotalSamples, uint64_t MaxSamplesPerLine, + uint64_t MaxFunctionCount, int32_t NumLinesWithSamples, + uint32_t NumFunctions, + SummaryEntryVector DetailedSummary) + : ProfileSummary(PSK_Sample, DetailedSummary, TotalSamples, + MaxSamplesPerLine, MaxFunctionCount, NumLinesWithSamples, + NumFunctions) {} + static bool classof(const ProfileSummary *PS) { + return PS->getKind() == PSK_Sample; + } +}; + +} // end namespace llvm +#endif diff --git a/include/llvm/ProfileData/ProfileCommon.h b/include/llvm/ProfileData/ProfileCommon.h index 2702d6fc6ae..79eee91c3d7 100644 --- a/include/llvm/ProfileData/ProfileCommon.h +++ b/include/llvm/ProfileData/ProfileCommon.h @@ -20,7 +20,7 @@ #include #include -#include "llvm/Support/Casting.h" +#include "llvm/IR/ProfileSummary.h" #include "llvm/Support/Error.h" namespace llvm { @@ -40,134 +40,54 @@ class MDNode; inline const char *getHotSectionPrefix() { return ".hot"; } inline const char *getUnlikelySectionPrefix() { return ".unlikely"; } -// The profile summary is one or more (Cutoff, MinCount, NumCounts) triplets. -// The semantics of counts depend on the type of profile. For instrumentation -// profile, counts are block counts and for sample profile, counts are -// per-line samples. Given a target counts percentile, we compute the minimum -// number of counts needed to reach this target and the minimum among these -// counts. -struct ProfileSummaryEntry { - uint32_t Cutoff; ///< The required percentile of counts. - uint64_t MinCount; ///< The minimum count for this percentile. - uint64_t NumCounts; ///< Number of counts >= the minimum count. - ProfileSummaryEntry(uint32_t TheCutoff, uint64_t TheMinCount, - uint64_t TheNumCounts) - : Cutoff(TheCutoff), MinCount(TheMinCount), NumCounts(TheNumCounts) {} -}; - -typedef std::vector SummaryEntryVector; - -class ProfileSummary { -public: - enum Kind { PSK_Instr, PSK_Sample }; +class ProfileSummaryBuilder { private: - const Kind PSK; - static const char *KindStr[2]; // We keep track of the number of times a count (block count or samples) // appears in the profile. The map is kept sorted in the descending order of // counts. std::map> CountFrequencies; + std::vector DetailedSummaryCutoffs; + protected: SummaryEntryVector DetailedSummary; - std::vector DetailedSummaryCutoffs; + ProfileSummaryBuilder(std::vector Cutoffs) + : DetailedSummaryCutoffs(Cutoffs), TotalCount(0), MaxCount(0), + MaxFunctionCount(0), NumCounts(0), NumFunctions(0) {} + inline void addCount(uint64_t Count); + ~ProfileSummaryBuilder() = default; + void computeDetailedSummary(); uint64_t TotalCount, MaxCount, MaxFunctionCount; uint32_t NumCounts, NumFunctions; - ProfileSummary(Kind K, std::vector Cutoffs) - : PSK(K), DetailedSummaryCutoffs(Cutoffs), TotalCount(0), MaxCount(0), - MaxFunctionCount(0), NumCounts(0), NumFunctions(0) {} - ProfileSummary(Kind K) - : PSK(K), TotalCount(0), MaxCount(0), MaxFunctionCount(0), NumCounts(0), - NumFunctions(0) {} - ProfileSummary(Kind K, SummaryEntryVector DetailedSummary, - uint64_t TotalCount, uint64_t MaxCount, - uint64_t MaxFunctionCount, uint32_t NumCounts, - uint32_t NumFunctions) - : PSK(K), DetailedSummary(DetailedSummary), TotalCount(TotalCount), - MaxCount(MaxCount), MaxFunctionCount(MaxFunctionCount), - NumCounts(NumCounts), NumFunctions(NumFunctions) {} - ~ProfileSummary() = default; - inline void addCount(uint64_t Count); - /// \brief Return metadata specific to the profile format. - /// Derived classes implement this method to return a vector of Metadata. - virtual std::vector getFormatSpecificMD(LLVMContext &Context) = 0; - /// \brief Return detailed summary as metadata. - Metadata *getDetailedSummaryMD(LLVMContext &Context); public: - static const int Scale = 1000000; - Kind getKind() const { return PSK; } - const char *getKindStr() const { return KindStr[PSK]; } - // \brief Returns true if F is a hot function. - static bool isFunctionHot(const Function *F); - // \brief Returns true if F is unlikley executed. - static bool isFunctionUnlikely(const Function *F); - inline SummaryEntryVector &getDetailedSummary(); - void computeDetailedSummary(); /// \brief A vector of useful cutoff values for detailed summary. static const std::vector DefaultCutoffs; - /// \brief Return summary information as metadata. - Metadata *getMD(LLVMContext &Context); - /// \brief Construct profile summary from metdata. - static ProfileSummary *getFromMD(Metadata *MD); - uint32_t getNumFunctions() { return NumFunctions; } - uint64_t getMaxFunctionCount() { return MaxFunctionCount; } }; -class InstrProfSummary final : public ProfileSummary { +class InstrProfSummaryBuilder final : public ProfileSummaryBuilder { uint64_t MaxInternalBlockCount; inline void addEntryCount(uint64_t Count); inline void addInternalCount(uint64_t Count); -protected: - std::vector getFormatSpecificMD(LLVMContext &Context) override; - public: - InstrProfSummary(std::vector Cutoffs) - : ProfileSummary(PSK_Instr, Cutoffs), MaxInternalBlockCount(0) {} - InstrProfSummary(const IndexedInstrProf::Summary &S); - InstrProfSummary(uint64_t TotalCount, uint64_t MaxBlockCount, - uint64_t MaxInternalBlockCount, uint64_t MaxFunctionCount, - uint32_t NumBlocks, uint32_t NumFunctions, - SummaryEntryVector Summary) - : ProfileSummary(PSK_Instr, Summary, TotalCount, MaxBlockCount, - MaxFunctionCount, NumBlocks, NumFunctions), - MaxInternalBlockCount(MaxInternalBlockCount) {} - static bool classof(const ProfileSummary *PS) { - return PS->getKind() == PSK_Instr; - } + InstrProfSummaryBuilder(std::vector Cutoffs) + : ProfileSummaryBuilder(Cutoffs), MaxInternalBlockCount(0) {} void addRecord(const InstrProfRecord &); - uint32_t getNumBlocks() { return NumCounts; } - uint64_t getTotalCount() { return TotalCount; } - uint64_t getMaxBlockCount() { return MaxCount; } - uint64_t getMaxInternalBlockCount() { return MaxInternalBlockCount; } + InstrProfSummary *getSummary(); }; -class SampleProfileSummary final : public ProfileSummary { -protected: - std::vector getFormatSpecificMD(LLVMContext &Context) override; +class SampleProfileSummaryBuilder final : public ProfileSummaryBuilder { public: - uint32_t getNumLinesWithSamples() { return NumCounts; } - uint64_t getTotalSamples() { return TotalCount; } - uint64_t getMaxSamplesPerLine() { return MaxCount; } void addRecord(const sampleprof::FunctionSamples &FS); - SampleProfileSummary(std::vector Cutoffs) - : ProfileSummary(PSK_Sample, Cutoffs) {} - SampleProfileSummary(uint64_t TotalSamples, uint64_t MaxSamplesPerLine, - uint64_t MaxFunctionCount, int32_t NumLinesWithSamples, - uint32_t NumFunctions, - SummaryEntryVector DetailedSummary) - : ProfileSummary(PSK_Sample, DetailedSummary, TotalSamples, - MaxSamplesPerLine, MaxFunctionCount, NumLinesWithSamples, - NumFunctions) {} - static bool classof(const ProfileSummary *PS) { - return PS->getKind() == PSK_Sample; - } + SampleProfileSummaryBuilder(std::vector Cutoffs) + : ProfileSummaryBuilder(Cutoffs) {} + SampleProfileSummary *getSummary(); }; // This is called when a count is seen in the profile. -void ProfileSummary::addCount(uint64_t Count) { +void ProfileSummaryBuilder::addCount(uint64_t Count) { TotalCount += Count; if (Count > MaxCount) MaxCount = Count; @@ -175,11 +95,6 @@ void ProfileSummary::addCount(uint64_t Count) { CountFrequencies[Count]++; } -SummaryEntryVector &ProfileSummary::getDetailedSummary() { - if (!DetailedSummaryCutoffs.empty() && DetailedSummary.empty()) - computeDetailedSummary(); - return DetailedSummary; -} } // end namespace llvm #endif diff --git a/lib/IR/CMakeLists.txt b/lib/IR/CMakeLists.txt index f3f87338ca4..07cec97084e 100644 --- a/lib/IR/CMakeLists.txt +++ b/lib/IR/CMakeLists.txt @@ -43,6 +43,7 @@ add_llvm_library(LLVMCore Pass.cpp PassManager.cpp PassRegistry.cpp + ProfileSummary.cpp Statepoint.cpp Type.cpp TypeFinder.cpp diff --git a/lib/ProfileData/ProfileSummary.cpp b/lib/IR/ProfileSummary.cpp similarity index 71% rename from lib/ProfileData/ProfileSummary.cpp rename to lib/IR/ProfileSummary.cpp index dfe44e32bbe..51bcd1845c7 100644 --- a/lib/ProfileData/ProfileSummary.cpp +++ b/lib/IR/ProfileSummary.cpp @@ -1,4 +1,4 @@ -//=-- Profilesummary.cpp - Profile summary computation ----------------------=// +//=-- Profilesummary.cpp - Profile summary support --------------------------=// // // The LLVM Compiler Infrastructure // @@ -7,134 +7,23 @@ // //===----------------------------------------------------------------------===// // -// This file contains support for computing profile summary data. +// This file contains support for converting profile summary data from/to +// metadata. // //===----------------------------------------------------------------------===// +#include "llvm/IR/ProfileSummary.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Type.h" -#include "llvm/ProfileData/InstrProf.h" -#include "llvm/ProfileData/ProfileCommon.h" -#include "llvm/ProfileData/SampleProf.h" #include "llvm/Support/Casting.h" using namespace llvm; -// A set of cutoff values. Each value, when divided by ProfileSummary::Scale -// (which is 1000000) is a desired percentile of total counts. -const std::vector ProfileSummary::DefaultCutoffs( - {10000, /* 1% */ - 100000, /* 10% */ - 200000, 300000, 400000, 500000, 600000, 500000, 600000, 700000, 800000, - 900000, 950000, 990000, 999000, 999900, 999990, 999999}); const char *ProfileSummary::KindStr[2] = {"InstrProf", "SampleProfile"}; -void InstrProfSummary::addRecord(const InstrProfRecord &R) { - // The first counter is not necessarily an entry count for IR - // instrumentation profiles. - // Eventually MaxFunctionCount will become obsolete and this can be - // removed. - addEntryCount(R.Counts[0]); - for (size_t I = 1, E = R.Counts.size(); I < E; ++I) - addInternalCount(R.Counts[I]); -} - -// To compute the detailed summary, we consider each line containing samples as -// equivalent to a block with a count in the instrumented profile. -void SampleProfileSummary::addRecord(const sampleprof::FunctionSamples &FS) { - NumFunctions++; - if (FS.getHeadSamples() > MaxFunctionCount) - MaxFunctionCount = FS.getHeadSamples(); - for (const auto &I : FS.getBodySamples()) - addCount(I.second.getSamples()); -} - -// The argument to this method is a vector of cutoff percentages and the return -// value is a vector of (Cutoff, MinCount, NumCounts) triplets. -void ProfileSummary::computeDetailedSummary() { - if (DetailedSummaryCutoffs.empty()) - return; - auto Iter = CountFrequencies.begin(); - auto End = CountFrequencies.end(); - std::sort(DetailedSummaryCutoffs.begin(), DetailedSummaryCutoffs.end()); - - uint32_t CountsSeen = 0; - uint64_t CurrSum = 0, Count = 0; - - for (uint32_t Cutoff : DetailedSummaryCutoffs) { - assert(Cutoff <= 999999); - APInt Temp(128, TotalCount); - APInt N(128, Cutoff); - APInt D(128, ProfileSummary::Scale); - Temp *= N; - Temp = Temp.sdiv(D); - uint64_t DesiredCount = Temp.getZExtValue(); - assert(DesiredCount <= TotalCount); - while (CurrSum < DesiredCount && Iter != End) { - Count = Iter->first; - uint32_t Freq = Iter->second; - CurrSum += (Count * Freq); - CountsSeen += Freq; - Iter++; - } - assert(CurrSum >= DesiredCount); - ProfileSummaryEntry PSE = {Cutoff, Count, CountsSeen}; - DetailedSummary.push_back(PSE); - } -} - -// Returns true if the function is a hot function. -bool ProfileSummary::isFunctionHot(const Function *F) { - // FIXME: update when summary data is stored in module's metadata. - return false; -} - -// Returns true if the function is a cold function. -bool ProfileSummary::isFunctionUnlikely(const Function *F) { - if (F->hasFnAttribute(Attribute::Cold)) { - return true; - } - if (!F->getEntryCount()) { - return false; - } - // FIXME: update when summary data is stored in module's metadata. - return (*F->getEntryCount()) == 0; -} - -InstrProfSummary::InstrProfSummary(const IndexedInstrProf::Summary &S) - : ProfileSummary(PSK_Instr), - MaxInternalBlockCount( - S.get(IndexedInstrProf::Summary::MaxInternalBlockCount)) { - - TotalCount = S.get(IndexedInstrProf::Summary::TotalBlockCount); - MaxCount = S.get(IndexedInstrProf::Summary::MaxBlockCount); - MaxFunctionCount = S.get(IndexedInstrProf::Summary::MaxFunctionCount); - NumCounts = S.get(IndexedInstrProf::Summary::TotalNumBlocks); - NumFunctions = S.get(IndexedInstrProf::Summary::TotalNumFunctions); - - for (unsigned I = 0; I < S.NumCutoffEntries; I++) { - const IndexedInstrProf::Summary::Entry &Ent = S.getEntry(I); - DetailedSummary.emplace_back((uint32_t)Ent.Cutoff, Ent.MinBlockCount, - Ent.NumBlocks); - } -} - -void InstrProfSummary::addEntryCount(uint64_t Count) { - addCount(Count); - NumFunctions++; - if (Count > MaxFunctionCount) - MaxFunctionCount = Count; -} - -void InstrProfSummary::addInternalCount(uint64_t Count) { - addCount(Count); - if (Count > MaxInternalBlockCount) - MaxInternalBlockCount = Count; -} - // Return an MDTuple with two elements. The first element is a string Key and // the second is a uint64_t Value. static Metadata *getKeyValMD(LLVMContext &Context, const char *Key, diff --git a/lib/ProfileData/CMakeLists.txt b/lib/ProfileData/CMakeLists.txt index e68717c8188..cd65762ae6a 100644 --- a/lib/ProfileData/CMakeLists.txt +++ b/lib/ProfileData/CMakeLists.txt @@ -2,7 +2,7 @@ add_llvm_library(LLVMProfileData InstrProf.cpp InstrProfReader.cpp InstrProfWriter.cpp - ProfileSummary.cpp + ProfileSummaryBuilder.cpp SampleProf.cpp SampleProfReader.cpp SampleProfWriter.cpp diff --git a/lib/ProfileData/InstrProfReader.cpp b/lib/ProfileData/InstrProfReader.cpp index 2678ac28561..33535fd8eb6 100644 --- a/lib/ProfileData/InstrProfReader.cpp +++ b/lib/ProfileData/InstrProfReader.cpp @@ -576,6 +576,7 @@ bool IndexedInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) { const unsigned char * IndexedInstrProfReader::readSummary(IndexedInstrProf::ProfVersion Version, const unsigned char *Cur) { + using namespace IndexedInstrProf; using namespace support; if (Version >= IndexedInstrProf::Version4) { const IndexedInstrProf::Summary *SummaryInLE = @@ -594,15 +595,28 @@ IndexedInstrProfReader::readSummary(IndexedInstrProf::ProfVersion Version, for (unsigned I = 0; I < SummarySize / sizeof(uint64_t); I++) Dst[I] = endian::byte_swap(Src[I]); + llvm::SummaryEntryVector DetailedSummary; + for (unsigned I = 0; I < SummaryData->NumCutoffEntries; I++) { + const IndexedInstrProf::Summary::Entry &Ent = SummaryData->getEntry(I); + DetailedSummary.emplace_back((uint32_t)Ent.Cutoff, Ent.MinBlockCount, + Ent.NumBlocks); + } // initialize InstrProfSummary using the SummaryData from disk. - this->Summary = llvm::make_unique(*(SummaryData.get())); + this->Summary = llvm::make_unique( + SummaryData->get(Summary::TotalBlockCount), + SummaryData->get(Summary::MaxBlockCount), + SummaryData->get(Summary::MaxInternalBlockCount), + SummaryData->get(Summary::MaxFunctionCount), + SummaryData->get(Summary::TotalNumBlocks), + SummaryData->get(Summary::TotalNumFunctions), DetailedSummary); return Cur + SummarySize; } else { // For older version of profile data, we need to compute on the fly: using namespace IndexedInstrProf; - this->Summary = - llvm::make_unique(ProfileSummary::DefaultCutoffs); - this->Summary->computeDetailedSummary(); + InstrProfSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs); + // FIXME: This only computes an empty summary. Need to call addRecord for + // all InstrProfRecords to get the correct summary. + this->Summary.reset(Builder.getSummary()); return Cur; } } diff --git a/lib/ProfileData/InstrProfWriter.cpp b/lib/ProfileData/InstrProfWriter.cpp index 9b01dac313b..1036a10ed8a 100644 --- a/lib/ProfileData/InstrProfWriter.cpp +++ b/lib/ProfileData/InstrProfWriter.cpp @@ -84,7 +84,7 @@ public: typedef uint64_t offset_type; support::endianness ValueProfDataEndianness; - InstrProfSummary *TheProfileSummary; + InstrProfSummaryBuilder *SummaryBuilder; InstrProfRecordWriterTrait() : ValueProfDataEndianness(support::little) {} static hash_value_type ComputeHash(key_type_ref K) { @@ -123,7 +123,7 @@ public: endian::Writer LE(Out); for (const auto &ProfileData : *V) { const InstrProfRecord &ProfRecord = ProfileData.second; - TheProfileSummary->addRecord(ProfRecord); + SummaryBuilder->addRecord(ProfRecord); LE.write(ProfileData.first); // Function hash LE.write(ProfRecord.Counts.size()); @@ -215,8 +215,8 @@ void InstrProfWriter::writeImpl(ProfOStream &OS) { OnDiskChainedHashTableGenerator Generator; using namespace IndexedInstrProf; - InstrProfSummary PS(ProfileSummary::DefaultCutoffs); - InfoObj->TheProfileSummary = &PS; + InstrProfSummaryBuilder ISB(ProfileSummaryBuilder::DefaultCutoffs); + InfoObj->SummaryBuilder = &ISB; // Populate the hash table generator. for (const auto &I : FunctionData) @@ -245,7 +245,7 @@ void InstrProfWriter::writeImpl(ProfOStream &OS) { OS.write(0); // Reserve space to write profile summary data. - uint32_t NumEntries = ProfileSummary::DefaultCutoffs.size(); + uint32_t NumEntries = ProfileSummaryBuilder::DefaultCutoffs.size(); uint32_t SummarySize = Summary::getSize(Summary::NumKinds, NumEntries); // Remember the summary offset. uint64_t SummaryOffset = OS.tell(); @@ -260,8 +260,9 @@ void InstrProfWriter::writeImpl(ProfOStream &OS) { IndexedInstrProf::allocSummary(SummarySize); // Compute the Summary and copy the data to the data // structure to be serialized out (to disk or buffer). - setSummary(TheSummary.get(), PS); - InfoObj->TheProfileSummary = 0; + InstrProfSummary *IPS = ISB.getSummary(); + setSummary(TheSummary.get(), *IPS); + InfoObj->SummaryBuilder = 0; // Now do the final patch: PatchItem PatchItems[] = { diff --git a/lib/ProfileData/ProfileSummaryBuilder.cpp b/lib/ProfileData/ProfileSummaryBuilder.cpp new file mode 100644 index 00000000000..3d32722ab63 --- /dev/null +++ b/lib/ProfileData/ProfileSummaryBuilder.cpp @@ -0,0 +1,113 @@ +//=-- ProfilesummaryBuilder.cpp - Profile summary computation ---------------=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains support for computing profile summary data. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/Attributes.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Metadata.h" +#include "llvm/IR/Type.h" +#include "llvm/ProfileData/InstrProf.h" +#include "llvm/ProfileData/ProfileCommon.h" +#include "llvm/ProfileData/SampleProf.h" +#include "llvm/Support/Casting.h" + +using namespace llvm; + +// A set of cutoff values. Each value, when divided by ProfileSummary::Scale +// (which is 1000000) is a desired percentile of total counts. +const std::vector ProfileSummaryBuilder::DefaultCutoffs( + {10000, /* 1% */ + 100000, /* 10% */ + 200000, 300000, 400000, 500000, 600000, 500000, 600000, 700000, 800000, + 900000, 950000, 990000, 999000, 999900, 999990, 999999}); + +void InstrProfSummaryBuilder::addRecord(const InstrProfRecord &R) { + // The first counter is not necessarily an entry count for IR + // instrumentation profiles. + // Eventually MaxFunctionCount will become obsolete and this can be + // removed. + addEntryCount(R.Counts[0]); + for (size_t I = 1, E = R.Counts.size(); I < E; ++I) + addInternalCount(R.Counts[I]); +} + +// To compute the detailed summary, we consider each line containing samples as +// equivalent to a block with a count in the instrumented profile. +void SampleProfileSummaryBuilder::addRecord( + const sampleprof::FunctionSamples &FS) { + NumFunctions++; + if (FS.getHeadSamples() > MaxFunctionCount) + MaxFunctionCount = FS.getHeadSamples(); + for (const auto &I : FS.getBodySamples()) + addCount(I.second.getSamples()); +} + +// The argument to this method is a vector of cutoff percentages and the return +// value is a vector of (Cutoff, MinCount, NumCounts) triplets. +void ProfileSummaryBuilder::computeDetailedSummary() { + if (DetailedSummaryCutoffs.empty()) + return; + auto Iter = CountFrequencies.begin(); + auto End = CountFrequencies.end(); + std::sort(DetailedSummaryCutoffs.begin(), DetailedSummaryCutoffs.end()); + + uint32_t CountsSeen = 0; + uint64_t CurrSum = 0, Count = 0; + + for (uint32_t Cutoff : DetailedSummaryCutoffs) { + assert(Cutoff <= 999999); + APInt Temp(128, TotalCount); + APInt N(128, Cutoff); + APInt D(128, ProfileSummary::Scale); + Temp *= N; + Temp = Temp.sdiv(D); + uint64_t DesiredCount = Temp.getZExtValue(); + assert(DesiredCount <= TotalCount); + while (CurrSum < DesiredCount && Iter != End) { + Count = Iter->first; + uint32_t Freq = Iter->second; + CurrSum += (Count * Freq); + CountsSeen += Freq; + Iter++; + } + assert(CurrSum >= DesiredCount); + ProfileSummaryEntry PSE = {Cutoff, Count, CountsSeen}; + DetailedSummary.push_back(PSE); + } +} + +SampleProfileSummary *SampleProfileSummaryBuilder::getSummary() { + computeDetailedSummary(); + return new SampleProfileSummary(TotalCount, MaxCount, MaxFunctionCount, + NumCounts, NumFunctions, DetailedSummary); +} + +InstrProfSummary *InstrProfSummaryBuilder::getSummary() { + computeDetailedSummary(); + return new InstrProfSummary(TotalCount, MaxCount, MaxInternalBlockCount, + MaxFunctionCount, NumCounts, NumFunctions, + DetailedSummary); +} + +void InstrProfSummaryBuilder::addEntryCount(uint64_t Count) { + addCount(Count); + NumFunctions++; + if (Count > MaxFunctionCount) + MaxFunctionCount = Count; +} + +void InstrProfSummaryBuilder::addInternalCount(uint64_t Count) { + addCount(Count); + if (Count > MaxInternalBlockCount) + MaxInternalBlockCount = Count; +} diff --git a/lib/ProfileData/SampleProfReader.cpp b/lib/ProfileData/SampleProfReader.cpp index 63f828697d6..14023bbd509 100644 --- a/lib/ProfileData/SampleProfReader.cpp +++ b/lib/ProfileData/SampleProfReader.cpp @@ -793,10 +793,10 @@ SampleProfileReader::create(std::unique_ptr &B, LLVMContext &C) { // For text and GCC file formats, we compute the summary after reading the // profile. Binary format has the profile summary in its header. void SampleProfileReader::computeSummary() { - Summary.reset(new SampleProfileSummary(ProfileSummary::DefaultCutoffs)); + SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs); for (const auto &I : Profiles) { const FunctionSamples &Profile = I.second; - Summary->addRecord(Profile); + Builder.addRecord(Profile); } - Summary->computeDetailedSummary(); + Summary.reset(Builder.getSummary()); } diff --git a/lib/ProfileData/SampleProfWriter.cpp b/lib/ProfileData/SampleProfWriter.cpp index 2f6490224c5..56e836c69cd 100644 --- a/lib/ProfileData/SampleProfWriter.cpp +++ b/lib/ProfileData/SampleProfWriter.cpp @@ -255,10 +255,10 @@ SampleProfileWriter::create(std::unique_ptr &OS, void SampleProfileWriter::computeSummary( const StringMap &ProfileMap) { - Summary.reset(new SampleProfileSummary(ProfileSummary::DefaultCutoffs)); + SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs); for (const auto &I : ProfileMap) { const FunctionSamples &Profile = I.second; - Summary->addRecord(Profile); + Builder.addRecord(Profile); } - Summary->computeDetailedSummary(); + Summary.reset(Builder.getSummary()); } diff --git a/tools/llvm-profdata/llvm-profdata.cpp b/tools/llvm-profdata/llvm-profdata.cpp index d45e6afa5a5..1b042be8a3f 100644 --- a/tools/llvm-profdata/llvm-profdata.cpp +++ b/tools/llvm-profdata/llvm-profdata.cpp @@ -281,7 +281,7 @@ static int showInstrProfile(std::string Filename, bool ShowCounts, if (ShowDetailedSummary && DetailedSummaryCutoffs.empty()) { Cutoffs = {800000, 900000, 950000, 990000, 999000, 999900, 999990}; } - InstrProfSummary PS(Cutoffs); + InstrProfSummaryBuilder Builder(Cutoffs); if (Error E = ReaderOrErr.takeError()) exitWithError(std::move(E), Filename); @@ -302,7 +302,7 @@ static int showInstrProfile(std::string Filename, bool ShowCounts, } assert(Func.Counts.size() > 0 && "function missing entry counter"); - PS.addRecord(Func); + Builder.addRecord(Func); if (Show) { @@ -353,18 +353,19 @@ static int showInstrProfile(std::string Filename, bool ShowCounts, if (ShowCounts && TextFormat) return 0; - + std::unique_ptr PS(Builder.getSummary()); if (ShowAllFunctions || !ShowFunction.empty()) OS << "Functions shown: " << ShownFunctions << "\n"; - OS << "Total functions: " << PS.getNumFunctions() << "\n"; - OS << "Maximum function count: " << PS.getMaxFunctionCount() << "\n"; - OS << "Maximum internal block count: " << PS.getMaxInternalBlockCount() << "\n"; + OS << "Total functions: " << PS->getNumFunctions() << "\n"; + OS << "Maximum function count: " << PS->getMaxFunctionCount() << "\n"; + OS << "Maximum internal block count: " << PS->getMaxInternalBlockCount() + << "\n"; if (ShowDetailedSummary) { OS << "Detailed summary:\n"; - OS << "Total number of blocks: " << PS.getNumBlocks() << "\n"; - OS << "Total count: " << PS.getTotalCount() << "\n"; - for (auto Entry : PS.getDetailedSummary()) { + OS << "Total number of blocks: " << PS->getNumBlocks() << "\n"; + OS << "Total count: " << PS->getTotalCount() << "\n"; + for (auto Entry : PS->getDetailedSummary()) { OS << Entry.NumCounts << " blocks with count >= " << Entry.MinCount << " account for " << format("%0.6g", (float)Entry.Cutoff / ProfileSummary::Scale * 100)