diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2023-09-02 21:17:18 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2023-12-08 17:34:50 +0000 |
commit | 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e (patch) | |
tree | 62f873df87c7c675557a179e0c4c83fe9f3087bc /contrib/llvm-project/llvm/lib/ProfileData/SampleProfWriter.cpp | |
parent | cf037972ea8863e2bab7461d77345367d2c1e054 (diff) | |
parent | 7fa27ce4a07f19b07799a767fc29416f3b625afb (diff) |
Diffstat (limited to 'contrib/llvm-project/llvm/lib/ProfileData/SampleProfWriter.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/ProfileData/SampleProfWriter.cpp | 217 |
1 files changed, 127 insertions, 90 deletions
diff --git a/contrib/llvm-project/llvm/lib/ProfileData/SampleProfWriter.cpp b/contrib/llvm-project/llvm/lib/ProfileData/SampleProfWriter.cpp index 093790afe2d6..0873093ad426 100644 --- a/contrib/llvm-project/llvm/lib/ProfileData/SampleProfWriter.cpp +++ b/contrib/llvm-project/llvm/lib/ProfileData/SampleProfWriter.cpp @@ -30,6 +30,7 @@ #include "llvm/Support/MD5.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> +#include <cmath> #include <cstdint> #include <memory> #include <set> @@ -37,9 +38,109 @@ #include <utility> #include <vector> +#define DEBUG_TYPE "llvm-profdata" + using namespace llvm; using namespace sampleprof; +namespace llvm { +namespace support { +namespace endian { +namespace { + +// Adapter class to llvm::support::endian::Writer for pwrite(). +struct SeekableWriter { + raw_pwrite_stream &OS; + endianness Endian; + SeekableWriter(raw_pwrite_stream &OS, endianness Endian) + : OS(OS), Endian(Endian) {} + + template <typename ValueType> + void pwrite(ValueType Val, size_t Offset) { + std::string StringBuf; + raw_string_ostream SStream(StringBuf); + Writer(SStream, Endian).write(Val); + OS.pwrite(StringBuf.data(), StringBuf.size(), Offset); + } +}; + +} // namespace +} // namespace endian +} // namespace support +} // namespace llvm + +DefaultFunctionPruningStrategy::DefaultFunctionPruningStrategy( + SampleProfileMap &ProfileMap, size_t OutputSizeLimit) + : FunctionPruningStrategy(ProfileMap, OutputSizeLimit) { + sortFuncProfiles(ProfileMap, SortedFunctions); +} + +void DefaultFunctionPruningStrategy::Erase(size_t CurrentOutputSize) { + double D = (double)OutputSizeLimit / CurrentOutputSize; + size_t NewSize = (size_t)round(ProfileMap.size() * D * D); + size_t NumToRemove = ProfileMap.size() - NewSize; + if (NumToRemove < 1) + NumToRemove = 1; + + assert(NumToRemove <= SortedFunctions.size()); + llvm::for_each( + llvm::make_range(SortedFunctions.begin() + SortedFunctions.size() - + NumToRemove, + SortedFunctions.end()), + [&](const NameFunctionSamples &E) { ProfileMap.erase(E.first); }); + SortedFunctions.resize(SortedFunctions.size() - NumToRemove); +} + +std::error_code SampleProfileWriter::writeWithSizeLimitInternal( + SampleProfileMap &ProfileMap, size_t OutputSizeLimit, + FunctionPruningStrategy *Strategy) { + if (OutputSizeLimit == 0) + return write(ProfileMap); + + size_t OriginalFunctionCount = ProfileMap.size(); + + std::unique_ptr<raw_ostream> OriginalOutputStream; + OutputStream.swap(OriginalOutputStream); + + size_t IterationCount = 0; + size_t TotalSize; + + SmallVector<char> StringBuffer; + do { + StringBuffer.clear(); + OutputStream.reset(new raw_svector_ostream(StringBuffer)); + if (std::error_code EC = write(ProfileMap)) + return EC; + + TotalSize = StringBuffer.size(); + // On Windows every "\n" is actually written as "\r\n" to disk but not to + // memory buffer, this difference should be added when considering the total + // output size. +#ifdef _WIN32 + if (Format == SPF_Text) + TotalSize += LineCount; +#endif + if (TotalSize <= OutputSizeLimit) + break; + + Strategy->Erase(TotalSize); + IterationCount++; + } while (ProfileMap.size() != 0); + + if (ProfileMap.size() == 0) + return sampleprof_error::too_large; + + OutputStream.swap(OriginalOutputStream); + OutputStream->write(StringBuffer.data(), StringBuffer.size()); + LLVM_DEBUG(dbgs() << "Profile originally has " << OriginalFunctionCount + << " functions, reduced to " << ProfileMap.size() << " in " + << IterationCount << " iterations\n"); + // Silence warning on Release build. + (void)OriginalFunctionCount; + (void)IterationCount; + return sampleprof_error::success; +} + std::error_code SampleProfileWriter::writeFuncProfiles(const SampleProfileMap &ProfileMap) { std::vector<NameFunctionSamples> V; @@ -116,6 +217,12 @@ std::error_code SampleProfileWriterExtBinaryBase::addNewSection( std::error_code SampleProfileWriterExtBinaryBase::write(const SampleProfileMap &ProfileMap) { + // When calling write on a different profile map, existing states should be + // cleared. + NameTable.clear(); + CSNameTable.clear(); + SecHdrTable.clear(); + if (std::error_code EC = writeHeader(ProfileMap)) return EC; @@ -450,15 +557,6 @@ std::error_code SampleProfileWriterExtBinary::writeSections( return EC; } -std::error_code -SampleProfileWriterCompactBinary::write(const SampleProfileMap &ProfileMap) { - if (std::error_code EC = SampleProfileWriter::write(ProfileMap)) - return EC; - if (std::error_code EC = writeFuncOffsetTable()) - return EC; - return sampleprof_error::success; -} - /// Write samples to a text file. /// /// Note: it may be tempting to implement this in terms of @@ -477,6 +575,7 @@ std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) { if (Indent == 0) OS << ":" << S.getHeadSamples(); OS << "\n"; + LineCount++; SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples()); for (const auto &I : SortedSamples.get()) { @@ -493,6 +592,7 @@ std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) { for (const auto &J : Sample.getSortedCallTargets()) OS << " " << J.first << ":" << J.second; OS << "\n"; + LineCount++; } SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples( @@ -515,11 +615,13 @@ std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) { if (FunctionSamples::ProfileIsProbeBased) { OS.indent(Indent + 1); OS << "!CFGChecksum: " << S.getFunctionHash() << "\n"; + LineCount++; } if (S.getContext().getAllAttributes()) { OS.indent(Indent + 1); OS << "!Attributes: " << S.getContext().getAllAttributes() << "\n"; + LineCount++; } return sampleprof_error::success; @@ -601,44 +703,6 @@ std::error_code SampleProfileWriterBinary::writeNameTable() { return sampleprof_error::success; } -std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() { - auto &OS = *OutputStream; - - // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable. - auto &OFS = static_cast<raw_fd_ostream &>(OS); - uint64_t FuncOffsetTableStart = OS.tell(); - if (OFS.seek(TableOffset) == (uint64_t)-1) - return sampleprof_error::ostream_seek_unsupported; - support::endian::Writer Writer(*OutputStream, support::little); - Writer.write(FuncOffsetTableStart); - if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1) - return sampleprof_error::ostream_seek_unsupported; - - // Write out the table size. - encodeULEB128(FuncOffsetTable.size(), OS); - - // Write out FuncOffsetTable. - for (auto Entry : FuncOffsetTable) { - if (std::error_code EC = writeNameIdx(Entry.first)) - return EC; - encodeULEB128(Entry.second, OS); - } - return sampleprof_error::success; -} - -std::error_code SampleProfileWriterCompactBinary::writeNameTable() { - auto &OS = *OutputStream; - std::set<StringRef> V; - stablizeNameTable(NameTable, V); - - // Write out the name table. - encodeULEB128(NameTable.size(), OS); - for (auto N : V) { - encodeULEB128(MD5Hash(N), OS); - } - return sampleprof_error::success; -} - std::error_code SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) { auto &OS = *OutputStream; @@ -650,6 +714,10 @@ SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) { std::error_code SampleProfileWriterBinary::writeHeader(const SampleProfileMap &ProfileMap) { + // When calling write on a different profile map, existing names should be + // cleared. + NameTable.clear(); + writeMagicIdent(Format); computeSummary(ProfileMap); @@ -690,14 +758,6 @@ void SampleProfileWriterExtBinaryBase::allocSecHdrTable() { } std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() { - auto &OFS = static_cast<raw_fd_ostream &>(*OutputStream); - uint64_t Saved = OutputStream->tell(); - - // Set OutputStream to the location saved in SecHdrTableOffset. - if (OFS.seek(SecHdrTableOffset) == (uint64_t)-1) - return sampleprof_error::ostream_seek_unsupported; - support::endian::Writer Writer(*OutputStream, support::little); - assert(SecHdrTable.size() == SectionHdrLayout.size() && "SecHdrTable entries doesn't match SectionHdrLayout"); SmallVector<uint32_t, 16> IndexMap(SecHdrTable.size(), -1); @@ -714,21 +774,23 @@ std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() { // needs to be computed after SecLBRProfile (the order in SecHdrTable), // but it needs to be read before SecLBRProfile (the order in // SectionHdrLayout). So we use IndexMap above to switch the order. + support::endian::SeekableWriter Writer( + static_cast<raw_pwrite_stream &>(*OutputStream), support::little); for (uint32_t LayoutIdx = 0; LayoutIdx < SectionHdrLayout.size(); LayoutIdx++) { assert(IndexMap[LayoutIdx] < SecHdrTable.size() && "Incorrect LayoutIdx in SecHdrTable"); auto Entry = SecHdrTable[IndexMap[LayoutIdx]]; - Writer.write(static_cast<uint64_t>(Entry.Type)); - Writer.write(static_cast<uint64_t>(Entry.Flags)); - Writer.write(static_cast<uint64_t>(Entry.Offset)); - Writer.write(static_cast<uint64_t>(Entry.Size)); + Writer.pwrite(static_cast<uint64_t>(Entry.Type), + SecHdrTableOffset + 4 * LayoutIdx * sizeof(uint64_t)); + Writer.pwrite(static_cast<uint64_t>(Entry.Flags), + SecHdrTableOffset + (4 * LayoutIdx + 1) * sizeof(uint64_t)); + Writer.pwrite(static_cast<uint64_t>(Entry.Offset), + SecHdrTableOffset + (4 * LayoutIdx + 2) * sizeof(uint64_t)); + Writer.pwrite(static_cast<uint64_t>(Entry.Size), + SecHdrTableOffset + (4 * LayoutIdx + 3) * sizeof(uint64_t)); } - // Reset OutputStream. - if (OFS.seek(Saved) == (uint64_t)-1) - return sampleprof_error::ostream_seek_unsupported; - return sampleprof_error::success; } @@ -742,19 +804,6 @@ std::error_code SampleProfileWriterExtBinaryBase::writeHeader( return sampleprof_error::success; } -std::error_code SampleProfileWriterCompactBinary::writeHeader( - const SampleProfileMap &ProfileMap) { - support::endian::Writer Writer(*OutputStream, support::little); - if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap)) - return EC; - - // Reserve a slot for the offset of function offset table. The slot will - // be populated with the offset of FuncOffsetTable later. - TableOffset = OutputStream->tell(); - Writer.write(static_cast<uint64_t>(-2)); - return sampleprof_error::success; -} - std::error_code SampleProfileWriterBinary::writeSummary() { auto &OS = *OutputStream; encodeULEB128(Summary->getTotalCount(), OS); @@ -824,15 +873,6 @@ SampleProfileWriterBinary::writeSample(const FunctionSamples &S) { return writeBody(S); } -std::error_code -SampleProfileWriterCompactBinary::writeSample(const FunctionSamples &S) { - uint64_t Offset = OutputStream->tell(); - StringRef Name = S.getName(); - FuncOffsetTable[Name] = Offset; - encodeULEB128(S.getHeadSamples(), *OutputStream); - return writeBody(S); -} - /// Create a sample profile file writer based on the specified format. /// /// \param Filename The file to create. @@ -844,8 +884,7 @@ ErrorOr<std::unique_ptr<SampleProfileWriter>> SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) { std::error_code EC; std::unique_ptr<raw_ostream> OS; - if (Format == SPF_Binary || Format == SPF_Ext_Binary || - Format == SPF_Compact_Binary) + if (Format == SPF_Binary || Format == SPF_Ext_Binary) OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None)); else OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_TextWithCRLF)); @@ -870,15 +909,13 @@ SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS, // Currently only Text and Extended Binary format are supported for CSSPGO. if ((FunctionSamples::ProfileIsCS || FunctionSamples::ProfileIsProbeBased) && - (Format == SPF_Binary || Format == SPF_Compact_Binary)) + Format == SPF_Binary) return sampleprof_error::unsupported_writing_format; if (Format == SPF_Binary) Writer.reset(new SampleProfileWriterRawBinary(OS)); else if (Format == SPF_Ext_Binary) Writer.reset(new SampleProfileWriterExtBinary(OS)); - else if (Format == SPF_Compact_Binary) - Writer.reset(new SampleProfileWriterCompactBinary(OS)); else if (Format == SPF_Text) Writer.reset(new SampleProfileWriterText(OS)); else if (Format == SPF_GCC) |