diff options
Diffstat (limited to 'contrib/llvm/lib/ProfileData')
-rw-r--r-- | contrib/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp | 113 | ||||
-rw-r--r-- | contrib/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp | 86 | ||||
-rw-r--r-- | contrib/llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp | 35 | ||||
-rw-r--r-- | contrib/llvm/lib/ProfileData/InstrProf.cpp | 250 | ||||
-rw-r--r-- | contrib/llvm/lib/ProfileData/InstrProfReader.cpp | 83 | ||||
-rw-r--r-- | contrib/llvm/lib/ProfileData/InstrProfWriter.cpp | 102 | ||||
-rw-r--r-- | contrib/llvm/lib/ProfileData/SampleProf.cpp | 34 | ||||
-rw-r--r-- | contrib/llvm/lib/ProfileData/SampleProfReader.cpp | 31 | ||||
-rw-r--r-- | contrib/llvm/lib/ProfileData/SampleProfWriter.cpp | 112 |
9 files changed, 580 insertions, 266 deletions
diff --git a/contrib/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/contrib/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp index 6d907c7..8c5f136 100644 --- a/contrib/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp +++ b/contrib/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp @@ -1,4 +1,4 @@ -//=-- CoverageMapping.cpp - Code coverage mapping support ---------*- C++ -*-=// +//===- CoverageMapping.cpp - Code coverage mapping support ----------------===// // // The LLVM Compiler Infrastructure // @@ -13,17 +13,31 @@ //===----------------------------------------------------------------------===// #include "llvm/ProfileData/Coverage/CoverageMapping.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallBitVector.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ProfileData/Coverage/CoverageMappingReader.h" #include "llvm/ProfileData/InstrProfReader.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Errc.h" +#include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/Path.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <iterator> +#include <memory> +#include <string> +#include <system_error> +#include <utility> +#include <vector> using namespace llvm; using namespace coverage; @@ -40,26 +54,26 @@ Counter CounterExpressionBuilder::get(const CounterExpression &E) { return Counter::getExpression(I); } -void CounterExpressionBuilder::extractTerms( - Counter C, int Sign, SmallVectorImpl<std::pair<unsigned, int>> &Terms) { +void CounterExpressionBuilder::extractTerms(Counter C, int Factor, + SmallVectorImpl<Term> &Terms) { switch (C.getKind()) { case Counter::Zero: break; case Counter::CounterValueReference: - Terms.push_back(std::make_pair(C.getCounterID(), Sign)); + Terms.emplace_back(C.getCounterID(), Factor); break; case Counter::Expression: const auto &E = Expressions[C.getExpressionID()]; - extractTerms(E.LHS, Sign, Terms); - extractTerms(E.RHS, E.Kind == CounterExpression::Subtract ? -Sign : Sign, - Terms); + extractTerms(E.LHS, Factor, Terms); + extractTerms( + E.RHS, E.Kind == CounterExpression::Subtract ? -Factor : Factor, Terms); break; } } Counter CounterExpressionBuilder::simplify(Counter ExpressionTree) { // Gather constant terms. - llvm::SmallVector<std::pair<unsigned, int>, 32> Terms; + SmallVector<Term, 32> Terms; extractTerms(ExpressionTree, +1, Terms); // If there are no terms, this is just a zero. The algorithm below assumes at @@ -68,17 +82,15 @@ Counter CounterExpressionBuilder::simplify(Counter ExpressionTree) { return Counter::getZero(); // Group the terms by counter ID. - std::sort(Terms.begin(), Terms.end(), - [](const std::pair<unsigned, int> &LHS, - const std::pair<unsigned, int> &RHS) { - return LHS.first < RHS.first; + std::sort(Terms.begin(), Terms.end(), [](const Term &LHS, const Term &RHS) { + return LHS.CounterID < RHS.CounterID; }); // Combine terms by counter ID to eliminate counters that sum to zero. auto Prev = Terms.begin(); for (auto I = Prev + 1, E = Terms.end(); I != E; ++I) { - if (I->first == Prev->first) { - Prev->second += I->second; + if (I->CounterID == Prev->CounterID) { + Prev->Factor += I->Factor; continue; } ++Prev; @@ -89,24 +101,24 @@ Counter CounterExpressionBuilder::simplify(Counter ExpressionTree) { Counter C; // Create additions. We do this before subtractions to avoid constructs like // ((0 - X) + Y), as opposed to (Y - X). - for (auto Term : Terms) { - if (Term.second <= 0) + for (auto T : Terms) { + if (T.Factor <= 0) continue; - for (int I = 0; I < Term.second; ++I) + for (int I = 0; I < T.Factor; ++I) if (C.isZero()) - C = Counter::getCounter(Term.first); + C = Counter::getCounter(T.CounterID); else C = get(CounterExpression(CounterExpression::Add, C, - Counter::getCounter(Term.first))); + Counter::getCounter(T.CounterID))); } // Create subtractions. - for (auto Term : Terms) { - if (Term.second >= 0) + for (auto T : Terms) { + if (T.Factor >= 0) continue; - for (int I = 0; I < -Term.second; ++I) + for (int I = 0; I < -T.Factor; ++I) C = get(CounterExpression(CounterExpression::Subtract, C, - Counter::getCounter(Term.first))); + Counter::getCounter(T.CounterID))); } return C; } @@ -120,8 +132,7 @@ Counter CounterExpressionBuilder::subtract(Counter LHS, Counter RHS) { get(CounterExpression(CounterExpression::Subtract, LHS, RHS))); } -void CounterMappingContext::dump(const Counter &C, - llvm::raw_ostream &OS) const { +void CounterMappingContext::dump(const Counter &C, raw_ostream &OS) const { switch (C.getKind()) { case Counter::Zero: OS << '0'; @@ -145,7 +156,7 @@ void CounterMappingContext::dump(const Counter &C, return; Expected<int64_t> Value = evaluate(C); if (auto E = Value.takeError()) { - llvm::consumeError(std::move(E)); + consumeError(std::move(E)); return; } OS << '[' << *Value << ']'; @@ -187,6 +198,9 @@ Error CoverageMapping::loadFunctionRecord( const CoverageMappingRecord &Record, IndexedInstrProfReader &ProfileReader) { StringRef OrigFuncName = Record.FunctionName; + if (OrigFuncName.empty()) + return make_error<CoverageMapError>(coveragemap_error::malformed); + if (Record.Filenames.empty()) OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName); else @@ -217,7 +231,7 @@ Error CoverageMapping::loadFunctionRecord( for (const auto &Region : Record.MappingRegions) { Expected<int64_t> ExecutionCount = Ctx.evaluate(Region.Count); if (auto E = ExecutionCount.takeError()) { - llvm::consumeError(std::move(E)); + consumeError(std::move(E)); return Error::success(); } Function.pushRegion(Region, *ExecutionCount); @@ -231,18 +245,6 @@ Error CoverageMapping::loadFunctionRecord( return Error::success(); } -Expected<std::unique_ptr<CoverageMapping>> -CoverageMapping::load(CoverageMappingReader &CoverageReader, - IndexedInstrProfReader &ProfileReader) { - auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping()); - - for (const auto &Record : CoverageReader) - if (Error E = Coverage->loadFunctionRecord(Record, ProfileReader)) - return std::move(E); - - return std::move(Coverage); -} - Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load( ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders, IndexedInstrProfReader &ProfileReader) { @@ -281,13 +283,14 @@ CoverageMapping::load(ArrayRef<StringRef> ObjectFilenames, } namespace { + /// \brief Distributes functions into instantiation sets. /// /// An instantiation set is a collection of functions that have the same source /// code, ie, template functions specializations. class FunctionInstantiationSetCollector { - typedef DenseMap<std::pair<unsigned, unsigned>, - std::vector<const FunctionRecord *>> MapT; + using MapT = DenseMap<std::pair<unsigned, unsigned>, + std::vector<const FunctionRecord *>>; MapT InstantiatedFunctions; public: @@ -301,7 +304,6 @@ public: } MapT::iterator begin() { return InstantiatedFunctions.begin(); } - MapT::iterator end() { return InstantiatedFunctions.end(); } }; @@ -326,7 +328,7 @@ class SegmentBuilder { Segments.pop_back(); DEBUG(dbgs() << "Segment at " << Line << ":" << Col); // Set this region's count. - if (Region.Kind != coverage::CounterMappingRegion::SkippedRegion) { + if (Region.Kind != CounterMappingRegion::SkippedRegion) { DEBUG(dbgs() << " with count " << Region.ExecutionCount); Segments.emplace_back(Line, Col, Region.ExecutionCount, IsRegionEntry); } else @@ -380,10 +382,10 @@ class SegmentBuilder { // in combineRegions(). Because we accumulate counter values only from // regions of the same kind as the first region of the area, prefer // CodeRegion to ExpansionRegion and ExpansionRegion to SkippedRegion. - static_assert(coverage::CounterMappingRegion::CodeRegion < - coverage::CounterMappingRegion::ExpansionRegion && - coverage::CounterMappingRegion::ExpansionRegion < - coverage::CounterMappingRegion::SkippedRegion, + static_assert(CounterMappingRegion::CodeRegion < + CounterMappingRegion::ExpansionRegion && + CounterMappingRegion::ExpansionRegion < + CounterMappingRegion::SkippedRegion, "Unexpected order of region kind values"); return LHS.Kind < RHS.Kind; }); @@ -437,7 +439,8 @@ public: return Segments; } }; -} + +} // end anonymous namespace std::vector<StringRef> CoverageMapping::getUniqueSourceFiles() const { std::vector<StringRef> Filenames; @@ -487,7 +490,7 @@ static bool isExpansion(const CountedRegion &R, unsigned FileID) { CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const { CoverageData FileCoverage(Filename); - std::vector<coverage::CountedRegion> Regions; + std::vector<CountedRegion> Regions; for (const auto &Function : Functions) { auto MainFileID = findMainViewFileID(Filename, Function); @@ -533,7 +536,7 @@ CoverageMapping::getCoverageForFunction(const FunctionRecord &Function) const { return CoverageData(); CoverageData FunctionCoverage(Function.Filenames[*MainFileID]); - std::vector<coverage::CountedRegion> Regions; + std::vector<CountedRegion> Regions; for (const auto &CR : Function.CountedRegions) if (CR.FileID == *MainFileID) { Regions.push_back(CR); @@ -551,7 +554,7 @@ CoverageData CoverageMapping::getCoverageForExpansion( const ExpansionRecord &Expansion) const { CoverageData ExpansionCoverage( Expansion.Function.Filenames[Expansion.FileID]); - std::vector<coverage::CountedRegion> Regions; + std::vector<CountedRegion> Regions; for (const auto &CR : Expansion.Function.CountedRegions) if (CR.FileID == Expansion.FileID) { Regions.push_back(CR); @@ -566,8 +569,7 @@ CoverageData CoverageMapping::getCoverageForExpansion( return ExpansionCoverage; } -namespace { -std::string getCoverageMapErrString(coveragemap_error Err) { +static std::string getCoverageMapErrString(coveragemap_error Err) { switch (Err) { case coveragemap_error::success: return "Success"; @@ -585,6 +587,8 @@ std::string getCoverageMapErrString(coveragemap_error Err) { llvm_unreachable("A value of coveragemap_error has no message."); } +namespace { + // FIXME: This class is only here to support the transition to llvm::Error. It // will be removed once this transition is complete. Clients should prefer to // deal with the Error value directly, rather than converting to error_code. @@ -594,6 +598,7 @@ class CoverageMappingErrorCategoryType : public std::error_category { return getCoverageMapErrString(static_cast<coveragemap_error>(IE)); } }; + } // end anonymous namespace std::string CoverageMapError::message() const { diff --git a/contrib/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/contrib/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp index a6c7031..fff0a03 100644 --- a/contrib/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp +++ b/contrib/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp @@ -1,4 +1,4 @@ -//=-- CoverageMappingReader.cpp - Code coverage mapping reader ----*- C++ -*-=// +//===- CoverageMappingReader.cpp - Code coverage mapping reader -----------===// // // The LLVM Compiler Infrastructure // @@ -13,14 +13,34 @@ //===----------------------------------------------------------------------===// #include "llvm/ProfileData/Coverage/CoverageMappingReader.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Object/Binary.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/Error.h" #include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/ProfileData/InstrProf.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <limits> +#include <memory> +#include <utility> +#include <vector> using namespace llvm; using namespace coverage; @@ -42,7 +62,7 @@ void CoverageMappingIterator::increment() { } Error RawCoverageReader::readULEB128(uint64_t &Result) { - if (Data.size() < 1) + if (Data.empty()) return make_error<CoverageMapError>(coveragemap_error::truncated); unsigned N = 0; Result = decodeULEB128(reinterpret_cast<const uint8_t *>(Data.data()), &N); @@ -226,9 +246,8 @@ Error RawCoverageMappingReader::readMappingRegionsSubArray( } Error RawCoverageMappingReader::read() { - // Read the virtual file mapping. - llvm::SmallVector<unsigned, 8> VirtualFileMapping; + SmallVector<unsigned, 8> VirtualFileMapping; uint64_t NumFileMappings; if (auto Err = readSize(NumFileMappings)) return Err; @@ -349,7 +368,10 @@ static Expected<bool> isCoverageMappingDummy(uint64_t Hash, StringRef Mapping) { } namespace { + struct CovMapFuncRecordReader { + virtual ~CovMapFuncRecordReader() = default; + // The interface to read coverage mapping function records for a module. // // \p Buf points to the buffer containing the \c CovHeader of the coverage @@ -359,26 +381,24 @@ struct CovMapFuncRecordReader { // greater than \p End if not. virtual Expected<const char *> readFunctionRecords(const char *Buf, const char *End) = 0; - virtual ~CovMapFuncRecordReader() {} + template <class IntPtrT, support::endianness Endian> static Expected<std::unique_ptr<CovMapFuncRecordReader>> - get(coverage::CovMapVersion Version, InstrProfSymtab &P, + get(CovMapVersion Version, InstrProfSymtab &P, std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, std::vector<StringRef> &F); }; // A class for reading coverage mapping function records for a module. -template <coverage::CovMapVersion Version, class IntPtrT, - support::endianness Endian> +template <CovMapVersion Version, class IntPtrT, support::endianness Endian> class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader { - typedef typename coverage::CovMapTraits< - Version, IntPtrT>::CovMapFuncRecordType FuncRecordType; - typedef typename coverage::CovMapTraits<Version, IntPtrT>::NameRefType - NameRefType; + using FuncRecordType = + typename CovMapTraits<Version, IntPtrT>::CovMapFuncRecordType; + using NameRefType = typename CovMapTraits<Version, IntPtrT>::NameRefType; // Maps function's name references to the indexes of their records // in \c Records. - llvm::DenseMap<NameRefType, size_t> FunctionRecords; + DenseMap<NameRefType, size_t> FunctionRecords; InstrProfSymtab &ProfileNames; std::vector<StringRef> &Filenames; std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records; @@ -399,6 +419,8 @@ class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader { StringRef FuncName; if (Error Err = CFR->template getFuncName<Endian>(ProfileNames, FuncName)) return Err; + if (FuncName.empty()) + return make_error<InstrProfError>(instrprof_error::malformed); Records.emplace_back(Version, FuncName, FuncHash, Mapping, FilenamesBegin, Filenames.size() - FilenamesBegin); return Error::success(); @@ -432,14 +454,16 @@ public: std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, std::vector<StringRef> &F) : ProfileNames(P), Filenames(F), Records(R) {} - ~VersionedCovMapFuncRecordReader() override {} + + ~VersionedCovMapFuncRecordReader() override = default; Expected<const char *> readFunctionRecords(const char *Buf, const char *End) override { using namespace support; + if (Buf + sizeof(CovMapHeader) > End) return make_error<CoverageMapError>(coveragemap_error::malformed); - auto CovHeader = reinterpret_cast<const coverage::CovMapHeader *>(Buf); + auto CovHeader = reinterpret_cast<const CovMapHeader *>(Buf); uint32_t NRecords = CovHeader->getNRecords<Endian>(); uint32_t FilenamesSize = CovHeader->getFilenamesSize<Endian>(); uint32_t CoverageSize = CovHeader->getCoverageSize<Endian>(); @@ -490,14 +514,16 @@ public: return Buf; } }; + } // end anonymous namespace template <class IntPtrT, support::endianness Endian> Expected<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get( - coverage::CovMapVersion Version, InstrProfSymtab &P, + CovMapVersion Version, InstrProfSymtab &P, std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, std::vector<StringRef> &F) { using namespace coverage; + switch (Version) { case CovMapVersion::Version1: return llvm::make_unique<VersionedCovMapFuncRecordReader< @@ -518,11 +544,12 @@ static Error readCoverageMappingData( std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records, std::vector<StringRef> &Filenames) { using namespace coverage; + // Read the records in the coverage data section. auto CovHeader = - reinterpret_cast<const coverage::CovMapHeader *>(Data.data()); + reinterpret_cast<const CovMapHeader *>(Data.data()); CovMapVersion Version = (CovMapVersion)CovHeader->getVersion<Endian>(); - if (Version > coverage::CovMapVersion::CurrentVersion) + if (Version > CovMapVersion::CurrentVersion) return make_error<CoverageMapError>(coveragemap_error::unsupported_version); Expected<std::unique_ptr<CovMapFuncRecordReader>> ReaderExpected = CovMapFuncRecordReader::get<T, Endian>(Version, ProfileNames, Records, @@ -538,6 +565,7 @@ static Error readCoverageMappingData( } return Error::success(); } + static const char *TestingFormatMagic = "llvmcovmtestdata"; static Error loadTestingFormat(StringRef Data, InstrProfSymtab &ProfileNames, @@ -548,7 +576,7 @@ static Error loadTestingFormat(StringRef Data, InstrProfSymtab &ProfileNames, Endian = support::endianness::little; Data = Data.substr(StringRef(TestingFormatMagic).size()); - if (Data.size() < 1) + if (Data.empty()) return make_error<CoverageMapError>(coveragemap_error::truncated); unsigned N = 0; auto ProfileNamesSize = @@ -556,7 +584,7 @@ static Error loadTestingFormat(StringRef Data, InstrProfSymtab &ProfileNames, if (N > Data.size()) return make_error<CoverageMapError>(coveragemap_error::malformed); Data = Data.substr(N); - if (Data.size() < 1) + if (Data.empty()) return make_error<CoverageMapError>(coveragemap_error::truncated); N = 0; uint64_t Address = @@ -570,7 +598,7 @@ static Error loadTestingFormat(StringRef Data, InstrProfSymtab &ProfileNames, return E; CoverageMapping = Data.substr(ProfileNamesSize); // Skip the padding bytes because coverage map data has an alignment of 8. - if (CoverageMapping.size() < 1) + if (CoverageMapping.empty()) return make_error<CoverageMapError>(coveragemap_error::truncated); size_t Pad = alignmentAdjustment(CoverageMapping.data(), 8); if (CoverageMapping.size() < Pad) @@ -595,21 +623,21 @@ static Error loadBinaryFormat(MemoryBufferRef ObjectBuffer, StringRef &CoverageMapping, uint8_t &BytesInAddress, support::endianness &Endian, StringRef Arch) { - auto BinOrErr = object::createBinary(ObjectBuffer); + auto BinOrErr = createBinary(ObjectBuffer); if (!BinOrErr) return BinOrErr.takeError(); auto Bin = std::move(BinOrErr.get()); std::unique_ptr<ObjectFile> OF; - if (auto *Universal = dyn_cast<object::MachOUniversalBinary>(Bin.get())) { + if (auto *Universal = dyn_cast<MachOUniversalBinary>(Bin.get())) { // If we have a universal binary, try to look up the object for the // appropriate architecture. auto ObjectFileOrErr = Universal->getObjectForArch(Arch); if (!ObjectFileOrErr) return ObjectFileOrErr.takeError(); OF = std::move(ObjectFileOrErr.get()); - } else if (isa<object::ObjectFile>(Bin.get())) { + } else if (isa<ObjectFile>(Bin.get())) { // For any other object file, upcast and take ownership. - OF.reset(cast<object::ObjectFile>(Bin.release())); + OF.reset(cast<ObjectFile>(Bin.release())); // If we've asked for a particular arch, make sure they match. if (!Arch.empty() && OF->getArch() != Triple(Arch).getArch()) return errorCodeToError(object_error::arch_not_found); @@ -623,11 +651,15 @@ static Error loadBinaryFormat(MemoryBufferRef ObjectBuffer, : support::endianness::big; // Look for the sections that we are interested in. - auto NamesSection = lookupSection(*OF, getInstrProfNameSectionName(false)); + auto ObjFormat = OF->getTripleObjectFormat(); + auto NamesSection = + lookupSection(*OF, getInstrProfSectionName(IPSK_name, ObjFormat, + /*AddSegmentInfo=*/false)); if (auto E = NamesSection.takeError()) return E; auto CoverageSection = - lookupSection(*OF, getInstrProfCoverageSectionName(false)); + lookupSection(*OF, getInstrProfSectionName(IPSK_covmap, ObjFormat, + /*AddSegmentInfo=*/false)); if (auto E = CoverageSection.takeError()) return E; diff --git a/contrib/llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp b/contrib/llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp index 8235633..6fe9353 100644 --- a/contrib/llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp +++ b/contrib/llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp @@ -1,4 +1,4 @@ -//=-- CoverageMappingWriter.cpp - Code coverage mapping writer -------------=// +//===- CoverageMappingWriter.cpp - Code coverage mapping writer -----------===// // // The LLVM Compiler Infrastructure // @@ -13,7 +13,14 @@ //===----------------------------------------------------------------------===// #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Support/LEB128.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <limits> +#include <vector> using namespace llvm; using namespace coverage; @@ -27,14 +34,25 @@ void CoverageFilenamesSectionWriter::write(raw_ostream &OS) { } namespace { + /// \brief Gather only the expressions that are used by the mapping /// regions in this function. class CounterExpressionsMinimizer { ArrayRef<CounterExpression> Expressions; - llvm::SmallVector<CounterExpression, 16> UsedExpressions; + SmallVector<CounterExpression, 16> UsedExpressions; std::vector<unsigned> AdjustedExpressionIDs; public: + CounterExpressionsMinimizer(ArrayRef<CounterExpression> Expressions, + ArrayRef<CounterMappingRegion> MappingRegions) + : Expressions(Expressions) { + AdjustedExpressionIDs.resize(Expressions.size(), 0); + for (const auto &I : MappingRegions) + mark(I.Count); + for (const auto &I : MappingRegions) + gatherUsed(I.Count); + } + void mark(Counter C) { if (!C.isExpression()) return; @@ -54,16 +72,6 @@ public: gatherUsed(E.RHS); } - CounterExpressionsMinimizer(ArrayRef<CounterExpression> Expressions, - ArrayRef<CounterMappingRegion> MappingRegions) - : Expressions(Expressions) { - AdjustedExpressionIDs.resize(Expressions.size(), 0); - for (const auto &I : MappingRegions) - mark(I.Count); - for (const auto &I : MappingRegions) - gatherUsed(I.Count); - } - ArrayRef<CounterExpression> getExpressions() const { return UsedExpressions; } /// \brief Adjust the given counter to correctly transition from the old @@ -74,7 +82,8 @@ public: return C; } }; -} + +} // end anonymous namespace /// \brief Encode the counter. /// diff --git a/contrib/llvm/lib/ProfileData/InstrProf.cpp b/contrib/llvm/lib/ProfileData/InstrProf.cpp index 74acd9e..48c1643 100644 --- a/contrib/llvm/lib/ProfileData/InstrProf.cpp +++ b/contrib/llvm/lib/ProfileData/InstrProf.cpp @@ -1,4 +1,4 @@ -//=-- InstrProf.cpp - Instrumented profiling format support -----------------=// +//===- InstrProf.cpp - Instrumented profiling format support --------------===// // // The LLVM Compiler Infrastructure // @@ -13,28 +13,67 @@ //===----------------------------------------------------------------------===// #include "llvm/ProfileData/InstrProf.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" +#include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" +#include "llvm/IR/GlobalValue.h" #include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/IR/MDBuilder.h" +#include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/Compression.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MathExtras.h" #include "llvm/Support/Path.h" +#include "llvm/Support/SwapByteOrder.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <cstring> +#include <memory> +#include <string> +#include <system_error> +#include <utility> +#include <vector> using namespace llvm; static cl::opt<bool> StaticFuncFullModulePrefix( - "static-func-full-module-prefix", cl::init(false), + "static-func-full-module-prefix", cl::init(true), cl::desc("Use full module build paths in the profile counter names for " "static functions.")); -namespace { -std::string getInstrProfErrString(instrprof_error Err) { +// This option is tailored to users that have different top-level directory in +// profile-gen and profile-use compilation. Users need to specific the number +// of levels to strip. A value larger than the number of directories in the +// source file will strip all the directory names and only leave the basename. +// +// Note current ThinLTO module importing for the indirect-calls assumes +// the source directory name not being stripped. A non-zero option value here +// can potentially prevent some inter-module indirect-call-promotions. +static cl::opt<unsigned> StaticFuncStripDirNamePrefix( + "static-func-strip-dirname-prefix", cl::init(0), + cl::desc("Strip specified level of directory name from source path in " + "the profile counter name for static functions.")); + +static std::string getInstrProfErrString(instrprof_error Err) { switch (Err) { case instrprof_error::success: return "Success"; @@ -76,15 +115,19 @@ std::string getInstrProfErrString(instrprof_error Err) { llvm_unreachable("A value of instrprof_error has no message."); } +namespace { + // FIXME: This class is only here to support the transition to llvm::Error. It // will be removed once this transition is complete. Clients should prefer to // deal with the Error value directly, rather than converting to error_code. class InstrProfErrorCategoryType : public std::error_category { const char *name() const noexcept override { return "llvm.instrprof"; } + std::string message(int IE) const override { return getInstrProfErrString(static_cast<instrprof_error>(IE)); } }; + } // end anonymous namespace static ManagedStatic<InstrProfErrorCategoryType> ErrorCategory; @@ -93,8 +136,49 @@ const std::error_category &llvm::instrprof_category() { return *ErrorCategory; } +namespace { + +const char *InstrProfSectNameCommon[] = { +#define INSTR_PROF_SECT_ENTRY(Kind, SectNameCommon, SectNameCoff, Prefix) \ + SectNameCommon, +#include "llvm/ProfileData/InstrProfData.inc" +}; + +const char *InstrProfSectNameCoff[] = { +#define INSTR_PROF_SECT_ENTRY(Kind, SectNameCommon, SectNameCoff, Prefix) \ + SectNameCoff, +#include "llvm/ProfileData/InstrProfData.inc" +}; + +const char *InstrProfSectNamePrefix[] = { +#define INSTR_PROF_SECT_ENTRY(Kind, SectNameCommon, SectNameCoff, Prefix) \ + Prefix, +#include "llvm/ProfileData/InstrProfData.inc" +}; + +} // namespace + namespace llvm { +std::string getInstrProfSectionName(InstrProfSectKind IPSK, + Triple::ObjectFormatType OF, + bool AddSegmentInfo) { + std::string SectName; + + if (OF == Triple::MachO && AddSegmentInfo) + SectName = InstrProfSectNamePrefix[IPSK]; + + if (OF == Triple::COFF) + SectName += InstrProfSectNameCoff[IPSK]; + else + SectName += InstrProfSectNameCommon[IPSK]; + + if (OF == Triple::MachO && IPSK == IPSK_data && AddSegmentInfo) + SectName += ",regular,live_support"; + + return SectName; +} + void SoftInstrProfErrors::addError(instrprof_error IE) { if (IE == instrprof_error::success) return; @@ -133,6 +217,24 @@ std::string getPGOFuncName(StringRef RawFuncName, return GlobalValue::getGlobalIdentifier(RawFuncName, Linkage, FileName); } +// Strip NumPrefix level of directory name from PathNameStr. If the number of +// directory separators is less than NumPrefix, strip all the directories and +// leave base file name only. +static StringRef stripDirPrefix(StringRef PathNameStr, uint32_t NumPrefix) { + uint32_t Count = NumPrefix; + uint32_t Pos = 0, LastPos = 0; + for (auto & CI : PathNameStr) { + ++Pos; + if (llvm::sys::path::is_separator(CI)) { + LastPos = Pos; + --Count; + } + if (Count == 0) + break; + } + return PathNameStr.substr(LastPos); +} + // Return the PGOFuncName. This function has some special handling when called // in LTO optimization. The following only applies when calling in LTO passes // (when \c InLTO is true): LTO's internalization privatizes many global linkage @@ -151,6 +253,8 @@ std::string getPGOFuncName(const Function &F, bool InLTO, uint64_t Version) { StringRef FileName = (StaticFuncFullModulePrefix ? F.getParent()->getName() : sys::path::filename(F.getParent()->getName())); + if (StaticFuncFullModulePrefix && StaticFuncStripDirNamePrefix != 0) + FileName = stripDirPrefix(FileName, StaticFuncStripDirNamePrefix); return getPGOFuncName(F.getName(), F.getLinkage(), FileName, Version); } @@ -198,7 +302,6 @@ std::string getPGOFuncNameVarName(StringRef FuncName, GlobalVariable *createPGOFuncNameVar(Module &M, GlobalValue::LinkageTypes Linkage, StringRef PGOFuncName) { - // We generally want to match the function's linkage, but available_externally // and extern_weak both have the wrong semantics, and anything that doesn't // need to link across compilation units doesn't need to be visible at all. @@ -227,23 +330,37 @@ GlobalVariable *createPGOFuncNameVar(Function &F, StringRef PGOFuncName) { return createPGOFuncNameVar(*F.getParent(), F.getLinkage(), PGOFuncName); } -void InstrProfSymtab::create(Module &M, bool InLTO) { +Error InstrProfSymtab::create(Module &M, bool InLTO) { for (Function &F : M) { // Function may not have a name: like using asm("") to overwrite the name. // Ignore in this case. if (!F.hasName()) continue; const std::string &PGOFuncName = getPGOFuncName(F, InLTO); - addFuncName(PGOFuncName); + if (Error E = addFuncName(PGOFuncName)) + return E; MD5FuncMap.emplace_back(Function::getGUID(PGOFuncName), &F); + // In ThinLTO, local function may have been promoted to global and have + // suffix added to the function name. We need to add the stripped function + // name to the symbol table so that we can find a match from profile. + if (InLTO) { + auto pos = PGOFuncName.find('.'); + if (pos != std::string::npos) { + const std::string &OtherFuncName = PGOFuncName.substr(0, pos); + if (Error E = addFuncName(OtherFuncName)) + return E; + MD5FuncMap.emplace_back(Function::getGUID(OtherFuncName), &F); + } + } } finalizeSymtab(); + return Error::success(); } -Error collectPGOFuncNameStrings(const std::vector<std::string> &NameStrs, +Error collectPGOFuncNameStrings(ArrayRef<std::string> NameStrs, bool doCompression, std::string &Result) { - assert(NameStrs.size() && "No name data to emit"); + assert(!NameStrs.empty() && "No name data to emit"); uint8_t Header[16], *P = Header; std::string UncompressedNameStrings = @@ -271,12 +388,12 @@ Error collectPGOFuncNameStrings(const std::vector<std::string> &NameStrs, } SmallString<128> CompressedNameStrings; - zlib::Status Success = - zlib::compress(StringRef(UncompressedNameStrings), CompressedNameStrings, - zlib::BestSizeCompression); - - if (Success != zlib::StatusOK) + Error E = zlib::compress(StringRef(UncompressedNameStrings), + CompressedNameStrings, zlib::BestSizeCompression); + if (E) { + consumeError(std::move(E)); return make_error<InstrProfError>(instrprof_error::compress_failed); + } return WriteStringToResult(CompressedNameStrings.size(), CompressedNameStrings); @@ -289,7 +406,7 @@ StringRef getPGOFuncNameVarInitializer(GlobalVariable *NameVar) { return NameStr; } -Error collectPGOFuncNameStrings(const std::vector<GlobalVariable *> &NameVars, +Error collectPGOFuncNameStrings(ArrayRef<GlobalVariable *> NameVars, std::string &Result, bool doCompression) { std::vector<std::string> NameStrs; for (auto *NameVar : NameVars) { @@ -315,9 +432,12 @@ Error readPGOFuncNameStrings(StringRef NameStrings, InstrProfSymtab &Symtab) { if (isCompressed) { StringRef CompressedNameStrings(reinterpret_cast<const char *>(P), CompressedSize); - if (zlib::uncompress(CompressedNameStrings, UncompressedNameStrings, - UncompressedSize) != zlib::StatusOK) + if (Error E = + zlib::uncompress(CompressedNameStrings, UncompressedNameStrings, + UncompressedSize)) { + consumeError(std::move(E)); return make_error<InstrProfError>(instrprof_error::uncompress_failed); + } P += CompressedSize; NameStrings = StringRef(UncompressedNameStrings.data(), UncompressedNameStrings.size()); @@ -330,7 +450,8 @@ Error readPGOFuncNameStrings(StringRef NameStrings, InstrProfSymtab &Symtab) { SmallVector<StringRef, 0> Names; NameStrings.split(Names, getInstrProfNameSeparator()); for (StringRef &Name : Names) - Symtab.addFuncName(Name); + if (Error E = Symtab.addFuncName(Name)) + return E; while (P < EndP && *P == 0) P++; @@ -339,9 +460,9 @@ Error readPGOFuncNameStrings(StringRef NameStrings, InstrProfSymtab &Symtab) { return Error::success(); } -void InstrProfValueSiteRecord::merge(SoftInstrProfErrors &SIPE, - InstrProfValueSiteRecord &Input, - uint64_t Weight) { +void InstrProfValueSiteRecord::merge(InstrProfValueSiteRecord &Input, + uint64_t Weight, + function_ref<void(instrprof_error)> Warn) { this->sortByTargetValues(); Input.sortByTargetValues(); auto I = ValueData.begin(); @@ -354,7 +475,7 @@ void InstrProfValueSiteRecord::merge(SoftInstrProfErrors &SIPE, bool Overflowed; I->Count = SaturatingMultiplyAdd(J->Count, Weight, I->Count, &Overflowed); if (Overflowed) - SIPE.addError(instrprof_error::counter_overflow); + Warn(instrprof_error::counter_overflow); ++I; continue; } @@ -362,40 +483,43 @@ void InstrProfValueSiteRecord::merge(SoftInstrProfErrors &SIPE, } } -void InstrProfValueSiteRecord::scale(SoftInstrProfErrors &SIPE, - uint64_t Weight) { +void InstrProfValueSiteRecord::scale(uint64_t Weight, + function_ref<void(instrprof_error)> Warn) { for (auto I = ValueData.begin(), IE = ValueData.end(); I != IE; ++I) { bool Overflowed; I->Count = SaturatingMultiply(I->Count, Weight, &Overflowed); if (Overflowed) - SIPE.addError(instrprof_error::counter_overflow); + Warn(instrprof_error::counter_overflow); } } // Merge Value Profile data from Src record to this record for ValueKind. // Scale merged value counts by \p Weight. -void InstrProfRecord::mergeValueProfData(uint32_t ValueKind, - InstrProfRecord &Src, - uint64_t Weight) { +void InstrProfRecord::mergeValueProfData( + uint32_t ValueKind, InstrProfRecord &Src, uint64_t Weight, + function_ref<void(instrprof_error)> Warn) { uint32_t ThisNumValueSites = getNumValueSites(ValueKind); uint32_t OtherNumValueSites = Src.getNumValueSites(ValueKind); if (ThisNumValueSites != OtherNumValueSites) { - SIPE.addError(instrprof_error::value_site_count_mismatch); + Warn(instrprof_error::value_site_count_mismatch); return; } + if (!ThisNumValueSites) + return; std::vector<InstrProfValueSiteRecord> &ThisSiteRecords = - getValueSitesForKind(ValueKind); - std::vector<InstrProfValueSiteRecord> &OtherSiteRecords = + getOrCreateValueSitesForKind(ValueKind); + MutableArrayRef<InstrProfValueSiteRecord> OtherSiteRecords = Src.getValueSitesForKind(ValueKind); for (uint32_t I = 0; I < ThisNumValueSites; I++) - ThisSiteRecords[I].merge(SIPE, OtherSiteRecords[I], Weight); + ThisSiteRecords[I].merge(OtherSiteRecords[I], Weight, Warn); } -void InstrProfRecord::merge(InstrProfRecord &Other, uint64_t Weight) { +void InstrProfRecord::merge(InstrProfRecord &Other, uint64_t Weight, + function_ref<void(instrprof_error)> Warn) { // If the number of counters doesn't match we either have bad data // or a hash collision. if (Counts.size() != Other.Counts.size()) { - SIPE.addError(instrprof_error::count_mismatch); + Warn(instrprof_error::count_mismatch); return; } @@ -404,30 +528,30 @@ void InstrProfRecord::merge(InstrProfRecord &Other, uint64_t Weight) { Counts[I] = SaturatingMultiplyAdd(Other.Counts[I], Weight, Counts[I], &Overflowed); if (Overflowed) - SIPE.addError(instrprof_error::counter_overflow); + Warn(instrprof_error::counter_overflow); } for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) - mergeValueProfData(Kind, Other, Weight); + mergeValueProfData(Kind, Other, Weight, Warn); } -void InstrProfRecord::scaleValueProfData(uint32_t ValueKind, uint64_t Weight) { - uint32_t ThisNumValueSites = getNumValueSites(ValueKind); - std::vector<InstrProfValueSiteRecord> &ThisSiteRecords = - getValueSitesForKind(ValueKind); - for (uint32_t I = 0; I < ThisNumValueSites; I++) - ThisSiteRecords[I].scale(SIPE, Weight); +void InstrProfRecord::scaleValueProfData( + uint32_t ValueKind, uint64_t Weight, + function_ref<void(instrprof_error)> Warn) { + for (auto &R : getValueSitesForKind(ValueKind)) + R.scale(Weight, Warn); } -void InstrProfRecord::scale(uint64_t Weight) { +void InstrProfRecord::scale(uint64_t Weight, + function_ref<void(instrprof_error)> Warn) { for (auto &Count : this->Counts) { bool Overflowed; Count = SaturatingMultiply(Count, Weight, &Overflowed); if (Overflowed) - SIPE.addError(instrprof_error::counter_overflow); + Warn(instrprof_error::counter_overflow); } for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) - scaleValueProfData(Kind, Weight); + scaleValueProfData(Kind, Weight, Warn); } // Map indirect call target name hash to name string. @@ -462,7 +586,7 @@ void InstrProfRecord::addValueData(uint32_t ValueKind, uint32_t Site, VData[I].Value = remapValue(VData[I].Value, ValueKind, ValueMap); } std::vector<InstrProfValueSiteRecord> &ValueSites = - getValueSitesForKind(ValueKind); + getOrCreateValueSitesForKind(ValueKind); if (N == 0) ValueSites.emplace_back(); else @@ -521,8 +645,9 @@ static ValueProfRecordClosure InstrProfRecordClosure = { // Wrapper implementation using the closure mechanism. uint32_t ValueProfData::getSize(const InstrProfRecord &Record) { - InstrProfRecordClosure.Record = &Record; - return getValueProfDataSize(&InstrProfRecordClosure); + auto Closure = InstrProfRecordClosure; + Closure.Record = &Record; + return getValueProfDataSize(&Closure); } // Wrapper implementation using the closure mechanism. @@ -553,6 +678,7 @@ void ValueProfRecord::deserializeTo(InstrProfRecord &Record, void ValueProfRecord::swapBytes(support::endianness Old, support::endianness New) { using namespace support; + if (Old == New) return; @@ -589,6 +715,7 @@ void ValueProfData::deserializeTo(InstrProfRecord &Record, template <class T> static T swapToHostOrder(const unsigned char *&D, support::endianness Orig) { using namespace support; + if (Orig == little) return endian::readNext<T, little, unaligned>(D); else @@ -623,6 +750,7 @@ ValueProfData::getValueProfData(const unsigned char *D, const unsigned char *const BufferEnd, support::endianness Endianness) { using namespace support; + if (D + sizeof(ValueProfData) > BufferEnd) return make_error<InstrProfError>(instrprof_error::truncated); @@ -645,6 +773,7 @@ ValueProfData::getValueProfData(const unsigned char *D, void ValueProfData::swapBytesToHost(support::endianness Endianness) { using namespace support; + if (Endianness == getHostEndianness()) return; @@ -660,6 +789,7 @@ void ValueProfData::swapBytesToHost(support::endianness Endianness) { void ValueProfData::swapBytesFromHost(support::endianness Endianness) { using namespace support; + if (Endianness == getHostEndianness()) return; @@ -791,7 +921,7 @@ bool needsComdatForCounter(const Function &F, const Module &M) { return true; Triple TT(M.getTargetTriple()); - if (!TT.isOSBinFormatELF()) + if (!TT.isOSBinFormatELF() && !TT.isOSBinFormatWasm()) return false; // See createPGOFuncNameVar for more details. To avoid link errors, profile @@ -854,4 +984,26 @@ bool canRenameComdatFunc(const Function &F, bool CheckAddressTaken) { } return true; } + +// Parse the value profile options. +void getMemOPSizeRangeFromOption(StringRef MemOPSizeRange, int64_t &RangeStart, + int64_t &RangeLast) { + static const int64_t DefaultMemOPSizeRangeStart = 0; + static const int64_t DefaultMemOPSizeRangeLast = 8; + RangeStart = DefaultMemOPSizeRangeStart; + RangeLast = DefaultMemOPSizeRangeLast; + + if (!MemOPSizeRange.empty()) { + auto Pos = MemOPSizeRange.find(':'); + if (Pos != std::string::npos) { + if (Pos > 0) + MemOPSizeRange.substr(0, Pos).getAsInteger(10, RangeStart); + if (Pos < MemOPSizeRange.size() - 1) + MemOPSizeRange.substr(Pos + 1).getAsInteger(10, RangeLast); + } else + MemOPSizeRange.getAsInteger(10, RangeLast); + } + assert(RangeLast >= RangeStart); +} + } // end namespace llvm diff --git a/contrib/llvm/lib/ProfileData/InstrProfReader.cpp b/contrib/llvm/lib/ProfileData/InstrProfReader.cpp index ad407f0..1b39a06 100644 --- a/contrib/llvm/lib/ProfileData/InstrProfReader.cpp +++ b/contrib/llvm/lib/ProfileData/InstrProfReader.cpp @@ -1,4 +1,4 @@ -//=-- InstrProfReader.cpp - Instrumented profiling reader -------------------=// +//===- InstrProfReader.cpp - Instrumented profiling reader ----------------===// // // The LLVM Compiler Infrastructure // @@ -13,8 +13,26 @@ //===----------------------------------------------------------------------===// #include "llvm/ProfileData/InstrProfReader.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" -#include <cassert> +#include "llvm/ADT/StringRef.h" +#include "llvm/IR/ProfileSummary.h" +#include "llvm/ProfileData/InstrProf.h" +#include "llvm/ProfileData/ProfileCommon.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SwapByteOrder.h" +#include <algorithm> +#include <cctype> +#include <cstddef> +#include <cstdint> +#include <limits> +#include <memory> +#include <system_error> +#include <utility> +#include <vector> using namespace llvm; @@ -78,7 +96,6 @@ IndexedInstrProfReader::create(const Twine &Path) { return IndexedInstrProfReader::create(std::move(BufferOrError.get())); } - Expected<std::unique_ptr<IndexedInstrProfReader>> IndexedInstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer) { // Sanity check the buffer. @@ -182,8 +199,9 @@ TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) { CHECK_LINE_END(Line); std::pair<StringRef, StringRef> VD = Line->rsplit(':'); uint64_t TakenCount, Value; - if (VK == IPVK_IndirectCallTarget) { - Symtab->addFuncName(VD.first); + if (ValueKind == IPVK_IndirectCallTarget) { + if (Error E = Symtab->addFuncName(VD.first)) + return E; Value = IndexedInstrProf::ComputeHash(VD.first); } else { READ_NUM(VD.first, Value); @@ -192,7 +210,8 @@ TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) { CurrentValues.push_back({Value, TakenCount}); Line++; } - Record.addValueData(VK, S, CurrentValues.data(), NumValueData, nullptr); + Record.addValueData(ValueKind, S, CurrentValues.data(), NumValueData, + nullptr); } } return success(); @@ -202,7 +221,7 @@ TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) { #undef VP_READ_ADVANCE } -Error TextInstrProfReader::readNextRecord(InstrProfRecord &Record) { +Error TextInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) { // Skip empty lines and comments. while (!Line.is_at_end() && (Line->empty() || Line->startswith("#"))) ++Line; @@ -214,7 +233,8 @@ Error TextInstrProfReader::readNextRecord(InstrProfRecord &Record) { // Read the function name. Record.Name = *Line++; - Symtab->addFuncName(Record.Name); + if (Error E = Symtab->addFuncName(Record.Name)) + return E; // Read the function hash. if (Line.is_at_end()) @@ -232,7 +252,7 @@ Error TextInstrProfReader::readNextRecord(InstrProfRecord &Record) { return error(instrprof_error::malformed); // Read each counter and fill our internal storage with the values. - Record.Counts.clear(); + Record.Clear(); Record.Counts.reserve(NumCounters); for (uint64_t I = 0; I < NumCounters; ++I) { if (Line.is_at_end()) @@ -357,13 +377,13 @@ Error RawInstrProfReader<IntPtrT>::readHeader( } template <class IntPtrT> -Error RawInstrProfReader<IntPtrT>::readName(InstrProfRecord &Record) { +Error RawInstrProfReader<IntPtrT>::readName(NamedInstrProfRecord &Record) { Record.Name = getName(Data->NameRef); return success(); } template <class IntPtrT> -Error RawInstrProfReader<IntPtrT>::readFuncHash(InstrProfRecord &Record) { +Error RawInstrProfReader<IntPtrT>::readFuncHash(NamedInstrProfRecord &Record) { Record.Hash = swap(Data->FuncHash); return success(); } @@ -398,7 +418,6 @@ Error RawInstrProfReader<IntPtrT>::readRawCounts( template <class IntPtrT> Error RawInstrProfReader<IntPtrT>::readValueProfilingData( InstrProfRecord &Record) { - Record.clearValueData(); CurValueDataSize = 0; // Need to match the logic in value profile dumper code in compiler-rt: @@ -426,7 +445,7 @@ Error RawInstrProfReader<IntPtrT>::readValueProfilingData( } template <class IntPtrT> -Error RawInstrProfReader<IntPtrT>::readNextRecord(InstrProfRecord &Record) { +Error RawInstrProfReader<IntPtrT>::readNextRecord(NamedInstrProfRecord &Record) { if (atEnd()) // At this point, ValueDataStart field points to the next header. if (Error E = readNextHeader(getNextHeaderPos())) @@ -454,17 +473,19 @@ Error RawInstrProfReader<IntPtrT>::readNextRecord(InstrProfRecord &Record) { } namespace llvm { + template class RawInstrProfReader<uint32_t>; template class RawInstrProfReader<uint64_t>; -} + +} // end namespace llvm InstrProfLookupTrait::hash_value_type InstrProfLookupTrait::ComputeHash(StringRef K) { return IndexedInstrProf::ComputeHash(HashType, K); } -typedef InstrProfLookupTrait::data_type data_type; -typedef InstrProfLookupTrait::offset_type offset_type; +using data_type = InstrProfLookupTrait::data_type; +using offset_type = InstrProfLookupTrait::offset_type; bool InstrProfLookupTrait::readValueProfilingData( const unsigned char *&D, const unsigned char *const End) { @@ -482,6 +503,8 @@ bool InstrProfLookupTrait::readValueProfilingData( data_type InstrProfLookupTrait::ReadData(StringRef K, const unsigned char *D, offset_type N) { + using namespace support; + // Check if the data is corrupt. If so, don't try to read it. if (N % sizeof(uint64_t)) return data_type(); @@ -489,7 +512,6 @@ data_type InstrProfLookupTrait::ReadData(StringRef K, const unsigned char *D, DataBuffer.clear(); std::vector<uint64_t> CounterBuffer; - using namespace support; const unsigned char *End = D + N; while (D < End) { // Read hash. @@ -528,7 +550,7 @@ data_type InstrProfLookupTrait::ReadData(StringRef K, const unsigned char *D, template <typename HashTableImpl> Error InstrProfReaderIndex<HashTableImpl>::getRecords( - StringRef FuncName, ArrayRef<InstrProfRecord> &Data) { + StringRef FuncName, ArrayRef<NamedInstrProfRecord> &Data) { auto Iter = HashTable->find(FuncName); if (Iter == HashTable->end()) return make_error<InstrProfError>(instrprof_error::unknown_function); @@ -542,7 +564,7 @@ Error InstrProfReaderIndex<HashTableImpl>::getRecords( template <typename HashTableImpl> Error InstrProfReaderIndex<HashTableImpl>::getRecords( - ArrayRef<InstrProfRecord> &Data) { + ArrayRef<NamedInstrProfRecord> &Data) { if (atEnd()) return make_error<InstrProfError>(instrprof_error::eof); @@ -567,9 +589,10 @@ InstrProfReaderIndex<HashTableImpl>::InstrProfReaderIndex( } bool IndexedInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) { + using namespace support; + if (DataBuffer.getBufferSize() < 8) return false; - using namespace support; uint64_t Magic = endian::read<uint64_t, little, aligned>(DataBuffer.getBufferStart()); // Verify that it's magical. @@ -581,6 +604,7 @@ IndexedInstrProfReader::readSummary(IndexedInstrProf::ProfVersion Version, const unsigned char *Cur) { using namespace IndexedInstrProf; using namespace support; + if (Version >= IndexedInstrProf::Version4) { const IndexedInstrProf::Summary *SummaryInLE = reinterpret_cast<const IndexedInstrProf::Summary *>(Cur); @@ -598,7 +622,7 @@ IndexedInstrProfReader::readSummary(IndexedInstrProf::ProfVersion Version, for (unsigned I = 0; I < SummarySize / sizeof(uint64_t); I++) Dst[I] = endian::byte_swap<uint64_t, little>(Src[I]); - llvm::SummaryEntryVector DetailedSummary; + 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, @@ -617,23 +641,24 @@ IndexedInstrProfReader::readSummary(IndexedInstrProf::ProfVersion Version, } else { // For older version of profile data, we need to compute on the fly: using namespace IndexedInstrProf; + InstrProfSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs); // FIXME: This only computes an empty summary. Need to call addRecord for - // all InstrProfRecords to get the correct summary. + // all NamedInstrProfRecords to get the correct summary. this->Summary = Builder.getSummary(); return Cur; } } Error IndexedInstrProfReader::readHeader() { + using namespace support; + const unsigned char *Start = (const unsigned char *)DataBuffer->getBufferStart(); const unsigned char *Cur = Start; if ((const unsigned char *)DataBuffer->getBufferEnd() - Cur < 24) return error(instrprof_error::truncated); - using namespace support; - auto *Header = reinterpret_cast<const IndexedInstrProf::Header *>(Cur); Cur += sizeof(IndexedInstrProf::Header); @@ -671,7 +696,9 @@ InstrProfSymtab &IndexedInstrProfReader::getSymtab() { return *Symtab.get(); std::unique_ptr<InstrProfSymtab> NewSymtab = make_unique<InstrProfSymtab>(); - Index->populateSymtab(*NewSymtab.get()); + if (Error E = Index->populateSymtab(*NewSymtab.get())) { + consumeError(error(InstrProfError::take(std::move(E)))); + } Symtab = std::move(NewSymtab); return *Symtab.get(); @@ -680,7 +707,7 @@ InstrProfSymtab &IndexedInstrProfReader::getSymtab() { Expected<InstrProfRecord> IndexedInstrProfReader::getInstrProfRecord(StringRef FuncName, uint64_t FuncHash) { - ArrayRef<InstrProfRecord> Data; + ArrayRef<NamedInstrProfRecord> Data; Error Err = Index->getRecords(FuncName, Data); if (Err) return std::move(Err); @@ -705,10 +732,10 @@ Error IndexedInstrProfReader::getFunctionCounts(StringRef FuncName, return success(); } -Error IndexedInstrProfReader::readNextRecord(InstrProfRecord &Record) { +Error IndexedInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) { static unsigned RecordIndex = 0; - ArrayRef<InstrProfRecord> Data; + ArrayRef<NamedInstrProfRecord> Data; Error E = Index->getRecords(Data); if (E) diff --git a/contrib/llvm/lib/ProfileData/InstrProfWriter.cpp b/contrib/llvm/lib/ProfileData/InstrProfWriter.cpp index 029d756..ce3f880 100644 --- a/contrib/llvm/lib/ProfileData/InstrProfWriter.cpp +++ b/contrib/llvm/lib/ProfileData/InstrProfWriter.cpp @@ -1,4 +1,4 @@ -//=-- InstrProfWriter.cpp - Instrumented profiling writer -------------------=// +//===- InstrProfWriter.cpp - Instrumented profiling writer ----------------===// // // The LLVM Compiler Infrastructure // @@ -13,14 +13,20 @@ //===----------------------------------------------------------------------===// #include "llvm/ProfileData/InstrProfWriter.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/IR/ProfileSummary.h" +#include "llvm/ProfileData/InstrProf.h" #include "llvm/ProfileData/ProfileCommon.h" +#include "llvm/Support/Endian.h" #include "llvm/Support/EndianStream.h" +#include "llvm/Support/Error.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/OnDiskHashTable.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> +#include <cstdint> +#include <memory> #include <string> #include <tuple> #include <utility> @@ -41,10 +47,9 @@ namespace llvm { // A wrapper class to abstract writer stream with support of bytes // back patching. class ProfOStream { - public: - ProfOStream(llvm::raw_fd_ostream &FD) : IsFDOStream(true), OS(FD), LE(FD) {} - ProfOStream(llvm::raw_string_ostream &STR) + ProfOStream(raw_fd_ostream &FD) : IsFDOStream(true), OS(FD), LE(FD) {} + ProfOStream(raw_string_ostream &STR) : IsFDOStream(false), OS(STR), LE(STR) {} uint64_t tell() { return OS.tell(); } @@ -55,16 +60,16 @@ public: // directly and it won't be reflected in the stream's internal buffer. void patch(PatchItem *P, int NItems) { using namespace support; + if (IsFDOStream) { - llvm::raw_fd_ostream &FDOStream = static_cast<llvm::raw_fd_ostream &>(OS); + raw_fd_ostream &FDOStream = static_cast<raw_fd_ostream &>(OS); for (int K = 0; K < NItems; K++) { FDOStream.seek(P[K].Pos); for (int I = 0; I < P[K].N; I++) write(P[K].D[I]); } } else { - llvm::raw_string_ostream &SOStream = - static_cast<llvm::raw_string_ostream &>(OS); + raw_string_ostream &SOStream = static_cast<raw_string_ostream &>(OS); std::string &Data = SOStream.str(); // with flush for (int K = 0; K < NItems; K++) { for (int I = 0; I < P[K].N; I++) { @@ -85,26 +90,28 @@ public: class InstrProfRecordWriterTrait { public: - typedef StringRef key_type; - typedef StringRef key_type_ref; + using key_type = StringRef; + using key_type_ref = StringRef; - typedef const InstrProfWriter::ProfilingData *const data_type; - typedef const InstrProfWriter::ProfilingData *const data_type_ref; + using data_type = const InstrProfWriter::ProfilingData *const; + using data_type_ref = const InstrProfWriter::ProfilingData *const; - typedef uint64_t hash_value_type; - typedef uint64_t offset_type; + using hash_value_type = uint64_t; + using offset_type = uint64_t; - support::endianness ValueProfDataEndianness; + support::endianness ValueProfDataEndianness = support::little; InstrProfSummaryBuilder *SummaryBuilder; - InstrProfRecordWriterTrait() : ValueProfDataEndianness(support::little) {} + InstrProfRecordWriterTrait() = default; + static hash_value_type ComputeHash(key_type_ref K) { return IndexedInstrProf::ComputeHash(K); } static std::pair<offset_type, offset_type> EmitKeyDataLength(raw_ostream &Out, key_type_ref K, data_type_ref V) { - using namespace llvm::support; + using namespace support; + endian::Writer<little> LE(Out); offset_type N = K.size(); @@ -130,7 +137,8 @@ public: } void EmitData(raw_ostream &Out, key_type_ref, data_type_ref V, offset_type) { - using namespace llvm::support; + using namespace support; + endian::Writer<little> LE(Out); for (const auto &ProfileData : *V) { const InstrProfRecord &ProfRecord = ProfileData.second; @@ -154,8 +162,7 @@ public: } // end namespace llvm InstrProfWriter::InstrProfWriter(bool Sparse) - : Sparse(Sparse), FunctionData(), ProfileKind(PF_Unknown), - InfoObj(new InstrProfRecordWriterTrait()) {} + : Sparse(Sparse), InfoObj(new InstrProfRecordWriterTrait()) {} InstrProfWriter::~InstrProfWriter() { delete InfoObj; } @@ -169,38 +176,46 @@ void InstrProfWriter::setOutputSparse(bool Sparse) { this->Sparse = Sparse; } -Error InstrProfWriter::addRecord(InstrProfRecord &&I, uint64_t Weight) { - auto &ProfileDataMap = FunctionData[I.Name]; +void InstrProfWriter::addRecord(NamedInstrProfRecord &&I, uint64_t Weight, + function_ref<void(Error)> Warn) { + auto Name = I.Name; + auto Hash = I.Hash; + addRecord(Name, Hash, std::move(I), Weight, Warn); +} + +void InstrProfWriter::addRecord(StringRef Name, uint64_t Hash, + InstrProfRecord &&I, uint64_t Weight, + function_ref<void(Error)> Warn) { + auto &ProfileDataMap = FunctionData[Name]; bool NewFunc; ProfilingData::iterator Where; std::tie(Where, NewFunc) = - ProfileDataMap.insert(std::make_pair(I.Hash, InstrProfRecord())); + ProfileDataMap.insert(std::make_pair(Hash, InstrProfRecord())); InstrProfRecord &Dest = Where->second; + auto MapWarn = [&](instrprof_error E) { + Warn(make_error<InstrProfError>(E)); + }; + if (NewFunc) { // We've never seen a function with this name and hash, add it. Dest = std::move(I); - // Fix up the name to avoid dangling reference. - Dest.Name = FunctionData.find(Dest.Name)->getKey(); if (Weight > 1) - Dest.scale(Weight); + Dest.scale(Weight, MapWarn); } else { // We're updating a function we've seen before. - Dest.merge(I, Weight); + Dest.merge(I, Weight, MapWarn); } Dest.sortValueData(); - - return Dest.takeError(); } -Error InstrProfWriter::mergeRecordsFromWriter(InstrProfWriter &&IPW) { +void InstrProfWriter::mergeRecordsFromWriter(InstrProfWriter &&IPW, + function_ref<void(Error)> Warn) { for (auto &I : IPW.FunctionData) for (auto &Func : I.getValue()) - if (Error E = addRecord(std::move(Func.second), 1)) - return E; - return Error::success(); + addRecord(I.getKey(), Func.first, std::move(Func.second), 1, Warn); } bool InstrProfWriter::shouldEncodeData(const ProfilingData &PD) { @@ -208,7 +223,7 @@ bool InstrProfWriter::shouldEncodeData(const ProfilingData &PD) { return true; for (const auto &Func : PD) { const InstrProfRecord &IPR = Func.second; - if (any_of(IPR.Counts, [](uint64_t Count) { return Count > 0; })) + if (llvm::any_of(IPR.Counts, [](uint64_t Count) { return Count > 0; })) return true; } return false; @@ -217,6 +232,7 @@ bool InstrProfWriter::shouldEncodeData(const ProfilingData &PD) { static void setSummary(IndexedInstrProf::Summary *TheSummary, ProfileSummary &PS) { using namespace IndexedInstrProf; + std::vector<ProfileSummaryEntry> &Res = PS.getDetailedSummary(); TheSummary->NumSummaryFields = Summary::NumKinds; TheSummary->NumCutoffEntries = Res.size(); @@ -231,9 +247,10 @@ static void setSummary(IndexedInstrProf::Summary *TheSummary, } void InstrProfWriter::writeImpl(ProfOStream &OS) { + using namespace IndexedInstrProf; + OnDiskChainedHashTableGenerator<InstrProfRecordWriterTrait> Generator; - using namespace IndexedInstrProf; InstrProfSummaryBuilder ISB(ProfileSummaryBuilder::DefaultCutoffs); InfoObj->SummaryBuilder = &ISB; @@ -301,7 +318,7 @@ void InstrProfWriter::write(raw_fd_ostream &OS) { std::unique_ptr<MemoryBuffer> InstrProfWriter::writeBuffer() { std::string Data; - llvm::raw_string_ostream OS(Data); + raw_string_ostream OS(Data); ProfOStream POS(OS); // Write the hash table. writeImpl(POS); @@ -314,11 +331,12 @@ static const char *ValueProfKindStr[] = { #include "llvm/ProfileData/InstrProfData.inc" }; -void InstrProfWriter::writeRecordInText(const InstrProfRecord &Func, +void InstrProfWriter::writeRecordInText(StringRef Name, uint64_t Hash, + const InstrProfRecord &Func, InstrProfSymtab &Symtab, raw_fd_ostream &OS) { - OS << Func.Name << "\n"; - OS << "# Func Hash:\n" << Func.Hash << "\n"; + OS << Name << "\n"; + OS << "# Func Hash:\n" << Hash << "\n"; OS << "# Num Counters:\n" << Func.Counts.size() << "\n"; OS << "# Counter Values:\n"; for (uint64_t Count : Func.Counts) @@ -353,17 +371,19 @@ void InstrProfWriter::writeRecordInText(const InstrProfRecord &Func, OS << "\n"; } -void InstrProfWriter::writeText(raw_fd_ostream &OS) { +Error InstrProfWriter::writeText(raw_fd_ostream &OS) { if (ProfileKind == PF_IRLevel) OS << "# IR level Instrumentation Flag\n:ir\n"; InstrProfSymtab Symtab; for (const auto &I : FunctionData) if (shouldEncodeData(I.getValue())) - Symtab.addFuncName(I.getKey()); + if (Error E = Symtab.addFuncName(I.getKey())) + return E; Symtab.finalizeSymtab(); for (const auto &I : FunctionData) if (shouldEncodeData(I.getValue())) for (const auto &Func : I.getValue()) - writeRecordInText(Func.second, Symtab, OS); + writeRecordInText(I.getKey(), Func.first, Func.second, Symtab, OS); + return Error::success(); } diff --git a/contrib/llvm/lib/ProfileData/SampleProf.cpp b/contrib/llvm/lib/ProfileData/SampleProf.cpp index 5bcfff0..eafdd21 100644 --- a/contrib/llvm/lib/ProfileData/SampleProf.cpp +++ b/contrib/llvm/lib/ProfileData/SampleProf.cpp @@ -13,18 +13,25 @@ //===----------------------------------------------------------------------===// #include "llvm/ProfileData/SampleProf.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/raw_ostream.h" +#include <string> +#include <system_error> -using namespace llvm::sampleprof; using namespace llvm; +using namespace sampleprof; namespace { + // FIXME: This class is only here to support the transition to llvm::Error. It // will be removed once this transition is complete. Clients should prefer to // deal with the Error value directly, rather than converting to error_code. class SampleProfErrorCategoryType : public std::error_category { const char *name() const noexcept override { return "llvm.sampleprof"; } + std::string message(int IE) const override { sampleprof_error E = static_cast<sampleprof_error>(IE); switch (E) { @@ -54,7 +61,8 @@ class SampleProfErrorCategoryType : public std::error_category { llvm_unreachable("A value of sampleprof_error has no message."); } }; -} + +} // end anonymous namespace static ManagedStatic<SampleProfErrorCategoryType> ErrorCategory; @@ -74,7 +82,9 @@ raw_ostream &llvm::sampleprof::operator<<(raw_ostream &OS, return OS; } +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void LineLocation::dump() const { print(dbgs()); } +#endif /// \brief Print the sample record to the stream \p OS indented by \p Indent. void SampleRecord::print(raw_ostream &OS, unsigned Indent) const { @@ -87,7 +97,9 @@ void SampleRecord::print(raw_ostream &OS, unsigned Indent) const { OS << "\n"; } +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void SampleRecord::dump() const { print(dbgs(), 0); } +#endif raw_ostream &llvm::sampleprof::operator<<(raw_ostream &OS, const SampleRecord &Sample) { @@ -101,7 +113,7 @@ void FunctionSamples::print(raw_ostream &OS, unsigned Indent) const { << " sampled lines\n"; OS.indent(Indent); - if (BodySamples.size() > 0) { + if (!BodySamples.empty()) { OS << "Samples collected in the function's body {\n"; SampleSorter<LineLocation, SampleRecord> SortedBodySamples(BodySamples); for (const auto &SI : SortedBodySamples.get()) { @@ -115,14 +127,16 @@ void FunctionSamples::print(raw_ostream &OS, unsigned Indent) const { } OS.indent(Indent); - if (CallsiteSamples.size() > 0) { + if (!CallsiteSamples.empty()) { OS << "Samples collected in inlined callsites {\n"; - SampleSorter<LineLocation, FunctionSamples> SortedCallsiteSamples( + SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples( CallsiteSamples); for (const auto &CS : SortedCallsiteSamples.get()) { - OS.indent(Indent + 2); - OS << CS->first << ": inlined callee: " << CS->second.getName() << ": "; - CS->second.print(OS, Indent + 4); + for (const auto &FS : CS->second) { + OS.indent(Indent + 2); + OS << CS->first << ": inlined callee: " << FS.second.getName() << ": "; + FS.second.print(OS, Indent + 4); + } } OS << "}\n"; } else { @@ -136,4 +150,6 @@ raw_ostream &llvm::sampleprof::operator<<(raw_ostream &OS, return OS; } -void FunctionSamples::dump(void) const { print(dbgs(), 0); } +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +LLVM_DUMP_METHOD void FunctionSamples::dump() const { print(dbgs(), 0); } +#endif diff --git a/contrib/llvm/lib/ProfileData/SampleProfReader.cpp b/contrib/llvm/lib/ProfileData/SampleProfReader.cpp index af80b03..234fe02 100644 --- a/contrib/llvm/lib/ProfileData/SampleProfReader.cpp +++ b/contrib/llvm/lib/ProfileData/SampleProfReader.cpp @@ -23,14 +23,25 @@ #include "llvm/ProfileData/SampleProfReader.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/Support/Debug.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/IR/ProfileSummary.h" +#include "llvm/ProfileData/ProfileCommon.h" +#include "llvm/ProfileData/SampleProf.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/LineIterator.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cstddef> +#include <cstdint> +#include <limits> +#include <memory> +#include <system_error> +#include <vector> -using namespace llvm::sampleprof; using namespace llvm; +using namespace sampleprof; /// \brief Dump the function profile for \p FName. /// @@ -200,7 +211,7 @@ std::error_code SampleProfileReaderText::read() { InlineStack.pop_back(); } FunctionSamples &FSamples = InlineStack.back()->functionSamplesAt( - LineLocation(LineOffset, Discriminator)); + LineLocation(LineOffset, Discriminator))[FName]; FSamples.setName(FName); MergeResult(Result, FSamples.addTotalSamples(NumSamples)); InlineStack.push_back(&FSamples); @@ -352,8 +363,8 @@ SampleProfileReaderBinary::readProfile(FunctionSamples &FProfile) { if (std::error_code EC = FName.getError()) return EC; - FunctionSamples &CalleeProfile = - FProfile.functionSamplesAt(LineLocation(*LineOffset, *Discriminator)); + FunctionSamples &CalleeProfile = FProfile.functionSamplesAt( + LineLocation(*LineOffset, *Discriminator))[*FName]; CalleeProfile.setName(*FName); if (std::error_code EC = readProfile(CalleeProfile)) return EC; @@ -625,7 +636,7 @@ std::error_code SampleProfileReaderGCC::readOneFunctionProfile( uint32_t LineOffset = Offset >> 16; uint32_t Discriminator = Offset & 0xffff; FProfile = &CallerProfile->functionSamplesAt( - LineLocation(LineOffset, Discriminator)); + LineLocation(LineOffset, Discriminator))[Name]; } FProfile->setName(Name); @@ -681,11 +692,9 @@ std::error_code SampleProfileReaderGCC::readOneFunctionProfile( if (!GcovBuffer.readInt64(TargetCount)) return sampleprof_error::truncated; - if (Update) { - FunctionSamples &TargetProfile = Profiles[TargetName]; - TargetProfile.addCalledTargetSamples(LineOffset, Discriminator, - TargetName, TargetCount); - } + if (Update) + FProfile->addCalledTargetSamples(LineOffset, Discriminator, + TargetName, TargetCount); } } diff --git a/contrib/llvm/lib/ProfileData/SampleProfWriter.cpp b/contrib/llvm/lib/ProfileData/SampleProfWriter.cpp index 4fa7128..b450261 100644 --- a/contrib/llvm/lib/ProfileData/SampleProfWriter.cpp +++ b/contrib/llvm/lib/ProfileData/SampleProfWriter.cpp @@ -19,15 +19,49 @@ //===----------------------------------------------------------------------===// #include "llvm/ProfileData/SampleProfWriter.h" -#include "llvm/Support/Debug.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ProfileData/ProfileCommon.h" +#include "llvm/ProfileData/SampleProf.h" #include "llvm/Support/ErrorOr.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/LEB128.h" -#include "llvm/Support/LineIterator.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Regex.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cstdint> +#include <memory> +#include <set> +#include <system_error> +#include <utility> +#include <vector> -using namespace llvm::sampleprof; using namespace llvm; +using namespace sampleprof; + +std::error_code +SampleProfileWriter::write(const StringMap<FunctionSamples> &ProfileMap) { + if (std::error_code EC = writeHeader(ProfileMap)) + return EC; + + // Sort the ProfileMap by total samples. + typedef std::pair<StringRef, const FunctionSamples *> NameFunctionSamples; + std::vector<NameFunctionSamples> V; + for (const auto &I : ProfileMap) + V.push_back(std::make_pair(I.getKey(), &I.second)); + + std::stable_sort( + V.begin(), V.end(), + [](const NameFunctionSamples &A, const NameFunctionSamples &B) { + if (A.second->getTotalSamples() == B.second->getTotalSamples()) + return A.first > B.first; + return A.second->getTotalSamples() > B.second->getTotalSamples(); + }); + + for (const auto &I : V) { + if (std::error_code EC = write(*I.second)) + return EC; + } + return sampleprof_error::success; +} /// \brief Write samples to a text file. /// @@ -61,20 +95,21 @@ std::error_code SampleProfileWriterText::write(const FunctionSamples &S) { OS << "\n"; } - SampleSorter<LineLocation, FunctionSamples> SortedCallsiteSamples( + SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples( S.getCallsiteSamples()); Indent += 1; - for (const auto &I : SortedCallsiteSamples.get()) { - LineLocation Loc = I->first; - const FunctionSamples &CalleeSamples = I->second; - OS.indent(Indent); - if (Loc.Discriminator == 0) - OS << Loc.LineOffset << ": "; - else - OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; - if (std::error_code EC = write(CalleeSamples)) - return EC; - } + for (const auto &I : SortedCallsiteSamples.get()) + for (const auto &FS : I->second) { + LineLocation Loc = I->first; + const FunctionSamples &CalleeSamples = FS.second; + OS.indent(Indent); + if (Loc.Discriminator == 0) + OS << Loc.LineOffset << ": "; + else + OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; + if (std::error_code EC = write(CalleeSamples)) + return EC; + } Indent -= 1; return sampleprof_error::success; @@ -89,8 +124,7 @@ std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) { } void SampleProfileWriterBinary::addName(StringRef FName) { - auto NextIdx = NameTable.size(); - NameTable.insert(std::make_pair(FName, NextIdx)); + NameTable.insert(std::make_pair(FName, 0)); } void SampleProfileWriterBinary::addNames(const FunctionSamples &S) { @@ -102,11 +136,12 @@ void SampleProfileWriterBinary::addNames(const FunctionSamples &S) { } // Recursively add all the names for inlined callsites. - for (const auto &J : S.getCallsiteSamples()) { - const FunctionSamples &CalleeSamples = J.second; - addName(CalleeSamples.getName()); - addNames(CalleeSamples); - } + for (const auto &J : S.getCallsiteSamples()) + for (const auto &FS : J.second) { + const FunctionSamples &CalleeSamples = FS.second; + addName(CalleeSamples.getName()); + addNames(CalleeSamples); + } } std::error_code SampleProfileWriterBinary::writeHeader( @@ -127,10 +162,18 @@ std::error_code SampleProfileWriterBinary::writeHeader( addNames(I.second); } + // Sort the names to make NameTable is deterministic. + std::set<StringRef> 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 : NameTable) { - OS << N.first; + for (auto N : V) { + OS << N; encodeULEB128(0, OS); } return sampleprof_error::success; @@ -180,14 +223,15 @@ std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) { // Recursively emit all the callsite samples. encodeULEB128(S.getCallsiteSamples().size(), OS); - for (const auto &J : S.getCallsiteSamples()) { - LineLocation Loc = J.first; - const FunctionSamples &CalleeSamples = J.second; - encodeULEB128(Loc.LineOffset, OS); - encodeULEB128(Loc.Discriminator, OS); - if (std::error_code EC = writeBody(CalleeSamples)) - return EC; - } + for (const auto &J : S.getCallsiteSamples()) + for (const auto &FS : J.second) { + LineLocation Loc = J.first; + const FunctionSamples &CalleeSamples = FS.second; + encodeULEB128(Loc.LineOffset, OS); + encodeULEB128(Loc.Discriminator, OS); + if (std::error_code EC = writeBody(CalleeSamples)) + return EC; + } return sampleprof_error::success; } |