diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:12 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:12 +0000 |
commit | e6d1592492a3a379186bfb02bd0f4eda0669c0d5 (patch) | |
tree | 599ab169a01f1c86eda9adc774edaedde2f2db5b /lib/ProfileData | |
parent | 1a56a5ead7a2e84bee8240f5f6b033b5f1707154 (diff) |
Notes
Diffstat (limited to 'lib/ProfileData')
-rw-r--r-- | lib/ProfileData/Coverage/CoverageMapping.cpp | 18 | ||||
-rw-r--r-- | lib/ProfileData/Coverage/CoverageMappingReader.cpp | 235 | ||||
-rw-r--r-- | lib/ProfileData/Coverage/CoverageMappingWriter.cpp | 24 | ||||
-rw-r--r-- | lib/ProfileData/GCOV.cpp | 26 | ||||
-rw-r--r-- | lib/ProfileData/InstrProf.cpp | 293 | ||||
-rw-r--r-- | lib/ProfileData/InstrProfReader.cpp | 47 | ||||
-rw-r--r-- | lib/ProfileData/InstrProfWriter.cpp | 107 | ||||
-rw-r--r-- | lib/ProfileData/ProfileSummaryBuilder.cpp | 20 | ||||
-rw-r--r-- | lib/ProfileData/SampleProf.cpp | 7 | ||||
-rw-r--r-- | lib/ProfileData/SampleProfReader.cpp | 11 | ||||
-rw-r--r-- | lib/ProfileData/SampleProfWriter.cpp | 12 |
11 files changed, 630 insertions, 170 deletions
diff --git a/lib/ProfileData/Coverage/CoverageMapping.cpp b/lib/ProfileData/Coverage/CoverageMapping.cpp index b2dde3406a63..afd6618e7cb3 100644 --- a/lib/ProfileData/Coverage/CoverageMapping.cpp +++ b/lib/ProfileData/Coverage/CoverageMapping.cpp @@ -1,9 +1,8 @@ //===- CoverageMapping.cpp - Code coverage mapping support ----------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -286,11 +285,14 @@ CoverageMapping::load(ArrayRef<StringRef> ObjectFilenames, if (std::error_code EC = CovMappingBufOrErr.getError()) return errorCodeToError(EC); StringRef Arch = Arches.empty() ? StringRef() : Arches[File.index()]; - auto CoverageReaderOrErr = - BinaryCoverageReader::create(CovMappingBufOrErr.get(), Arch); - if (Error E = CoverageReaderOrErr.takeError()) + MemoryBufferRef CovMappingBufRef = + CovMappingBufOrErr.get()->getMemBufferRef(); + auto CoverageReadersOrErr = + BinaryCoverageReader::create(CovMappingBufRef, Arch, Buffers); + if (Error E = CoverageReadersOrErr.takeError()) return std::move(E); - Readers.push_back(std::move(CoverageReaderOrErr.get())); + for (auto &Reader : CoverageReadersOrErr.get()) + Readers.push_back(std::move(Reader)); Buffers.push_back(std::move(CovMappingBufOrErr.get())); } return load(Readers, *ProfileReader); diff --git a/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/lib/ProfileData/Coverage/CoverageMappingReader.cpp index ee48256bc2e5..e193e10f91d9 100644 --- a/lib/ProfileData/Coverage/CoverageMappingReader.cpp +++ b/lib/ProfileData/Coverage/CoverageMappingReader.cpp @@ -1,9 +1,8 @@ //===- CoverageMappingReader.cpp - Code coverage mapping reader -----------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -23,6 +22,7 @@ #include "llvm/Object/Error.h" #include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Object/COFF.h" #include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" @@ -59,7 +59,7 @@ Error RawCoverageReader::readULEB128(uint64_t &Result) { if (Data.empty()) return make_error<CoverageMapError>(coveragemap_error::truncated); unsigned N = 0; - Result = decodeULEB128(reinterpret_cast<const uint8_t *>(Data.data()), &N); + Result = decodeULEB128(Data.bytes_begin(), &N); if (N > Data.size()) return make_error<CoverageMapError>(coveragemap_error::malformed); Data = Data.substr(N); @@ -348,9 +348,18 @@ Expected<bool> RawCoverageMappingDummyChecker::isDummy() { } Error InstrProfSymtab::create(SectionRef &Section) { - if (auto EC = Section.getContents(Data)) - return errorCodeToError(EC); + Expected<StringRef> DataOrErr = Section.getContents(); + if (!DataOrErr) + return DataOrErr.takeError(); + Data = *DataOrErr; Address = Section.getAddress(); + + // If this is a linked PE/COFF file, then we have to skip over the null byte + // that is allocated in the .lprfn$A section in the LLVM profiling runtime. + const ObjectFile *Obj = Section.getObject(); + if (isa<COFFObjectFile>(Obj) && !Obj->isRelocatableObject()) + Data = Data.drop_front(1); + return Error::success(); } @@ -577,35 +586,65 @@ static Error readCoverageMappingData( static const char *TestingFormatMagic = "llvmcovmtestdata"; -static Error loadTestingFormat(StringRef Data, InstrProfSymtab &ProfileNames, - StringRef &CoverageMapping, - uint8_t &BytesInAddress, - support::endianness &Endian) { - BytesInAddress = 8; - Endian = support::endianness::little; +Expected<std::unique_ptr<BinaryCoverageReader>> +BinaryCoverageReader::createCoverageReaderFromBuffer( + StringRef Coverage, InstrProfSymtab &&ProfileNames, uint8_t BytesInAddress, + support::endianness Endian) { + std::unique_ptr<BinaryCoverageReader> Reader(new BinaryCoverageReader()); + Reader->ProfileNames = std::move(ProfileNames); + if (BytesInAddress == 4 && Endian == support::endianness::little) { + if (Error E = + readCoverageMappingData<uint32_t, support::endianness::little>( + Reader->ProfileNames, Coverage, Reader->MappingRecords, + Reader->Filenames)) + return std::move(E); + } else if (BytesInAddress == 4 && Endian == support::endianness::big) { + if (Error E = readCoverageMappingData<uint32_t, support::endianness::big>( + Reader->ProfileNames, Coverage, Reader->MappingRecords, + Reader->Filenames)) + return std::move(E); + } else if (BytesInAddress == 8 && Endian == support::endianness::little) { + if (Error E = + readCoverageMappingData<uint64_t, support::endianness::little>( + Reader->ProfileNames, Coverage, Reader->MappingRecords, + Reader->Filenames)) + return std::move(E); + } else if (BytesInAddress == 8 && Endian == support::endianness::big) { + if (Error E = readCoverageMappingData<uint64_t, support::endianness::big>( + Reader->ProfileNames, Coverage, Reader->MappingRecords, + Reader->Filenames)) + return std::move(E); + } else + return make_error<CoverageMapError>(coveragemap_error::malformed); + return std::move(Reader); +} + +static Expected<std::unique_ptr<BinaryCoverageReader>> +loadTestingFormat(StringRef Data) { + uint8_t BytesInAddress = 8; + support::endianness Endian = support::endianness::little; Data = Data.substr(StringRef(TestingFormatMagic).size()); if (Data.empty()) return make_error<CoverageMapError>(coveragemap_error::truncated); unsigned N = 0; - auto ProfileNamesSize = - decodeULEB128(reinterpret_cast<const uint8_t *>(Data.data()), &N); + uint64_t ProfileNamesSize = decodeULEB128(Data.bytes_begin(), &N); if (N > Data.size()) return make_error<CoverageMapError>(coveragemap_error::malformed); Data = Data.substr(N); if (Data.empty()) return make_error<CoverageMapError>(coveragemap_error::truncated); N = 0; - uint64_t Address = - decodeULEB128(reinterpret_cast<const uint8_t *>(Data.data()), &N); + uint64_t Address = decodeULEB128(Data.bytes_begin(), &N); if (N > Data.size()) return make_error<CoverageMapError>(coveragemap_error::malformed); Data = Data.substr(N); if (Data.size() < ProfileNamesSize) return make_error<CoverageMapError>(coveragemap_error::malformed); + InstrProfSymtab ProfileNames; if (Error E = ProfileNames.create(Data.substr(0, ProfileNamesSize), Address)) - return E; - CoverageMapping = Data.substr(ProfileNamesSize); + return std::move(E); + StringRef CoverageMapping = Data.substr(ProfileNamesSize); // Skip the padding bytes because coverage map data has an alignment of 8. if (CoverageMapping.empty()) return make_error<CoverageMapError>(coveragemap_error::truncated); @@ -613,29 +652,32 @@ static Error loadTestingFormat(StringRef Data, InstrProfSymtab &ProfileNames, if (CoverageMapping.size() < Pad) return make_error<CoverageMapError>(coveragemap_error::malformed); CoverageMapping = CoverageMapping.substr(Pad); - return Error::success(); + return BinaryCoverageReader::createCoverageReaderFromBuffer( + CoverageMapping, std::move(ProfileNames), BytesInAddress, Endian); } static Expected<SectionRef> lookupSection(ObjectFile &OF, StringRef Name) { + // On COFF, the object file section name may end in "$M". This tells the + // linker to sort these sections between "$A" and "$Z". The linker removes the + // dollar and everything after it in the final binary. Do the same to match. + bool IsCOFF = isa<COFFObjectFile>(OF); + auto stripSuffix = [IsCOFF](StringRef N) { + return IsCOFF ? N.split('$').first : N; + }; + Name = stripSuffix(Name); + StringRef FoundName; for (const auto &Section : OF.sections()) { if (auto EC = Section.getName(FoundName)) return errorCodeToError(EC); - if (FoundName == Name) + if (stripSuffix(FoundName) == Name) return Section; } return make_error<CoverageMapError>(coveragemap_error::no_data_found); } -static Error loadBinaryFormat(MemoryBufferRef ObjectBuffer, - InstrProfSymtab &ProfileNames, - StringRef &CoverageMapping, - uint8_t &BytesInAddress, - support::endianness &Endian, StringRef Arch) { - auto BinOrErr = createBinary(ObjectBuffer); - if (!BinOrErr) - return BinOrErr.takeError(); - auto Bin = std::move(BinOrErr.get()); +static Expected<std::unique_ptr<BinaryCoverageReader>> +loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch) { std::unique_ptr<ObjectFile> OF; if (auto *Universal = dyn_cast<MachOUniversalBinary>(Bin.get())) { // If we have a universal binary, try to look up the object for the @@ -655,9 +697,10 @@ static Error loadBinaryFormat(MemoryBufferRef ObjectBuffer, return make_error<CoverageMapError>(coveragemap_error::malformed); // The coverage uses native pointer sizes for the object it's written in. - BytesInAddress = OF->getBytesInAddress(); - Endian = OF->isLittleEndian() ? support::endianness::little - : support::endianness::big; + uint8_t BytesInAddress = OF->getBytesInAddress(); + support::endianness Endian = OF->isLittleEndian() + ? support::endianness::little + : support::endianness::big; // Look for the sections that we are interested in. auto ObjFormat = OF->getTripleObjectFormat(); @@ -665,63 +708,101 @@ static Error loadBinaryFormat(MemoryBufferRef ObjectBuffer, lookupSection(*OF, getInstrProfSectionName(IPSK_name, ObjFormat, /*AddSegmentInfo=*/false)); if (auto E = NamesSection.takeError()) - return E; + return std::move(E); auto CoverageSection = lookupSection(*OF, getInstrProfSectionName(IPSK_covmap, ObjFormat, /*AddSegmentInfo=*/false)); if (auto E = CoverageSection.takeError()) - return E; + return std::move(E); // Get the contents of the given sections. - if (auto EC = CoverageSection->getContents(CoverageMapping)) - return errorCodeToError(EC); + auto CoverageMappingOrErr = CoverageSection->getContents(); + if (!CoverageMappingOrErr) + return CoverageMappingOrErr.takeError(); + + InstrProfSymtab ProfileNames; if (Error E = ProfileNames.create(*NamesSection)) - return E; + return std::move(E); - return Error::success(); + return BinaryCoverageReader::createCoverageReaderFromBuffer( + CoverageMappingOrErr.get(), std::move(ProfileNames), BytesInAddress, + Endian); } -Expected<std::unique_ptr<BinaryCoverageReader>> -BinaryCoverageReader::create(std::unique_ptr<MemoryBuffer> &ObjectBuffer, - StringRef Arch) { - std::unique_ptr<BinaryCoverageReader> Reader(new BinaryCoverageReader()); +Expected<std::vector<std::unique_ptr<BinaryCoverageReader>>> +BinaryCoverageReader::create( + MemoryBufferRef ObjectBuffer, StringRef Arch, + SmallVectorImpl<std::unique_ptr<MemoryBuffer>> &ObjectFileBuffers) { + std::vector<std::unique_ptr<BinaryCoverageReader>> Readers; - StringRef Coverage; - uint8_t BytesInAddress; - support::endianness Endian; - Error E = Error::success(); - consumeError(std::move(E)); - if (ObjectBuffer->getBuffer().startswith(TestingFormatMagic)) + if (ObjectBuffer.getBuffer().startswith(TestingFormatMagic)) { // This is a special format used for testing. - E = loadTestingFormat(ObjectBuffer->getBuffer(), Reader->ProfileNames, - Coverage, BytesInAddress, Endian); - else - E = loadBinaryFormat(ObjectBuffer->getMemBufferRef(), Reader->ProfileNames, - Coverage, BytesInAddress, Endian, Arch); - if (E) - return std::move(E); + auto ReaderOrErr = loadTestingFormat(ObjectBuffer.getBuffer()); + if (!ReaderOrErr) + return ReaderOrErr.takeError(); + Readers.push_back(std::move(ReaderOrErr.get())); + return std::move(Readers); + } - if (BytesInAddress == 4 && Endian == support::endianness::little) - E = readCoverageMappingData<uint32_t, support::endianness::little>( - Reader->ProfileNames, Coverage, Reader->MappingRecords, - Reader->Filenames); - else if (BytesInAddress == 4 && Endian == support::endianness::big) - E = readCoverageMappingData<uint32_t, support::endianness::big>( - Reader->ProfileNames, Coverage, Reader->MappingRecords, - Reader->Filenames); - else if (BytesInAddress == 8 && Endian == support::endianness::little) - E = readCoverageMappingData<uint64_t, support::endianness::little>( - Reader->ProfileNames, Coverage, Reader->MappingRecords, - Reader->Filenames); - else if (BytesInAddress == 8 && Endian == support::endianness::big) - E = readCoverageMappingData<uint64_t, support::endianness::big>( - Reader->ProfileNames, Coverage, Reader->MappingRecords, - Reader->Filenames); - else - return make_error<CoverageMapError>(coveragemap_error::malformed); - if (E) - return std::move(E); - return std::move(Reader); + auto BinOrErr = createBinary(ObjectBuffer); + if (!BinOrErr) + return BinOrErr.takeError(); + std::unique_ptr<Binary> Bin = std::move(BinOrErr.get()); + + // MachO universal binaries which contain archives need to be treated as + // archives, not as regular binaries. + if (auto *Universal = dyn_cast<MachOUniversalBinary>(Bin.get())) { + for (auto &ObjForArch : Universal->objects()) { + // Skip slices within the universal binary which target the wrong arch. + std::string ObjArch = ObjForArch.getArchFlagName(); + if (Arch != ObjArch) + continue; + + auto ArchiveOrErr = ObjForArch.getAsArchive(); + if (!ArchiveOrErr) { + // If this is not an archive, try treating it as a regular object. + consumeError(ArchiveOrErr.takeError()); + break; + } + + return BinaryCoverageReader::create( + ArchiveOrErr.get()->getMemoryBufferRef(), Arch, ObjectFileBuffers); + } + } + + // Load coverage out of archive members. + if (auto *Ar = dyn_cast<Archive>(Bin.get())) { + Error Err = Error::success(); + for (auto &Child : Ar->children(Err)) { + Expected<MemoryBufferRef> ChildBufOrErr = Child.getMemoryBufferRef(); + if (!ChildBufOrErr) + return ChildBufOrErr.takeError(); + + auto ChildReadersOrErr = BinaryCoverageReader::create( + ChildBufOrErr.get(), Arch, ObjectFileBuffers); + if (!ChildReadersOrErr) + return ChildReadersOrErr.takeError(); + for (auto &Reader : ChildReadersOrErr.get()) + Readers.push_back(std::move(Reader)); + } + if (Err) + return std::move(Err); + + // Thin archives reference object files outside of the archive file, i.e. + // files which reside in memory not owned by the caller. Transfer ownership + // to the caller. + if (Ar->isThin()) + for (auto &Buffer : Ar->takeThinBuffers()) + ObjectFileBuffers.push_back(std::move(Buffer)); + + return std::move(Readers); + } + + auto ReaderOrErr = loadBinaryFormat(std::move(Bin), Arch); + if (!ReaderOrErr) + return ReaderOrErr.takeError(); + Readers.push_back(std::move(ReaderOrErr.get())); + return std::move(Readers); } Error BinaryCoverageReader::readNextRecord(CoverageMappingRecord &Record) { diff --git a/lib/ProfileData/Coverage/CoverageMappingWriter.cpp b/lib/ProfileData/Coverage/CoverageMappingWriter.cpp index bb3f4f854e04..432b20f217ca 100644 --- a/lib/ProfileData/Coverage/CoverageMappingWriter.cpp +++ b/lib/ProfileData/Coverage/CoverageMappingWriter.cpp @@ -1,9 +1,8 @@ //===- CoverageMappingWriter.cpp - Code coverage mapping writer -----------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -125,15 +124,14 @@ void CoverageMappingWriter::write(raw_ostream &OS) { // Sort the regions in an ascending order by the file id and the starting // location. Sort by region kinds to ensure stable order for tests. - std::stable_sort( - MappingRegions.begin(), MappingRegions.end(), - [](const CounterMappingRegion &LHS, const CounterMappingRegion &RHS) { - if (LHS.FileID != RHS.FileID) - return LHS.FileID < RHS.FileID; - if (LHS.startLoc() != RHS.startLoc()) - return LHS.startLoc() < RHS.startLoc(); - return LHS.Kind < RHS.Kind; - }); + llvm::stable_sort(MappingRegions, [](const CounterMappingRegion &LHS, + const CounterMappingRegion &RHS) { + if (LHS.FileID != RHS.FileID) + return LHS.FileID < RHS.FileID; + if (LHS.startLoc() != RHS.startLoc()) + return LHS.startLoc() < RHS.startLoc(); + return LHS.Kind < RHS.Kind; + }); // Write out the fileid -> filename mapping. encodeULEB128(VirtualFileMapping.size(), OS); diff --git a/lib/ProfileData/GCOV.cpp b/lib/ProfileData/GCOV.cpp index b687346a2c05..fa4e433d7aa6 100644 --- a/lib/ProfileData/GCOV.cpp +++ b/lib/ProfileData/GCOV.cpp @@ -1,9 +1,8 @@ //===- GCOV.cpp - LLVM coverage tool --------------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -19,6 +18,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" #include "llvm/Support/Path.h" +#include "llvm/Support/MD5.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <system_error> @@ -396,10 +396,10 @@ void GCOVBlock::addCount(size_t DstEdgeNo, uint64_t N) { /// sortDstEdges - Sort destination edges by block number, nop if already /// sorted. This is required for printing branch info in the correct order. void GCOVBlock::sortDstEdges() { - if (!DstEdgesAreSorted) { - SortDstEdgesFunctor SortEdges; - std::stable_sort(DstEdges.begin(), DstEdges.end(), SortEdges); - } + if (!DstEdgesAreSorted) + llvm::stable_sort(DstEdges, [](const GCOVEdge *E1, const GCOVEdge *E2) { + return E1->Dst.Number < E2->Dst.Number; + }); } /// collectLineCounts - Collect line counts. This must be used after @@ -687,7 +687,15 @@ std::string FileInfo::getCoveragePath(StringRef Filename, if (Options.LongFileNames && !Filename.equals(MainFilename)) CoveragePath = mangleCoveragePath(MainFilename, Options.PreservePaths) + "##"; - CoveragePath += mangleCoveragePath(Filename, Options.PreservePaths) + ".gcov"; + CoveragePath += mangleCoveragePath(Filename, Options.PreservePaths); + if (Options.HashFilenames) { + MD5 Hasher; + MD5::MD5Result Result; + Hasher.update(Filename.str()); + Hasher.final(Result); + CoveragePath += "##" + Result.digest().str().str(); + } + CoveragePath += ".gcov"; return CoveragePath; } diff --git a/lib/ProfileData/InstrProf.cpp b/lib/ProfileData/InstrProf.cpp index aaa8000ff2f9..510fd9887d9a 100644 --- a/lib/ProfileData/InstrProf.cpp +++ b/lib/ProfileData/InstrProf.cpp @@ -1,9 +1,8 @@ //===- InstrProf.cpp - Instrumented profiling format support --------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -30,6 +29,7 @@ #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/IR/Type.h" +#include "llvm/ProfileData/InstrProfReader.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" @@ -363,16 +363,15 @@ Error InstrProfSymtab::create(Module &M, bool InLTO) { uint64_t InstrProfSymtab::getFunctionHashFromAddress(uint64_t Address) { finalizeSymtab(); - auto Result = - std::lower_bound(AddrToMD5Map.begin(), AddrToMD5Map.end(), Address, - [](const std::pair<uint64_t, uint64_t> &LHS, - uint64_t RHS) { return LHS.first < RHS; }); + auto It = partition_point(AddrToMD5Map, [=](std::pair<uint64_t, uint64_t> A) { + return A.first < Address; + }); // Raw function pointer collected by value profiler may be from // external functions that are not instrumented. They won't have // mapping data to be used by the deserializer. Force the value to // be 0 in this case. - if (Result != AddrToMD5Map.end() && Result->first == Address) - return (uint64_t)Result->second; + if (It != AddrToMD5Map.end() && It->first == Address) + return (uint64_t)It->second; return 0; } @@ -435,9 +434,8 @@ Error collectPGOFuncNameStrings(ArrayRef<GlobalVariable *> NameVars, } Error readPGOFuncNameStrings(StringRef NameStrings, InstrProfSymtab &Symtab) { - const uint8_t *P = reinterpret_cast<const uint8_t *>(NameStrings.data()); - const uint8_t *EndP = reinterpret_cast<const uint8_t *>(NameStrings.data() + - NameStrings.size()); + const uint8_t *P = NameStrings.bytes_begin(); + const uint8_t *EndP = NameStrings.bytes_end(); while (P < EndP) { uint32_t N; uint64_t UncompressedSize = decodeULEB128(P, &N); @@ -480,6 +478,126 @@ Error readPGOFuncNameStrings(StringRef NameStrings, InstrProfSymtab &Symtab) { return Error::success(); } +void InstrProfRecord::accumuateCounts(CountSumOrPercent &Sum) const { + uint64_t FuncSum = 0; + Sum.NumEntries += Counts.size(); + for (size_t F = 0, E = Counts.size(); F < E; ++F) + FuncSum += Counts[F]; + Sum.CountSum += FuncSum; + + for (uint32_t VK = IPVK_First; VK <= IPVK_Last; ++VK) { + uint64_t KindSum = 0; + uint32_t NumValueSites = getNumValueSites(VK); + for (size_t I = 0; I < NumValueSites; ++I) { + uint32_t NV = getNumValueDataForSite(VK, I); + std::unique_ptr<InstrProfValueData[]> VD = getValueForSite(VK, I); + for (uint32_t V = 0; V < NV; V++) + KindSum += VD[V].Count; + } + Sum.ValueCounts[VK] += KindSum; + } +} + +void InstrProfValueSiteRecord::overlap(InstrProfValueSiteRecord &Input, + uint32_t ValueKind, + OverlapStats &Overlap, + OverlapStats &FuncLevelOverlap) { + this->sortByTargetValues(); + Input.sortByTargetValues(); + double Score = 0.0f, FuncLevelScore = 0.0f; + auto I = ValueData.begin(); + auto IE = ValueData.end(); + auto J = Input.ValueData.begin(); + auto JE = Input.ValueData.end(); + while (I != IE && J != JE) { + if (I->Value == J->Value) { + Score += OverlapStats::score(I->Count, J->Count, + Overlap.Base.ValueCounts[ValueKind], + Overlap.Test.ValueCounts[ValueKind]); + FuncLevelScore += OverlapStats::score( + I->Count, J->Count, FuncLevelOverlap.Base.ValueCounts[ValueKind], + FuncLevelOverlap.Test.ValueCounts[ValueKind]); + ++I; + } else if (I->Value < J->Value) { + ++I; + continue; + } + ++J; + } + Overlap.Overlap.ValueCounts[ValueKind] += Score; + FuncLevelOverlap.Overlap.ValueCounts[ValueKind] += FuncLevelScore; +} + +// Return false on mismatch. +void InstrProfRecord::overlapValueProfData(uint32_t ValueKind, + InstrProfRecord &Other, + OverlapStats &Overlap, + OverlapStats &FuncLevelOverlap) { + uint32_t ThisNumValueSites = getNumValueSites(ValueKind); + assert(ThisNumValueSites == Other.getNumValueSites(ValueKind)); + if (!ThisNumValueSites) + return; + + std::vector<InstrProfValueSiteRecord> &ThisSiteRecords = + getOrCreateValueSitesForKind(ValueKind); + MutableArrayRef<InstrProfValueSiteRecord> OtherSiteRecords = + Other.getValueSitesForKind(ValueKind); + for (uint32_t I = 0; I < ThisNumValueSites; I++) + ThisSiteRecords[I].overlap(OtherSiteRecords[I], ValueKind, Overlap, + FuncLevelOverlap); +} + +void InstrProfRecord::overlap(InstrProfRecord &Other, OverlapStats &Overlap, + OverlapStats &FuncLevelOverlap, + uint64_t ValueCutoff) { + // FuncLevel CountSum for other should already computed and nonzero. + assert(FuncLevelOverlap.Test.CountSum >= 1.0f); + accumuateCounts(FuncLevelOverlap.Base); + bool Mismatch = (Counts.size() != Other.Counts.size()); + + // Check if the value profiles mismatch. + if (!Mismatch) { + for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) { + uint32_t ThisNumValueSites = getNumValueSites(Kind); + uint32_t OtherNumValueSites = Other.getNumValueSites(Kind); + if (ThisNumValueSites != OtherNumValueSites) { + Mismatch = true; + break; + } + } + } + if (Mismatch) { + Overlap.addOneMismatch(FuncLevelOverlap.Test); + return; + } + + // Compute overlap for value counts. + for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) + overlapValueProfData(Kind, Other, Overlap, FuncLevelOverlap); + + double Score = 0.0; + uint64_t MaxCount = 0; + // Compute overlap for edge counts. + for (size_t I = 0, E = Other.Counts.size(); I < E; ++I) { + Score += OverlapStats::score(Counts[I], Other.Counts[I], + Overlap.Base.CountSum, Overlap.Test.CountSum); + MaxCount = std::max(Other.Counts[I], MaxCount); + } + Overlap.Overlap.CountSum += Score; + Overlap.Overlap.NumEntries += 1; + + if (MaxCount >= ValueCutoff) { + double FuncScore = 0.0; + for (size_t I = 0, E = Other.Counts.size(); I < E; ++I) + FuncScore += OverlapStats::score(Counts[I], Other.Counts[I], + FuncLevelOverlap.Base.CountSum, + FuncLevelOverlap.Test.CountSum); + FuncLevelOverlap.Overlap.CountSum = FuncScore; + FuncLevelOverlap.Overlap.NumEntries = Other.Counts.size(); + FuncLevelOverlap.Valid = true; + } +} + void InstrProfValueSiteRecord::merge(InstrProfValueSiteRecord &Input, uint64_t Weight, function_ref<void(instrprof_error)> Warn) { @@ -1012,4 +1130,153 @@ void getMemOPSizeRangeFromOption(StringRef MemOPSizeRange, int64_t &RangeStart, assert(RangeLast >= RangeStart); } +// Create a COMDAT variable INSTR_PROF_RAW_VERSION_VAR to make the runtime +// aware this is an ir_level profile so it can set the version flag. +void createIRLevelProfileFlagVar(Module &M, bool IsCS) { + const StringRef VarName(INSTR_PROF_QUOTE(INSTR_PROF_RAW_VERSION_VAR)); + Type *IntTy64 = Type::getInt64Ty(M.getContext()); + uint64_t ProfileVersion = (INSTR_PROF_RAW_VERSION | VARIANT_MASK_IR_PROF); + if (IsCS) + ProfileVersion |= VARIANT_MASK_CSIR_PROF; + auto IRLevelVersionVariable = new GlobalVariable( + M, IntTy64, true, GlobalValue::WeakAnyLinkage, + Constant::getIntegerValue(IntTy64, APInt(64, ProfileVersion)), VarName); + IRLevelVersionVariable->setVisibility(GlobalValue::DefaultVisibility); + Triple TT(M.getTargetTriple()); + if (TT.supportsCOMDAT()) { + IRLevelVersionVariable->setLinkage(GlobalValue::ExternalLinkage); + IRLevelVersionVariable->setComdat(M.getOrInsertComdat(VarName)); + } +} + +// Create the variable for the profile file name. +void createProfileFileNameVar(Module &M, StringRef InstrProfileOutput) { + if (InstrProfileOutput.empty()) + return; + Constant *ProfileNameConst = + ConstantDataArray::getString(M.getContext(), InstrProfileOutput, true); + GlobalVariable *ProfileNameVar = new GlobalVariable( + M, ProfileNameConst->getType(), true, GlobalValue::WeakAnyLinkage, + ProfileNameConst, INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_NAME_VAR)); + Triple TT(M.getTargetTriple()); + if (TT.supportsCOMDAT()) { + ProfileNameVar->setLinkage(GlobalValue::ExternalLinkage); + ProfileNameVar->setComdat(M.getOrInsertComdat( + StringRef(INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_NAME_VAR)))); + } +} + +Error OverlapStats::accumuateCounts(const std::string &BaseFilename, + const std::string &TestFilename, + bool IsCS) { + auto getProfileSum = [IsCS](const std::string &Filename, + CountSumOrPercent &Sum) -> Error { + auto ReaderOrErr = InstrProfReader::create(Filename); + if (Error E = ReaderOrErr.takeError()) { + return E; + } + auto Reader = std::move(ReaderOrErr.get()); + Reader->accumuateCounts(Sum, IsCS); + return Error::success(); + }; + auto Ret = getProfileSum(BaseFilename, Base); + if (Ret) + return Ret; + Ret = getProfileSum(TestFilename, Test); + if (Ret) + return Ret; + this->BaseFilename = &BaseFilename; + this->TestFilename = &TestFilename; + Valid = true; + return Error::success(); +} + +void OverlapStats::addOneMismatch(const CountSumOrPercent &MismatchFunc) { + Mismatch.NumEntries += 1; + Mismatch.CountSum += MismatchFunc.CountSum / Test.CountSum; + for (unsigned I = 0; I < IPVK_Last - IPVK_First + 1; I++) { + if (Test.ValueCounts[I] >= 1.0f) + Mismatch.ValueCounts[I] += + MismatchFunc.ValueCounts[I] / Test.ValueCounts[I]; + } +} + +void OverlapStats::addOneUnique(const CountSumOrPercent &UniqueFunc) { + Unique.NumEntries += 1; + Unique.CountSum += UniqueFunc.CountSum / Test.CountSum; + for (unsigned I = 0; I < IPVK_Last - IPVK_First + 1; I++) { + if (Test.ValueCounts[I] >= 1.0f) + Unique.ValueCounts[I] += UniqueFunc.ValueCounts[I] / Test.ValueCounts[I]; + } +} + +void OverlapStats::dump(raw_fd_ostream &OS) const { + if (!Valid) + return; + + const char *EntryName = + (Level == ProgramLevel ? "functions" : "edge counters"); + if (Level == ProgramLevel) { + OS << "Profile overlap infomation for base_profile: " << *BaseFilename + << " and test_profile: " << *TestFilename << "\nProgram level:\n"; + } else { + OS << "Function level:\n" + << " Function: " << FuncName << " (Hash=" << FuncHash << ")\n"; + } + + OS << " # of " << EntryName << " overlap: " << Overlap.NumEntries << "\n"; + if (Mismatch.NumEntries) + OS << " # of " << EntryName << " mismatch: " << Mismatch.NumEntries + << "\n"; + if (Unique.NumEntries) + OS << " # of " << EntryName + << " only in test_profile: " << Unique.NumEntries << "\n"; + + OS << " Edge profile overlap: " << format("%.3f%%", Overlap.CountSum * 100) + << "\n"; + if (Mismatch.NumEntries) + OS << " Mismatched count percentage (Edge): " + << format("%.3f%%", Mismatch.CountSum * 100) << "\n"; + if (Unique.NumEntries) + OS << " Percentage of Edge profile only in test_profile: " + << format("%.3f%%", Unique.CountSum * 100) << "\n"; + OS << " Edge profile base count sum: " << format("%.0f", Base.CountSum) + << "\n" + << " Edge profile test count sum: " << format("%.0f", Test.CountSum) + << "\n"; + + for (unsigned I = 0; I < IPVK_Last - IPVK_First + 1; I++) { + if (Base.ValueCounts[I] < 1.0f && Test.ValueCounts[I] < 1.0f) + continue; + char ProfileKindName[20]; + switch (I) { + case IPVK_IndirectCallTarget: + strncpy(ProfileKindName, "IndirectCall", 19); + break; + case IPVK_MemOPSize: + strncpy(ProfileKindName, "MemOP", 19); + break; + default: + snprintf(ProfileKindName, 19, "VP[%d]", I); + break; + } + OS << " " << ProfileKindName + << " profile overlap: " << format("%.3f%%", Overlap.ValueCounts[I] * 100) + << "\n"; + if (Mismatch.NumEntries) + OS << " Mismatched count percentage (" << ProfileKindName + << "): " << format("%.3f%%", Mismatch.ValueCounts[I] * 100) << "\n"; + if (Unique.NumEntries) + OS << " Percentage of " << ProfileKindName + << " profile only in test_profile: " + << format("%.3f%%", Unique.ValueCounts[I] * 100) << "\n"; + OS << " " << ProfileKindName + << " profile base count sum: " << format("%.0f", Base.ValueCounts[I]) + << "\n" + << " " << ProfileKindName + << " profile test count sum: " << format("%.0f", Test.ValueCounts[I]) + << "\n"; + } +} + } // end namespace llvm diff --git a/lib/ProfileData/InstrProfReader.cpp b/lib/ProfileData/InstrProfReader.cpp index eaf0eb04bfbf..fec1c152991c 100644 --- a/lib/ProfileData/InstrProfReader.cpp +++ b/lib/ProfileData/InstrProfReader.cpp @@ -1,9 +1,8 @@ //===- InstrProfReader.cpp - Instrumented profiling reader ----------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -63,7 +62,7 @@ InstrProfReader::create(const Twine &Path) { Expected<std::unique_ptr<InstrProfReader>> InstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer) { // Sanity check the buffer. - if (uint64_t(Buffer->getBufferSize()) > std::numeric_limits<unsigned>::max()) + if (uint64_t(Buffer->getBufferSize()) > std::numeric_limits<uint64_t>::max()) return make_error<InstrProfError>(instrprof_error::too_large); if (Buffer->getBufferSize() == 0) @@ -114,7 +113,7 @@ Expected<std::unique_ptr<IndexedInstrProfReader>> IndexedInstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer, std::unique_ptr<MemoryBuffer> RemappingBuffer) { // Sanity check the buffer. - if (uint64_t(Buffer->getBufferSize()) > std::numeric_limits<unsigned>::max()) + if (uint64_t(Buffer->getBufferSize()) > std::numeric_limits<uint64_t>::max()) return make_error<InstrProfError>(instrprof_error::too_large); // Create the reader. @@ -163,7 +162,10 @@ Error TextInstrProfReader::readHeader() { IsIRInstr = true; else if (Str.equals_lower("fe")) IsIRInstr = false; - else + else if (Str.equals_lower("csir")) { + IsIRInstr = true; + HasCSIRLevelProfile = true; + } else return error(instrprof_error::bad_header); ++Line; @@ -734,7 +736,7 @@ bool IndexedInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) { const unsigned char * IndexedInstrProfReader::readSummary(IndexedInstrProf::ProfVersion Version, - const unsigned char *Cur) { + const unsigned char *Cur, bool UseCS) { using namespace IndexedInstrProf; using namespace support; @@ -761,10 +763,13 @@ IndexedInstrProfReader::readSummary(IndexedInstrProf::ProfVersion Version, DetailedSummary.emplace_back((uint32_t)Ent.Cutoff, Ent.MinBlockCount, Ent.NumBlocks); } + std::unique_ptr<llvm::ProfileSummary> &Summary = + UseCS ? this->CS_Summary : this->Summary; + // initialize InstrProfSummary using the SummaryData from disk. - this->Summary = llvm::make_unique<ProfileSummary>( - ProfileSummary::PSK_Instr, DetailedSummary, - SummaryData->get(Summary::TotalBlockCount), + Summary = llvm::make_unique<ProfileSummary>( + UseCS ? ProfileSummary::PSK_CSInstr : ProfileSummary::PSK_Instr, + DetailedSummary, SummaryData->get(Summary::TotalBlockCount), SummaryData->get(Summary::MaxBlockCount), SummaryData->get(Summary::MaxInternalBlockCount), SummaryData->get(Summary::MaxFunctionCount), @@ -806,7 +811,11 @@ Error IndexedInstrProfReader::readHeader() { IndexedInstrProf::ProfVersion::CurrentVersion) return error(instrprof_error::unsupported_version); - Cur = readSummary((IndexedInstrProf::ProfVersion)FormatVersion, Cur); + Cur = readSummary((IndexedInstrProf::ProfVersion)FormatVersion, Cur, + /* UseCS */ false); + if (FormatVersion & VARIANT_MASK_CSIR_PROF) + Cur = readSummary((IndexedInstrProf::ProfVersion)FormatVersion, Cur, + /* UseCS */ true); // Read the hash type and start offset. IndexedInstrProf::HashT HashType = static_cast<IndexedInstrProf::HashT>( @@ -891,3 +900,17 @@ Error IndexedInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) { } return success(); } + +void InstrProfReader::accumuateCounts(CountSumOrPercent &Sum, bool IsCS) { + uint64_t NumFuncs = 0; + for (const auto &Func : *this) { + if (isIRLevelProfile()) { + bool FuncIsCS = NamedInstrProfRecord::hasCSFlagInHash(Func.Hash); + if (FuncIsCS != IsCS) + continue; + } + Func.accumuateCounts(Sum); + ++NumFuncs; + } + Sum.NumEntries = NumFuncs; +} diff --git a/lib/ProfileData/InstrProfWriter.cpp b/lib/ProfileData/InstrProfWriter.cpp index 18b9deec158f..4ca2defd26da 100644 --- a/lib/ProfileData/InstrProfWriter.cpp +++ b/lib/ProfileData/InstrProfWriter.cpp @@ -1,9 +1,8 @@ //===- InstrProfWriter.cpp - Instrumented profiling writer ----------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -102,6 +101,7 @@ public: support::endianness ValueProfDataEndianness = support::little; InstrProfSummaryBuilder *SummaryBuilder; + InstrProfSummaryBuilder *CSSummaryBuilder; InstrProfRecordWriterTrait() = default; @@ -143,7 +143,10 @@ public: endian::Writer LE(Out, little); for (const auto &ProfileData : *V) { const InstrProfRecord &ProfRecord = ProfileData.second; - SummaryBuilder->addRecord(ProfRecord); + if (NamedInstrProfRecord::hasCSFlagInHash(ProfileData.first)) + CSSummaryBuilder->addRecord(ProfRecord); + else + SummaryBuilder->addRecord(ProfRecord); LE.write<uint64_t>(ProfileData.first); // Function hash LE.write<uint64_t>(ProfRecord.Counts.size()); @@ -184,6 +187,40 @@ void InstrProfWriter::addRecord(NamedInstrProfRecord &&I, uint64_t Weight, addRecord(Name, Hash, std::move(I), Weight, Warn); } +void InstrProfWriter::overlapRecord(NamedInstrProfRecord &&Other, + OverlapStats &Overlap, + OverlapStats &FuncLevelOverlap, + const OverlapFuncFilters &FuncFilter) { + auto Name = Other.Name; + auto Hash = Other.Hash; + Other.accumuateCounts(FuncLevelOverlap.Test); + if (FunctionData.find(Name) == FunctionData.end()) { + Overlap.addOneUnique(FuncLevelOverlap.Test); + return; + } + if (FuncLevelOverlap.Test.CountSum < 1.0f) { + Overlap.Overlap.NumEntries += 1; + return; + } + auto &ProfileDataMap = FunctionData[Name]; + bool NewFunc; + ProfilingData::iterator Where; + std::tie(Where, NewFunc) = + ProfileDataMap.insert(std::make_pair(Hash, InstrProfRecord())); + if (NewFunc) { + Overlap.addOneMismatch(FuncLevelOverlap.Test); + return; + } + InstrProfRecord &Dest = Where->second; + + uint64_t ValueCutoff = FuncFilter.ValueCutoff; + if (!FuncFilter.NameFilter.empty() && + Name.find(FuncFilter.NameFilter) != Name.npos) + ValueCutoff = 0; + + Dest.overlap(Other, Overlap, FuncLevelOverlap, ValueCutoff); +} + void InstrProfWriter::addRecord(StringRef Name, uint64_t Hash, InstrProfRecord &&I, uint64_t Weight, function_ref<void(Error)> Warn) { @@ -254,6 +291,8 @@ void InstrProfWriter::writeImpl(ProfOStream &OS) { InstrProfSummaryBuilder ISB(ProfileSummaryBuilder::DefaultCutoffs); InfoObj->SummaryBuilder = &ISB; + InstrProfSummaryBuilder CSISB(ProfileSummaryBuilder::DefaultCutoffs); + InfoObj->CSSummaryBuilder = &CSISB; // Populate the hash table generator. for (const auto &I : FunctionData) @@ -265,6 +304,10 @@ void InstrProfWriter::writeImpl(ProfOStream &OS) { Header.Version = IndexedInstrProf::ProfVersion::CurrentVersion; if (ProfileKind == PF_IRLevel) Header.Version |= VARIANT_MASK_IR_PROF; + if (ProfileKind == PF_IRLevelWithCS) { + Header.Version |= VARIANT_MASK_IR_PROF; + Header.Version |= VARIANT_MASK_CSIR_PROF; + } Header.Unused = 0; Header.HashType = static_cast<uint64_t>(IndexedInstrProf::HashType); Header.HashOffset = 0; @@ -288,6 +331,14 @@ void InstrProfWriter::writeImpl(ProfOStream &OS) { uint64_t SummaryOffset = OS.tell(); for (unsigned I = 0; I < SummarySize / sizeof(uint64_t); I++) OS.write(0); + uint64_t CSSummaryOffset = 0; + uint64_t CSSummarySize = 0; + if (ProfileKind == PF_IRLevelWithCS) { + CSSummaryOffset = OS.tell(); + CSSummarySize = SummarySize / sizeof(uint64_t); + for (unsigned I = 0; I < CSSummarySize; I++) + OS.write(0); + } // Write the hash table. uint64_t HashTableStart = Generator.Emit(OS.OS, *InfoObj); @@ -301,13 +352,25 @@ void InstrProfWriter::writeImpl(ProfOStream &OS) { setSummary(TheSummary.get(), *PS); InfoObj->SummaryBuilder = nullptr; + // For Context Sensitive summary. + std::unique_ptr<IndexedInstrProf::Summary> TheCSSummary = nullptr; + if (ProfileKind == PF_IRLevelWithCS) { + TheCSSummary = IndexedInstrProf::allocSummary(SummarySize); + std::unique_ptr<ProfileSummary> CSPS = CSISB.getSummary(); + setSummary(TheCSSummary.get(), *CSPS); + } + InfoObj->CSSummaryBuilder = nullptr; + // Now do the final patch: PatchItem PatchItems[] = { // Patch the Header.HashOffset field. {HashTableStartFieldOffset, &HashTableStart, 1}, // Patch the summary data. {SummaryOffset, reinterpret_cast<uint64_t *>(TheSummary.get()), - (int)(SummarySize / sizeof(uint64_t))}}; + (int)(SummarySize / sizeof(uint64_t))}, + {CSSummaryOffset, reinterpret_cast<uint64_t *>(TheCSSummary.get()), + (int)CSSummarySize}}; + OS.patch(PatchItems, sizeof(PatchItems) / sizeof(*PatchItems)); } @@ -328,7 +391,7 @@ std::unique_ptr<MemoryBuffer> InstrProfWriter::writeBuffer() { } static const char *ValueProfKindStr[] = { -#define VALUE_PROF_KIND(Enumerator, Value) #Enumerator, +#define VALUE_PROF_KIND(Enumerator, Value, Descr) #Enumerator, #include "llvm/ProfileData/InstrProfData.inc" }; @@ -376,15 +439,33 @@ void InstrProfWriter::writeRecordInText(StringRef Name, uint64_t Hash, Error InstrProfWriter::writeText(raw_fd_ostream &OS) { if (ProfileKind == PF_IRLevel) OS << "# IR level Instrumentation Flag\n:ir\n"; + else if (ProfileKind == PF_IRLevelWithCS) + OS << "# CSIR level Instrumentation Flag\n:csir\n"; InstrProfSymtab Symtab; - for (const auto &I : FunctionData) - if (shouldEncodeData(I.getValue())) + + using FuncPair = detail::DenseMapPair<uint64_t, InstrProfRecord>; + using RecordType = std::pair<StringRef, FuncPair>; + SmallVector<RecordType, 4> OrderedFuncData; + + for (const auto &I : FunctionData) { + if (shouldEncodeData(I.getValue())) { if (Error E = Symtab.addFuncName(I.getKey())) return E; - - for (const auto &I : FunctionData) - if (shouldEncodeData(I.getValue())) for (const auto &Func : I.getValue()) - writeRecordInText(I.getKey(), Func.first, Func.second, Symtab, OS); + OrderedFuncData.push_back(std::make_pair(I.getKey(), Func)); + } + } + + llvm::sort(OrderedFuncData, [](const RecordType &A, const RecordType &B) { + return std::tie(A.first, A.second.first) < + std::tie(B.first, B.second.first); + }); + + for (const auto &record : OrderedFuncData) { + const StringRef &Name = record.first; + const FuncPair &Func = record.second; + writeRecordInText(Name, Func.first, Func.second, Symtab, OS); + } + return Error::success(); } diff --git a/lib/ProfileData/ProfileSummaryBuilder.cpp b/lib/ProfileData/ProfileSummaryBuilder.cpp index 3a8462fd9b0d..4d5b00935742 100644 --- a/lib/ProfileData/ProfileSummaryBuilder.cpp +++ b/lib/ProfileData/ProfileSummaryBuilder.cpp @@ -1,9 +1,8 @@ //=-- 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. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -45,12 +44,17 @@ void InstrProfSummaryBuilder::addRecord(const InstrProfRecord &R) { // 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(); + const sampleprof::FunctionSamples &FS, bool isCallsiteSample) { + if (!isCallsiteSample) { + NumFunctions++; + if (FS.getHeadSamples() > MaxFunctionCount) + MaxFunctionCount = FS.getHeadSamples(); + } for (const auto &I : FS.getBodySamples()) addCount(I.second.getSamples()); + for (const auto &I : FS.getCallsiteSamples()) + for (const auto &CS : I.second) + addRecord(CS.second, true); } // The argument to this method is a vector of cutoff percentages and the return diff --git a/lib/ProfileData/SampleProf.cpp b/lib/ProfileData/SampleProf.cpp index 1a124415f179..e17865cd15a4 100644 --- a/lib/ProfileData/SampleProf.cpp +++ b/lib/ProfileData/SampleProf.cpp @@ -1,9 +1,8 @@ //=-- SampleProf.cpp - Sample profiling format support --------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/ProfileData/SampleProfReader.cpp b/lib/ProfileData/SampleProfReader.cpp index a68d1e9d3ab0..192b6c711562 100644 --- a/lib/ProfileData/SampleProfReader.cpp +++ b/lib/ProfileData/SampleProfReader.cpp @@ -1,9 +1,8 @@ //===- SampleProfReader.cpp - Read LLVM sample profile data ---------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -594,8 +593,8 @@ std::error_code SampleProfileReaderCompactBinary::readFuncOffsetTable() { void SampleProfileReaderCompactBinary::collectFuncsToUse(const Module &M) { FuncsToUse.clear(); for (auto &F : M) { - StringRef Fname = F.getName().split('.').first; - FuncsToUse.insert(Fname); + StringRef CanonName = FunctionSamples::getCanonicalFnName(F); + FuncsToUse.insert(CanonName); } } diff --git a/lib/ProfileData/SampleProfWriter.cpp b/lib/ProfileData/SampleProfWriter.cpp index b1c669ec31c4..8b876e0aa5d9 100644 --- a/lib/ProfileData/SampleProfWriter.cpp +++ b/lib/ProfileData/SampleProfWriter.cpp @@ -1,9 +1,8 @@ //===- SampleProfWriter.cpp - Write LLVM sample profile data --------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -51,9 +50,8 @@ SampleProfileWriter::write(const StringMap<FunctionSamples> &ProfileMap) { 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) { + llvm::stable_sort( + V, [](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(); |