aboutsummaryrefslogtreecommitdiff
path: root/lib/ProfileData
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-08-20 20:50:12 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-08-20 20:50:12 +0000
commite6d1592492a3a379186bfb02bd0f4eda0669c0d5 (patch)
tree599ab169a01f1c86eda9adc774edaedde2f2db5b /lib/ProfileData
parent1a56a5ead7a2e84bee8240f5f6b033b5f1707154 (diff)
Notes
Diffstat (limited to 'lib/ProfileData')
-rw-r--r--lib/ProfileData/Coverage/CoverageMapping.cpp18
-rw-r--r--lib/ProfileData/Coverage/CoverageMappingReader.cpp235
-rw-r--r--lib/ProfileData/Coverage/CoverageMappingWriter.cpp24
-rw-r--r--lib/ProfileData/GCOV.cpp26
-rw-r--r--lib/ProfileData/InstrProf.cpp293
-rw-r--r--lib/ProfileData/InstrProfReader.cpp47
-rw-r--r--lib/ProfileData/InstrProfWriter.cpp107
-rw-r--r--lib/ProfileData/ProfileSummaryBuilder.cpp20
-rw-r--r--lib/ProfileData/SampleProf.cpp7
-rw-r--r--lib/ProfileData/SampleProfReader.cpp11
-rw-r--r--lib/ProfileData/SampleProfWriter.cpp12
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();