aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/ProfileData/SampleProfWriter.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2023-09-02 21:17:18 +0000
committerDimitry Andric <dim@FreeBSD.org>2023-12-08 17:34:50 +0000
commit06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e (patch)
tree62f873df87c7c675557a179e0c4c83fe9f3087bc /contrib/llvm-project/llvm/lib/ProfileData/SampleProfWriter.cpp
parentcf037972ea8863e2bab7461d77345367d2c1e054 (diff)
parent7fa27ce4a07f19b07799a767fc29416f3b625afb (diff)
Diffstat (limited to 'contrib/llvm-project/llvm/lib/ProfileData/SampleProfWriter.cpp')
-rw-r--r--contrib/llvm-project/llvm/lib/ProfileData/SampleProfWriter.cpp217
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)