10b57cec5SDimitry Andric //===- SampleProfWriter.cpp - Write LLVM sample profile data --------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements the class that writes LLVM sample profiles. It
100b57cec5SDimitry Andric // supports two file formats: text and binary. The textual representation
110b57cec5SDimitry Andric // is useful for debugging and testing purposes. The binary representation
120b57cec5SDimitry Andric // is more compact, resulting in smaller file sizes. However, they can
130b57cec5SDimitry Andric // both be used interchangeably.
140b57cec5SDimitry Andric //
150b57cec5SDimitry Andric // See lib/ProfileData/SampleProfReader.cpp for documentation on each of the
160b57cec5SDimitry Andric // supported formats.
170b57cec5SDimitry Andric //
180b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
190b57cec5SDimitry Andric
200b57cec5SDimitry Andric #include "llvm/ProfileData/SampleProfWriter.h"
210b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
220b57cec5SDimitry Andric #include "llvm/ProfileData/ProfileCommon.h"
230b57cec5SDimitry Andric #include "llvm/ProfileData/SampleProf.h"
248bcb0991SDimitry Andric #include "llvm/Support/Compression.h"
250b57cec5SDimitry Andric #include "llvm/Support/Endian.h"
260b57cec5SDimitry Andric #include "llvm/Support/EndianStream.h"
270b57cec5SDimitry Andric #include "llvm/Support/ErrorOr.h"
280b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
290b57cec5SDimitry Andric #include "llvm/Support/LEB128.h"
300b57cec5SDimitry Andric #include "llvm/Support/MD5.h"
310b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
320b57cec5SDimitry Andric #include <algorithm>
33fe013be4SDimitry Andric #include <cmath>
340b57cec5SDimitry Andric #include <cstdint>
350b57cec5SDimitry Andric #include <memory>
360b57cec5SDimitry Andric #include <set>
370b57cec5SDimitry Andric #include <system_error>
380b57cec5SDimitry Andric #include <utility>
390b57cec5SDimitry Andric #include <vector>
400b57cec5SDimitry Andric
41fe013be4SDimitry Andric #define DEBUG_TYPE "llvm-profdata"
42fe013be4SDimitry Andric
430b57cec5SDimitry Andric using namespace llvm;
440b57cec5SDimitry Andric using namespace sampleprof;
450b57cec5SDimitry Andric
46fe013be4SDimitry Andric namespace llvm {
47fe013be4SDimitry Andric namespace support {
48fe013be4SDimitry Andric namespace endian {
49fe013be4SDimitry Andric namespace {
50fe013be4SDimitry Andric
51fe013be4SDimitry Andric // Adapter class to llvm::support::endian::Writer for pwrite().
52fe013be4SDimitry Andric struct SeekableWriter {
53fe013be4SDimitry Andric raw_pwrite_stream &OS;
54fe013be4SDimitry Andric endianness Endian;
SeekableWriterllvm::support::endian::__anon6ffb05360111::SeekableWriter55fe013be4SDimitry Andric SeekableWriter(raw_pwrite_stream &OS, endianness Endian)
56fe013be4SDimitry Andric : OS(OS), Endian(Endian) {}
57fe013be4SDimitry Andric
58fe013be4SDimitry Andric template <typename ValueType>
pwritellvm::support::endian::__anon6ffb05360111::SeekableWriter59fe013be4SDimitry Andric void pwrite(ValueType Val, size_t Offset) {
60fe013be4SDimitry Andric std::string StringBuf;
61fe013be4SDimitry Andric raw_string_ostream SStream(StringBuf);
62fe013be4SDimitry Andric Writer(SStream, Endian).write(Val);
63fe013be4SDimitry Andric OS.pwrite(StringBuf.data(), StringBuf.size(), Offset);
64fe013be4SDimitry Andric }
65fe013be4SDimitry Andric };
66fe013be4SDimitry Andric
67fe013be4SDimitry Andric } // namespace
68fe013be4SDimitry Andric } // namespace endian
69fe013be4SDimitry Andric } // namespace support
70fe013be4SDimitry Andric } // namespace llvm
71fe013be4SDimitry Andric
DefaultFunctionPruningStrategy(SampleProfileMap & ProfileMap,size_t OutputSizeLimit)72fe013be4SDimitry Andric DefaultFunctionPruningStrategy::DefaultFunctionPruningStrategy(
73fe013be4SDimitry Andric SampleProfileMap &ProfileMap, size_t OutputSizeLimit)
74fe013be4SDimitry Andric : FunctionPruningStrategy(ProfileMap, OutputSizeLimit) {
75fe013be4SDimitry Andric sortFuncProfiles(ProfileMap, SortedFunctions);
76fe013be4SDimitry Andric }
77fe013be4SDimitry Andric
Erase(size_t CurrentOutputSize)78fe013be4SDimitry Andric void DefaultFunctionPruningStrategy::Erase(size_t CurrentOutputSize) {
79fe013be4SDimitry Andric double D = (double)OutputSizeLimit / CurrentOutputSize;
80fe013be4SDimitry Andric size_t NewSize = (size_t)round(ProfileMap.size() * D * D);
81fe013be4SDimitry Andric size_t NumToRemove = ProfileMap.size() - NewSize;
82fe013be4SDimitry Andric if (NumToRemove < 1)
83fe013be4SDimitry Andric NumToRemove = 1;
84fe013be4SDimitry Andric
85fe013be4SDimitry Andric assert(NumToRemove <= SortedFunctions.size());
86*c9157d92SDimitry Andric for (const NameFunctionSamples &E :
87*c9157d92SDimitry Andric llvm::drop_begin(SortedFunctions, SortedFunctions.size() - NumToRemove))
88*c9157d92SDimitry Andric ProfileMap.erase(E.first);
89fe013be4SDimitry Andric SortedFunctions.resize(SortedFunctions.size() - NumToRemove);
90fe013be4SDimitry Andric }
91fe013be4SDimitry Andric
writeWithSizeLimitInternal(SampleProfileMap & ProfileMap,size_t OutputSizeLimit,FunctionPruningStrategy * Strategy)92fe013be4SDimitry Andric std::error_code SampleProfileWriter::writeWithSizeLimitInternal(
93fe013be4SDimitry Andric SampleProfileMap &ProfileMap, size_t OutputSizeLimit,
94fe013be4SDimitry Andric FunctionPruningStrategy *Strategy) {
95fe013be4SDimitry Andric if (OutputSizeLimit == 0)
96fe013be4SDimitry Andric return write(ProfileMap);
97fe013be4SDimitry Andric
98fe013be4SDimitry Andric size_t OriginalFunctionCount = ProfileMap.size();
99fe013be4SDimitry Andric
100fe013be4SDimitry Andric std::unique_ptr<raw_ostream> OriginalOutputStream;
101fe013be4SDimitry Andric OutputStream.swap(OriginalOutputStream);
102fe013be4SDimitry Andric
103fe013be4SDimitry Andric size_t IterationCount = 0;
104fe013be4SDimitry Andric size_t TotalSize;
105fe013be4SDimitry Andric
106fe013be4SDimitry Andric SmallVector<char> StringBuffer;
107fe013be4SDimitry Andric do {
108fe013be4SDimitry Andric StringBuffer.clear();
109fe013be4SDimitry Andric OutputStream.reset(new raw_svector_ostream(StringBuffer));
110fe013be4SDimitry Andric if (std::error_code EC = write(ProfileMap))
111fe013be4SDimitry Andric return EC;
112fe013be4SDimitry Andric
113fe013be4SDimitry Andric TotalSize = StringBuffer.size();
114fe013be4SDimitry Andric // On Windows every "\n" is actually written as "\r\n" to disk but not to
115fe013be4SDimitry Andric // memory buffer, this difference should be added when considering the total
116fe013be4SDimitry Andric // output size.
117fe013be4SDimitry Andric #ifdef _WIN32
118fe013be4SDimitry Andric if (Format == SPF_Text)
119fe013be4SDimitry Andric TotalSize += LineCount;
120fe013be4SDimitry Andric #endif
121fe013be4SDimitry Andric if (TotalSize <= OutputSizeLimit)
122fe013be4SDimitry Andric break;
123fe013be4SDimitry Andric
124fe013be4SDimitry Andric Strategy->Erase(TotalSize);
125fe013be4SDimitry Andric IterationCount++;
126fe013be4SDimitry Andric } while (ProfileMap.size() != 0);
127fe013be4SDimitry Andric
128fe013be4SDimitry Andric if (ProfileMap.size() == 0)
129fe013be4SDimitry Andric return sampleprof_error::too_large;
130fe013be4SDimitry Andric
131fe013be4SDimitry Andric OutputStream.swap(OriginalOutputStream);
132fe013be4SDimitry Andric OutputStream->write(StringBuffer.data(), StringBuffer.size());
133fe013be4SDimitry Andric LLVM_DEBUG(dbgs() << "Profile originally has " << OriginalFunctionCount
134fe013be4SDimitry Andric << " functions, reduced to " << ProfileMap.size() << " in "
135fe013be4SDimitry Andric << IterationCount << " iterations\n");
136fe013be4SDimitry Andric // Silence warning on Release build.
137fe013be4SDimitry Andric (void)OriginalFunctionCount;
138fe013be4SDimitry Andric (void)IterationCount;
139fe013be4SDimitry Andric return sampleprof_error::success;
140fe013be4SDimitry Andric }
141fe013be4SDimitry Andric
142349cc55cSDimitry Andric std::error_code
writeFuncProfiles(const SampleProfileMap & ProfileMap)143349cc55cSDimitry Andric SampleProfileWriter::writeFuncProfiles(const SampleProfileMap &ProfileMap) {
1440b57cec5SDimitry Andric std::vector<NameFunctionSamples> V;
145349cc55cSDimitry Andric sortFuncProfiles(ProfileMap, V);
1460b57cec5SDimitry Andric for (const auto &I : V) {
1478bcb0991SDimitry Andric if (std::error_code EC = writeSample(*I.second))
1480b57cec5SDimitry Andric return EC;
1490b57cec5SDimitry Andric }
1500b57cec5SDimitry Andric return sampleprof_error::success;
1510b57cec5SDimitry Andric }
1520b57cec5SDimitry Andric
write(const SampleProfileMap & ProfileMap)153349cc55cSDimitry Andric std::error_code SampleProfileWriter::write(const SampleProfileMap &ProfileMap) {
1548bcb0991SDimitry Andric if (std::error_code EC = writeHeader(ProfileMap))
1558bcb0991SDimitry Andric return EC;
1568bcb0991SDimitry Andric
1578bcb0991SDimitry Andric if (std::error_code EC = writeFuncProfiles(ProfileMap))
1588bcb0991SDimitry Andric return EC;
1598bcb0991SDimitry Andric
1608bcb0991SDimitry Andric return sampleprof_error::success;
1618bcb0991SDimitry Andric }
1628bcb0991SDimitry Andric
1638bcb0991SDimitry Andric /// Return the current position and prepare to use it as the start
164e8d8bef9SDimitry Andric /// position of a section given the section type \p Type and its position
165e8d8bef9SDimitry Andric /// \p LayoutIdx in SectionHdrLayout.
166e8d8bef9SDimitry Andric uint64_t
markSectionStart(SecType Type,uint32_t LayoutIdx)167e8d8bef9SDimitry Andric SampleProfileWriterExtBinaryBase::markSectionStart(SecType Type,
168e8d8bef9SDimitry Andric uint32_t LayoutIdx) {
1698bcb0991SDimitry Andric uint64_t SectionStart = OutputStream->tell();
170e8d8bef9SDimitry Andric assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range");
171e8d8bef9SDimitry Andric const auto &Entry = SectionHdrLayout[LayoutIdx];
172e8d8bef9SDimitry Andric assert(Entry.Type == Type && "Unexpected section type");
1738bcb0991SDimitry Andric // Use LocalBuf as a temporary output for writting data.
1745ffd83dbSDimitry Andric if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress))
1758bcb0991SDimitry Andric LocalBufStream.swap(OutputStream);
1768bcb0991SDimitry Andric return SectionStart;
1778bcb0991SDimitry Andric }
1788bcb0991SDimitry Andric
compressAndOutput()1798bcb0991SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::compressAndOutput() {
180753f127fSDimitry Andric if (!llvm::compression::zlib::isAvailable())
1818bcb0991SDimitry Andric return sampleprof_error::zlib_unavailable;
1828bcb0991SDimitry Andric std::string &UncompressedStrings =
1838bcb0991SDimitry Andric static_cast<raw_string_ostream *>(LocalBufStream.get())->str();
1848bcb0991SDimitry Andric if (UncompressedStrings.size() == 0)
1858bcb0991SDimitry Andric return sampleprof_error::success;
1868bcb0991SDimitry Andric auto &OS = *OutputStream;
187753f127fSDimitry Andric SmallVector<uint8_t, 128> CompressedStrings;
188753f127fSDimitry Andric compression::zlib::compress(arrayRefFromStringRef(UncompressedStrings),
189753f127fSDimitry Andric CompressedStrings,
190753f127fSDimitry Andric compression::zlib::BestSizeCompression);
1918bcb0991SDimitry Andric encodeULEB128(UncompressedStrings.size(), OS);
1928bcb0991SDimitry Andric encodeULEB128(CompressedStrings.size(), OS);
193753f127fSDimitry Andric OS << toStringRef(CompressedStrings);
1948bcb0991SDimitry Andric UncompressedStrings.clear();
1958bcb0991SDimitry Andric return sampleprof_error::success;
1968bcb0991SDimitry Andric }
1978bcb0991SDimitry Andric
198e8d8bef9SDimitry Andric /// Add a new section into section header table given the section type
199e8d8bef9SDimitry Andric /// \p Type, its position \p LayoutIdx in SectionHdrLayout and the
200e8d8bef9SDimitry Andric /// location \p SectionStart where the section should be written to.
addNewSection(SecType Type,uint32_t LayoutIdx,uint64_t SectionStart)201e8d8bef9SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::addNewSection(
202e8d8bef9SDimitry Andric SecType Type, uint32_t LayoutIdx, uint64_t SectionStart) {
203e8d8bef9SDimitry Andric assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range");
204e8d8bef9SDimitry Andric const auto &Entry = SectionHdrLayout[LayoutIdx];
205e8d8bef9SDimitry Andric assert(Entry.Type == Type && "Unexpected section type");
2065ffd83dbSDimitry Andric if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress)) {
2078bcb0991SDimitry Andric LocalBufStream.swap(OutputStream);
2088bcb0991SDimitry Andric if (std::error_code EC = compressAndOutput())
2098bcb0991SDimitry Andric return EC;
2108bcb0991SDimitry Andric }
2118bcb0991SDimitry Andric SecHdrTable.push_back({Type, Entry.Flags, SectionStart - FileStart,
212e8d8bef9SDimitry Andric OutputStream->tell() - SectionStart, LayoutIdx});
2138bcb0991SDimitry Andric return sampleprof_error::success;
2148bcb0991SDimitry Andric }
2158bcb0991SDimitry Andric
216349cc55cSDimitry Andric std::error_code
write(const SampleProfileMap & ProfileMap)217349cc55cSDimitry Andric SampleProfileWriterExtBinaryBase::write(const SampleProfileMap &ProfileMap) {
218fe013be4SDimitry Andric // When calling write on a different profile map, existing states should be
219fe013be4SDimitry Andric // cleared.
220fe013be4SDimitry Andric NameTable.clear();
221fe013be4SDimitry Andric CSNameTable.clear();
222fe013be4SDimitry Andric SecHdrTable.clear();
223fe013be4SDimitry Andric
2248bcb0991SDimitry Andric if (std::error_code EC = writeHeader(ProfileMap))
2258bcb0991SDimitry Andric return EC;
2268bcb0991SDimitry Andric
2278bcb0991SDimitry Andric std::string LocalBuf;
2288bcb0991SDimitry Andric LocalBufStream = std::make_unique<raw_string_ostream>(LocalBuf);
2298bcb0991SDimitry Andric if (std::error_code EC = writeSections(ProfileMap))
2308bcb0991SDimitry Andric return EC;
2318bcb0991SDimitry Andric
2328bcb0991SDimitry Andric if (std::error_code EC = writeSecHdrTable())
2338bcb0991SDimitry Andric return EC;
2348bcb0991SDimitry Andric
2358bcb0991SDimitry Andric return sampleprof_error::success;
2368bcb0991SDimitry Andric }
2378bcb0991SDimitry Andric
writeContextIdx(const SampleContext & Context)238349cc55cSDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeContextIdx(
239349cc55cSDimitry Andric const SampleContext &Context) {
240349cc55cSDimitry Andric if (Context.hasContext())
241349cc55cSDimitry Andric return writeCSNameIdx(Context);
242349cc55cSDimitry Andric else
243*c9157d92SDimitry Andric return SampleProfileWriterBinary::writeNameIdx(Context.getFunction());
244349cc55cSDimitry Andric }
245349cc55cSDimitry Andric
246349cc55cSDimitry Andric std::error_code
writeCSNameIdx(const SampleContext & Context)247349cc55cSDimitry Andric SampleProfileWriterExtBinaryBase::writeCSNameIdx(const SampleContext &Context) {
248349cc55cSDimitry Andric const auto &Ret = CSNameTable.find(Context);
249349cc55cSDimitry Andric if (Ret == CSNameTable.end())
250349cc55cSDimitry Andric return sampleprof_error::truncated_name_table;
251349cc55cSDimitry Andric encodeULEB128(Ret->second, *OutputStream);
252349cc55cSDimitry Andric return sampleprof_error::success;
253349cc55cSDimitry Andric }
254349cc55cSDimitry Andric
2558bcb0991SDimitry Andric std::error_code
writeSample(const FunctionSamples & S)256e8d8bef9SDimitry Andric SampleProfileWriterExtBinaryBase::writeSample(const FunctionSamples &S) {
2578bcb0991SDimitry Andric uint64_t Offset = OutputStream->tell();
258349cc55cSDimitry Andric auto &Context = S.getContext();
259349cc55cSDimitry Andric FuncOffsetTable[Context] = Offset - SecLBRProfileStart;
2608bcb0991SDimitry Andric encodeULEB128(S.getHeadSamples(), *OutputStream);
2618bcb0991SDimitry Andric return writeBody(S);
2628bcb0991SDimitry Andric }
2638bcb0991SDimitry Andric
writeFuncOffsetTable()264e8d8bef9SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeFuncOffsetTable() {
2658bcb0991SDimitry Andric auto &OS = *OutputStream;
2668bcb0991SDimitry Andric
2678bcb0991SDimitry Andric // Write out the table size.
2688bcb0991SDimitry Andric encodeULEB128(FuncOffsetTable.size(), OS);
2698bcb0991SDimitry Andric
2708bcb0991SDimitry Andric // Write out FuncOffsetTable.
271349cc55cSDimitry Andric auto WriteItem = [&](const SampleContext &Context, uint64_t Offset) {
272349cc55cSDimitry Andric if (std::error_code EC = writeContextIdx(Context))
273fe6060f1SDimitry Andric return EC;
274349cc55cSDimitry Andric encodeULEB128(Offset, OS);
275349cc55cSDimitry Andric return (std::error_code)sampleprof_error::success;
276349cc55cSDimitry Andric };
277349cc55cSDimitry Andric
27881ad6265SDimitry Andric if (FunctionSamples::ProfileIsCS) {
279349cc55cSDimitry Andric // Sort the contexts before writing them out. This is to help fast load all
280349cc55cSDimitry Andric // context profiles for a function as well as their callee contexts which
281349cc55cSDimitry Andric // can help profile-guided importing for ThinLTO.
282349cc55cSDimitry Andric std::map<SampleContext, uint64_t> OrderedFuncOffsetTable(
283349cc55cSDimitry Andric FuncOffsetTable.begin(), FuncOffsetTable.end());
284349cc55cSDimitry Andric for (const auto &Entry : OrderedFuncOffsetTable) {
285349cc55cSDimitry Andric if (std::error_code EC = WriteItem(Entry.first, Entry.second))
286349cc55cSDimitry Andric return EC;
2878bcb0991SDimitry Andric }
288349cc55cSDimitry Andric addSectionFlag(SecFuncOffsetTable, SecFuncOffsetFlags::SecFlagOrdered);
289349cc55cSDimitry Andric } else {
290349cc55cSDimitry Andric for (const auto &Entry : FuncOffsetTable) {
291349cc55cSDimitry Andric if (std::error_code EC = WriteItem(Entry.first, Entry.second))
292349cc55cSDimitry Andric return EC;
293349cc55cSDimitry Andric }
294349cc55cSDimitry Andric }
295349cc55cSDimitry Andric
296e8d8bef9SDimitry Andric FuncOffsetTable.clear();
2978bcb0991SDimitry Andric return sampleprof_error::success;
2988bcb0991SDimitry Andric }
2998bcb0991SDimitry Andric
writeFuncMetadata(const FunctionSamples & FunctionProfile)300e8d8bef9SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeFuncMetadata(
3010eae32dcSDimitry Andric const FunctionSamples &FunctionProfile) {
302e8d8bef9SDimitry Andric auto &OS = *OutputStream;
3030eae32dcSDimitry Andric if (std::error_code EC = writeContextIdx(FunctionProfile.getContext()))
304fe6060f1SDimitry Andric return EC;
3050eae32dcSDimitry Andric
306fe6060f1SDimitry Andric if (FunctionSamples::ProfileIsProbeBased)
3070eae32dcSDimitry Andric encodeULEB128(FunctionProfile.getFunctionHash(), OS);
30881ad6265SDimitry Andric if (FunctionSamples::ProfileIsCS || FunctionSamples::ProfileIsPreInlined) {
3090eae32dcSDimitry Andric encodeULEB128(FunctionProfile.getContext().getAllAttributes(), OS);
3100eae32dcSDimitry Andric }
3110eae32dcSDimitry Andric
31281ad6265SDimitry Andric if (!FunctionSamples::ProfileIsCS) {
3130eae32dcSDimitry Andric // Recursively emit attributes for all callee samples.
3140eae32dcSDimitry Andric uint64_t NumCallsites = 0;
3150eae32dcSDimitry Andric for (const auto &J : FunctionProfile.getCallsiteSamples())
3160eae32dcSDimitry Andric NumCallsites += J.second.size();
3170eae32dcSDimitry Andric encodeULEB128(NumCallsites, OS);
3180eae32dcSDimitry Andric for (const auto &J : FunctionProfile.getCallsiteSamples()) {
3190eae32dcSDimitry Andric for (const auto &FS : J.second) {
3200eae32dcSDimitry Andric LineLocation Loc = J.first;
3210eae32dcSDimitry Andric encodeULEB128(Loc.LineOffset, OS);
3220eae32dcSDimitry Andric encodeULEB128(Loc.Discriminator, OS);
3230eae32dcSDimitry Andric if (std::error_code EC = writeFuncMetadata(FS.second))
3240eae32dcSDimitry Andric return EC;
3250eae32dcSDimitry Andric }
3260eae32dcSDimitry Andric }
3270eae32dcSDimitry Andric }
3280eae32dcSDimitry Andric
3290eae32dcSDimitry Andric return sampleprof_error::success;
3300eae32dcSDimitry Andric }
3310eae32dcSDimitry Andric
writeFuncMetadata(const SampleProfileMap & Profiles)3320eae32dcSDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeFuncMetadata(
3330eae32dcSDimitry Andric const SampleProfileMap &Profiles) {
33481ad6265SDimitry Andric if (!FunctionSamples::ProfileIsProbeBased && !FunctionSamples::ProfileIsCS &&
33581ad6265SDimitry Andric !FunctionSamples::ProfileIsPreInlined)
3360eae32dcSDimitry Andric return sampleprof_error::success;
3370eae32dcSDimitry Andric for (const auto &Entry : Profiles) {
3380eae32dcSDimitry Andric if (std::error_code EC = writeFuncMetadata(Entry.second))
3390eae32dcSDimitry Andric return EC;
340e8d8bef9SDimitry Andric }
341e8d8bef9SDimitry Andric return sampleprof_error::success;
342e8d8bef9SDimitry Andric }
343e8d8bef9SDimitry Andric
writeNameTable()344e8d8bef9SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeNameTable() {
3455ffd83dbSDimitry Andric if (!UseMD5)
3465ffd83dbSDimitry Andric return SampleProfileWriterBinary::writeNameTable();
3475ffd83dbSDimitry Andric
3485ffd83dbSDimitry Andric auto &OS = *OutputStream;
349*c9157d92SDimitry Andric std::set<FunctionId> V;
350349cc55cSDimitry Andric stablizeNameTable(NameTable, V);
3515ffd83dbSDimitry Andric
352e8d8bef9SDimitry Andric // Write out the MD5 name table. We wrote unencoded MD5 so reader can
353e8d8bef9SDimitry Andric // retrieve the name using the name index without having to read the
354e8d8bef9SDimitry Andric // whole name table.
3555ffd83dbSDimitry Andric encodeULEB128(NameTable.size(), OS);
356*c9157d92SDimitry Andric support::endian::Writer Writer(OS, llvm::endianness::little);
357e8d8bef9SDimitry Andric for (auto N : V)
358*c9157d92SDimitry Andric Writer.write(N.getHashCode());
359e8d8bef9SDimitry Andric return sampleprof_error::success;
3605ffd83dbSDimitry Andric }
361e8d8bef9SDimitry Andric
writeNameTableSection(const SampleProfileMap & ProfileMap)362e8d8bef9SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeNameTableSection(
363349cc55cSDimitry Andric const SampleProfileMap &ProfileMap) {
364e8d8bef9SDimitry Andric for (const auto &I : ProfileMap) {
365349cc55cSDimitry Andric addContext(I.second.getContext());
366e8d8bef9SDimitry Andric addNames(I.second);
367e8d8bef9SDimitry Andric }
368fe6060f1SDimitry Andric
369fe6060f1SDimitry Andric // If NameTable contains ".__uniq." suffix, set SecFlagUniqSuffix flag
370fe6060f1SDimitry Andric // so compiler won't strip the suffix during profile matching after
371fe6060f1SDimitry Andric // seeing the flag in the profile.
372*c9157d92SDimitry Andric // Original names are unavailable if using MD5, so this option has no use.
373*c9157d92SDimitry Andric if (!UseMD5) {
374fe6060f1SDimitry Andric for (const auto &I : NameTable) {
375*c9157d92SDimitry Andric if (I.first.stringRef().contains(FunctionSamples::UniqSuffix)) {
376fe6060f1SDimitry Andric addSectionFlag(SecNameTable, SecNameTableFlags::SecFlagUniqSuffix);
377fe6060f1SDimitry Andric break;
378fe6060f1SDimitry Andric }
379fe6060f1SDimitry Andric }
380*c9157d92SDimitry Andric }
381fe6060f1SDimitry Andric
382e8d8bef9SDimitry Andric if (auto EC = writeNameTable())
383e8d8bef9SDimitry Andric return EC;
384e8d8bef9SDimitry Andric return sampleprof_error::success;
385e8d8bef9SDimitry Andric }
386e8d8bef9SDimitry Andric
writeCSNameTableSection()387349cc55cSDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeCSNameTableSection() {
388349cc55cSDimitry Andric // Sort the names to make CSNameTable deterministic.
389349cc55cSDimitry Andric std::set<SampleContext> OrderedContexts;
390349cc55cSDimitry Andric for (const auto &I : CSNameTable)
391349cc55cSDimitry Andric OrderedContexts.insert(I.first);
392349cc55cSDimitry Andric assert(OrderedContexts.size() == CSNameTable.size() &&
393349cc55cSDimitry Andric "Unmatched ordered and unordered contexts");
394349cc55cSDimitry Andric uint64_t I = 0;
395349cc55cSDimitry Andric for (auto &Context : OrderedContexts)
396349cc55cSDimitry Andric CSNameTable[Context] = I++;
397349cc55cSDimitry Andric
398349cc55cSDimitry Andric auto &OS = *OutputStream;
399349cc55cSDimitry Andric encodeULEB128(OrderedContexts.size(), OS);
400*c9157d92SDimitry Andric support::endian::Writer Writer(OS, llvm::endianness::little);
401349cc55cSDimitry Andric for (auto Context : OrderedContexts) {
402349cc55cSDimitry Andric auto Frames = Context.getContextFrames();
403349cc55cSDimitry Andric encodeULEB128(Frames.size(), OS);
404349cc55cSDimitry Andric for (auto &Callsite : Frames) {
405*c9157d92SDimitry Andric if (std::error_code EC = writeNameIdx(Callsite.Func))
406349cc55cSDimitry Andric return EC;
407349cc55cSDimitry Andric encodeULEB128(Callsite.Location.LineOffset, OS);
408349cc55cSDimitry Andric encodeULEB128(Callsite.Location.Discriminator, OS);
409349cc55cSDimitry Andric }
410349cc55cSDimitry Andric }
411349cc55cSDimitry Andric
412349cc55cSDimitry Andric return sampleprof_error::success;
413349cc55cSDimitry Andric }
414349cc55cSDimitry Andric
415e8d8bef9SDimitry Andric std::error_code
writeProfileSymbolListSection()416e8d8bef9SDimitry Andric SampleProfileWriterExtBinaryBase::writeProfileSymbolListSection() {
417e8d8bef9SDimitry Andric if (ProfSymList && ProfSymList->size() > 0)
418e8d8bef9SDimitry Andric if (std::error_code EC = ProfSymList->write(*OutputStream))
419e8d8bef9SDimitry Andric return EC;
420e8d8bef9SDimitry Andric
421e8d8bef9SDimitry Andric return sampleprof_error::success;
422e8d8bef9SDimitry Andric }
423e8d8bef9SDimitry Andric
writeOneSection(SecType Type,uint32_t LayoutIdx,const SampleProfileMap & ProfileMap)424e8d8bef9SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeOneSection(
425349cc55cSDimitry Andric SecType Type, uint32_t LayoutIdx, const SampleProfileMap &ProfileMap) {
426e8d8bef9SDimitry Andric // The setting of SecFlagCompress should happen before markSectionStart.
427e8d8bef9SDimitry Andric if (Type == SecProfileSymbolList && ProfSymList && ProfSymList->toCompress())
428e8d8bef9SDimitry Andric setToCompressSection(SecProfileSymbolList);
429e8d8bef9SDimitry Andric if (Type == SecFuncMetadata && FunctionSamples::ProfileIsProbeBased)
430e8d8bef9SDimitry Andric addSectionFlag(SecFuncMetadata, SecFuncMetadataFlags::SecFlagIsProbeBased);
4310eae32dcSDimitry Andric if (Type == SecFuncMetadata &&
43281ad6265SDimitry Andric (FunctionSamples::ProfileIsCS || FunctionSamples::ProfileIsPreInlined))
433fe6060f1SDimitry Andric addSectionFlag(SecFuncMetadata, SecFuncMetadataFlags::SecFlagHasAttribute);
43481ad6265SDimitry Andric if (Type == SecProfSummary && FunctionSamples::ProfileIsCS)
4350eae32dcSDimitry Andric addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagFullContext);
43681ad6265SDimitry Andric if (Type == SecProfSummary && FunctionSamples::ProfileIsPreInlined)
43781ad6265SDimitry Andric addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagIsPreInlined);
438fe6060f1SDimitry Andric if (Type == SecProfSummary && FunctionSamples::ProfileIsFS)
439fe6060f1SDimitry Andric addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagFSDiscriminator);
440e8d8bef9SDimitry Andric
441e8d8bef9SDimitry Andric uint64_t SectionStart = markSectionStart(Type, LayoutIdx);
442e8d8bef9SDimitry Andric switch (Type) {
443e8d8bef9SDimitry Andric case SecProfSummary:
444e8d8bef9SDimitry Andric computeSummary(ProfileMap);
445e8d8bef9SDimitry Andric if (auto EC = writeSummary())
446e8d8bef9SDimitry Andric return EC;
447e8d8bef9SDimitry Andric break;
448e8d8bef9SDimitry Andric case SecNameTable:
449e8d8bef9SDimitry Andric if (auto EC = writeNameTableSection(ProfileMap))
450e8d8bef9SDimitry Andric return EC;
451e8d8bef9SDimitry Andric break;
452349cc55cSDimitry Andric case SecCSNameTable:
453349cc55cSDimitry Andric if (auto EC = writeCSNameTableSection())
454349cc55cSDimitry Andric return EC;
455349cc55cSDimitry Andric break;
456e8d8bef9SDimitry Andric case SecLBRProfile:
457e8d8bef9SDimitry Andric SecLBRProfileStart = OutputStream->tell();
458e8d8bef9SDimitry Andric if (std::error_code EC = writeFuncProfiles(ProfileMap))
459e8d8bef9SDimitry Andric return EC;
460e8d8bef9SDimitry Andric break;
461e8d8bef9SDimitry Andric case SecFuncOffsetTable:
462e8d8bef9SDimitry Andric if (auto EC = writeFuncOffsetTable())
463e8d8bef9SDimitry Andric return EC;
464e8d8bef9SDimitry Andric break;
465e8d8bef9SDimitry Andric case SecFuncMetadata:
466e8d8bef9SDimitry Andric if (std::error_code EC = writeFuncMetadata(ProfileMap))
467e8d8bef9SDimitry Andric return EC;
468e8d8bef9SDimitry Andric break;
469e8d8bef9SDimitry Andric case SecProfileSymbolList:
470e8d8bef9SDimitry Andric if (auto EC = writeProfileSymbolListSection())
471e8d8bef9SDimitry Andric return EC;
472e8d8bef9SDimitry Andric break;
473e8d8bef9SDimitry Andric default:
474e8d8bef9SDimitry Andric if (auto EC = writeCustomSection(Type))
475e8d8bef9SDimitry Andric return EC;
476e8d8bef9SDimitry Andric break;
477e8d8bef9SDimitry Andric }
478e8d8bef9SDimitry Andric if (std::error_code EC = addNewSection(Type, LayoutIdx, SectionStart))
479e8d8bef9SDimitry Andric return EC;
480e8d8bef9SDimitry Andric return sampleprof_error::success;
481e8d8bef9SDimitry Andric }
482e8d8bef9SDimitry Andric
writeDefaultLayout(const SampleProfileMap & ProfileMap)483e8d8bef9SDimitry Andric std::error_code SampleProfileWriterExtBinary::writeDefaultLayout(
484349cc55cSDimitry Andric const SampleProfileMap &ProfileMap) {
485e8d8bef9SDimitry Andric // The const indices passed to writeOneSection below are specifying the
486e8d8bef9SDimitry Andric // positions of the sections in SectionHdrLayout. Look at
487e8d8bef9SDimitry Andric // initSectionHdrLayout to find out where each section is located in
488e8d8bef9SDimitry Andric // SectionHdrLayout.
489e8d8bef9SDimitry Andric if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap))
490e8d8bef9SDimitry Andric return EC;
491e8d8bef9SDimitry Andric if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap))
492e8d8bef9SDimitry Andric return EC;
493349cc55cSDimitry Andric if (auto EC = writeOneSection(SecCSNameTable, 2, ProfileMap))
494e8d8bef9SDimitry Andric return EC;
495349cc55cSDimitry Andric if (auto EC = writeOneSection(SecLBRProfile, 4, ProfileMap))
496e8d8bef9SDimitry Andric return EC;
497349cc55cSDimitry Andric if (auto EC = writeOneSection(SecProfileSymbolList, 5, ProfileMap))
498e8d8bef9SDimitry Andric return EC;
499349cc55cSDimitry Andric if (auto EC = writeOneSection(SecFuncOffsetTable, 3, ProfileMap))
500349cc55cSDimitry Andric return EC;
501349cc55cSDimitry Andric if (auto EC = writeOneSection(SecFuncMetadata, 6, ProfileMap))
502e8d8bef9SDimitry Andric return EC;
503e8d8bef9SDimitry Andric return sampleprof_error::success;
504e8d8bef9SDimitry Andric }
505e8d8bef9SDimitry Andric
splitProfileMapToTwo(const SampleProfileMap & ProfileMap,SampleProfileMap & ContextProfileMap,SampleProfileMap & NoContextProfileMap)506349cc55cSDimitry Andric static void splitProfileMapToTwo(const SampleProfileMap &ProfileMap,
507349cc55cSDimitry Andric SampleProfileMap &ContextProfileMap,
508349cc55cSDimitry Andric SampleProfileMap &NoContextProfileMap) {
509e8d8bef9SDimitry Andric for (const auto &I : ProfileMap) {
510e8d8bef9SDimitry Andric if (I.second.getCallsiteSamples().size())
511349cc55cSDimitry Andric ContextProfileMap.insert({I.first, I.second});
512e8d8bef9SDimitry Andric else
513349cc55cSDimitry Andric NoContextProfileMap.insert({I.first, I.second});
514e8d8bef9SDimitry Andric }
515e8d8bef9SDimitry Andric }
516e8d8bef9SDimitry Andric
writeCtxSplitLayout(const SampleProfileMap & ProfileMap)517e8d8bef9SDimitry Andric std::error_code SampleProfileWriterExtBinary::writeCtxSplitLayout(
518349cc55cSDimitry Andric const SampleProfileMap &ProfileMap) {
519349cc55cSDimitry Andric SampleProfileMap ContextProfileMap, NoContextProfileMap;
520e8d8bef9SDimitry Andric splitProfileMapToTwo(ProfileMap, ContextProfileMap, NoContextProfileMap);
521e8d8bef9SDimitry Andric
522e8d8bef9SDimitry Andric if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap))
523e8d8bef9SDimitry Andric return EC;
524e8d8bef9SDimitry Andric if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap))
525e8d8bef9SDimitry Andric return EC;
526e8d8bef9SDimitry Andric if (auto EC = writeOneSection(SecLBRProfile, 3, ContextProfileMap))
527e8d8bef9SDimitry Andric return EC;
528e8d8bef9SDimitry Andric if (auto EC = writeOneSection(SecFuncOffsetTable, 2, ContextProfileMap))
529e8d8bef9SDimitry Andric return EC;
530e8d8bef9SDimitry Andric // Mark the section to have no context. Note section flag needs to be set
531e8d8bef9SDimitry Andric // before writing the section.
532e8d8bef9SDimitry Andric addSectionFlag(5, SecCommonFlags::SecFlagFlat);
533e8d8bef9SDimitry Andric if (auto EC = writeOneSection(SecLBRProfile, 5, NoContextProfileMap))
534e8d8bef9SDimitry Andric return EC;
535e8d8bef9SDimitry Andric // Mark the section to have no context. Note section flag needs to be set
536e8d8bef9SDimitry Andric // before writing the section.
537e8d8bef9SDimitry Andric addSectionFlag(4, SecCommonFlags::SecFlagFlat);
538e8d8bef9SDimitry Andric if (auto EC = writeOneSection(SecFuncOffsetTable, 4, NoContextProfileMap))
539e8d8bef9SDimitry Andric return EC;
540e8d8bef9SDimitry Andric if (auto EC = writeOneSection(SecProfileSymbolList, 6, ProfileMap))
541e8d8bef9SDimitry Andric return EC;
542e8d8bef9SDimitry Andric if (auto EC = writeOneSection(SecFuncMetadata, 7, ProfileMap))
543e8d8bef9SDimitry Andric return EC;
544e8d8bef9SDimitry Andric
5455ffd83dbSDimitry Andric return sampleprof_error::success;
5465ffd83dbSDimitry Andric }
5475ffd83dbSDimitry Andric
writeSections(const SampleProfileMap & ProfileMap)5488bcb0991SDimitry Andric std::error_code SampleProfileWriterExtBinary::writeSections(
549349cc55cSDimitry Andric const SampleProfileMap &ProfileMap) {
550e8d8bef9SDimitry Andric std::error_code EC;
551e8d8bef9SDimitry Andric if (SecLayout == DefaultLayout)
552e8d8bef9SDimitry Andric EC = writeDefaultLayout(ProfileMap);
553e8d8bef9SDimitry Andric else if (SecLayout == CtxSplitLayout)
554e8d8bef9SDimitry Andric EC = writeCtxSplitLayout(ProfileMap);
555e8d8bef9SDimitry Andric else
556e8d8bef9SDimitry Andric llvm_unreachable("Unsupported layout");
5578bcb0991SDimitry Andric return EC;
5588bcb0991SDimitry Andric }
5598bcb0991SDimitry Andric
5600b57cec5SDimitry Andric /// Write samples to a text file.
5610b57cec5SDimitry Andric ///
5620b57cec5SDimitry Andric /// Note: it may be tempting to implement this in terms of
5630b57cec5SDimitry Andric /// FunctionSamples::print(). Please don't. The dump functionality is intended
5640b57cec5SDimitry Andric /// for debugging and has no specified form.
5650b57cec5SDimitry Andric ///
5660b57cec5SDimitry Andric /// The format used here is more structured and deliberate because
5670b57cec5SDimitry Andric /// it needs to be parsed by the SampleProfileReaderText class.
writeSample(const FunctionSamples & S)5688bcb0991SDimitry Andric std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) {
5690b57cec5SDimitry Andric auto &OS = *OutputStream;
57081ad6265SDimitry Andric if (FunctionSamples::ProfileIsCS)
571349cc55cSDimitry Andric OS << "[" << S.getContext().toString() << "]:" << S.getTotalSamples();
572fe6060f1SDimitry Andric else
573*c9157d92SDimitry Andric OS << S.getFunction() << ":" << S.getTotalSamples();
574fe6060f1SDimitry Andric
5750b57cec5SDimitry Andric if (Indent == 0)
5760b57cec5SDimitry Andric OS << ":" << S.getHeadSamples();
5770b57cec5SDimitry Andric OS << "\n";
578fe013be4SDimitry Andric LineCount++;
5790b57cec5SDimitry Andric
5800b57cec5SDimitry Andric SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples());
5810b57cec5SDimitry Andric for (const auto &I : SortedSamples.get()) {
5820b57cec5SDimitry Andric LineLocation Loc = I->first;
5830b57cec5SDimitry Andric const SampleRecord &Sample = I->second;
5840b57cec5SDimitry Andric OS.indent(Indent + 1);
5850b57cec5SDimitry Andric if (Loc.Discriminator == 0)
5860b57cec5SDimitry Andric OS << Loc.LineOffset << ": ";
5870b57cec5SDimitry Andric else
5880b57cec5SDimitry Andric OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
5890b57cec5SDimitry Andric
5900b57cec5SDimitry Andric OS << Sample.getSamples();
5910b57cec5SDimitry Andric
5928bcb0991SDimitry Andric for (const auto &J : Sample.getSortedCallTargets())
5938bcb0991SDimitry Andric OS << " " << J.first << ":" << J.second;
5940b57cec5SDimitry Andric OS << "\n";
595fe013be4SDimitry Andric LineCount++;
5960b57cec5SDimitry Andric }
5970b57cec5SDimitry Andric
5980b57cec5SDimitry Andric SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples(
5990b57cec5SDimitry Andric S.getCallsiteSamples());
6000b57cec5SDimitry Andric Indent += 1;
6010b57cec5SDimitry Andric for (const auto &I : SortedCallsiteSamples.get())
6020b57cec5SDimitry Andric for (const auto &FS : I->second) {
6030b57cec5SDimitry Andric LineLocation Loc = I->first;
6040b57cec5SDimitry Andric const FunctionSamples &CalleeSamples = FS.second;
6050b57cec5SDimitry Andric OS.indent(Indent);
6060b57cec5SDimitry Andric if (Loc.Discriminator == 0)
6070b57cec5SDimitry Andric OS << Loc.LineOffset << ": ";
6080b57cec5SDimitry Andric else
6090b57cec5SDimitry Andric OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
6108bcb0991SDimitry Andric if (std::error_code EC = writeSample(CalleeSamples))
6110b57cec5SDimitry Andric return EC;
6120b57cec5SDimitry Andric }
6130b57cec5SDimitry Andric Indent -= 1;
6140b57cec5SDimitry Andric
615e8d8bef9SDimitry Andric if (FunctionSamples::ProfileIsProbeBased) {
616e8d8bef9SDimitry Andric OS.indent(Indent + 1);
617e8d8bef9SDimitry Andric OS << "!CFGChecksum: " << S.getFunctionHash() << "\n";
618fe013be4SDimitry Andric LineCount++;
619e8d8bef9SDimitry Andric }
6200eae32dcSDimitry Andric
6210eae32dcSDimitry Andric if (S.getContext().getAllAttributes()) {
622fe6060f1SDimitry Andric OS.indent(Indent + 1);
623fe6060f1SDimitry Andric OS << "!Attributes: " << S.getContext().getAllAttributes() << "\n";
624fe013be4SDimitry Andric LineCount++;
625fe6060f1SDimitry Andric }
626e8d8bef9SDimitry Andric
6270b57cec5SDimitry Andric return sampleprof_error::success;
6280b57cec5SDimitry Andric }
6290b57cec5SDimitry Andric
630349cc55cSDimitry Andric std::error_code
writeContextIdx(const SampleContext & Context)631349cc55cSDimitry Andric SampleProfileWriterBinary::writeContextIdx(const SampleContext &Context) {
632349cc55cSDimitry Andric assert(!Context.hasContext() && "cs profile is not supported");
633*c9157d92SDimitry Andric return writeNameIdx(Context.getFunction());
634fe6060f1SDimitry Andric }
635fe6060f1SDimitry Andric
writeNameIdx(FunctionId FName)636*c9157d92SDimitry Andric std::error_code SampleProfileWriterBinary::writeNameIdx(FunctionId FName) {
637349cc55cSDimitry Andric auto &NTable = getNameTable();
638349cc55cSDimitry Andric const auto &Ret = NTable.find(FName);
639349cc55cSDimitry Andric if (Ret == NTable.end())
6400b57cec5SDimitry Andric return sampleprof_error::truncated_name_table;
641fe6060f1SDimitry Andric encodeULEB128(Ret->second, *OutputStream);
6420b57cec5SDimitry Andric return sampleprof_error::success;
6430b57cec5SDimitry Andric }
6440b57cec5SDimitry Andric
addName(FunctionId FName)645*c9157d92SDimitry Andric void SampleProfileWriterBinary::addName(FunctionId FName) {
646349cc55cSDimitry Andric auto &NTable = getNameTable();
647349cc55cSDimitry Andric NTable.insert(std::make_pair(FName, 0));
648fe6060f1SDimitry Andric }
649349cc55cSDimitry Andric
addContext(const SampleContext & Context)650349cc55cSDimitry Andric void SampleProfileWriterBinary::addContext(const SampleContext &Context) {
651*c9157d92SDimitry Andric addName(Context.getFunction());
6520b57cec5SDimitry Andric }
6530b57cec5SDimitry Andric
addNames(const FunctionSamples & S)6540b57cec5SDimitry Andric void SampleProfileWriterBinary::addNames(const FunctionSamples &S) {
6550b57cec5SDimitry Andric // Add all the names in indirect call targets.
6560b57cec5SDimitry Andric for (const auto &I : S.getBodySamples()) {
6570b57cec5SDimitry Andric const SampleRecord &Sample = I.second;
6580b57cec5SDimitry Andric for (const auto &J : Sample.getCallTargets())
659*c9157d92SDimitry Andric addName(J.first);
6600b57cec5SDimitry Andric }
6610b57cec5SDimitry Andric
6620b57cec5SDimitry Andric // Recursively add all the names for inlined callsites.
6630b57cec5SDimitry Andric for (const auto &J : S.getCallsiteSamples())
6640b57cec5SDimitry Andric for (const auto &FS : J.second) {
6650b57cec5SDimitry Andric const FunctionSamples &CalleeSamples = FS.second;
666*c9157d92SDimitry Andric addName(CalleeSamples.getFunction());
6670b57cec5SDimitry Andric addNames(CalleeSamples);
6680b57cec5SDimitry Andric }
6690b57cec5SDimitry Andric }
6700b57cec5SDimitry Andric
addContext(const SampleContext & Context)671349cc55cSDimitry Andric void SampleProfileWriterExtBinaryBase::addContext(
672349cc55cSDimitry Andric const SampleContext &Context) {
673349cc55cSDimitry Andric if (Context.hasContext()) {
674349cc55cSDimitry Andric for (auto &Callsite : Context.getContextFrames())
675*c9157d92SDimitry Andric SampleProfileWriterBinary::addName(Callsite.Func);
676349cc55cSDimitry Andric CSNameTable.insert(std::make_pair(Context, 0));
677349cc55cSDimitry Andric } else {
678*c9157d92SDimitry Andric SampleProfileWriterBinary::addName(Context.getFunction());
679349cc55cSDimitry Andric }
680349cc55cSDimitry Andric }
681349cc55cSDimitry Andric
stablizeNameTable(MapVector<FunctionId,uint32_t> & NameTable,std::set<FunctionId> & V)682349cc55cSDimitry Andric void SampleProfileWriterBinary::stablizeNameTable(
683*c9157d92SDimitry Andric MapVector<FunctionId, uint32_t> &NameTable, std::set<FunctionId> &V) {
6840b57cec5SDimitry Andric // Sort the names to make NameTable deterministic.
6850b57cec5SDimitry Andric for (const auto &I : NameTable)
6860b57cec5SDimitry Andric V.insert(I.first);
6870b57cec5SDimitry Andric int i = 0;
688*c9157d92SDimitry Andric for (const FunctionId &N : V)
6890b57cec5SDimitry Andric NameTable[N] = i++;
6900b57cec5SDimitry Andric }
6910b57cec5SDimitry Andric
writeNameTable()6928bcb0991SDimitry Andric std::error_code SampleProfileWriterBinary::writeNameTable() {
6930b57cec5SDimitry Andric auto &OS = *OutputStream;
694*c9157d92SDimitry Andric std::set<FunctionId> V;
695349cc55cSDimitry Andric stablizeNameTable(NameTable, V);
6960b57cec5SDimitry Andric
6970b57cec5SDimitry Andric // Write out the name table.
6980b57cec5SDimitry Andric encodeULEB128(NameTable.size(), OS);
6990b57cec5SDimitry Andric for (auto N : V) {
7000b57cec5SDimitry Andric OS << N;
7010b57cec5SDimitry Andric encodeULEB128(0, OS);
7020b57cec5SDimitry Andric }
7030b57cec5SDimitry Andric return sampleprof_error::success;
7040b57cec5SDimitry Andric }
7050b57cec5SDimitry Andric
7068bcb0991SDimitry Andric std::error_code
writeMagicIdent(SampleProfileFormat Format)7078bcb0991SDimitry Andric SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) {
7080b57cec5SDimitry Andric auto &OS = *OutputStream;
7090b57cec5SDimitry Andric // Write file magic identifier.
7108bcb0991SDimitry Andric encodeULEB128(SPMagic(Format), OS);
7110b57cec5SDimitry Andric encodeULEB128(SPVersion(), OS);
7120b57cec5SDimitry Andric return sampleprof_error::success;
7130b57cec5SDimitry Andric }
7140b57cec5SDimitry Andric
715349cc55cSDimitry Andric std::error_code
writeHeader(const SampleProfileMap & ProfileMap)716349cc55cSDimitry Andric SampleProfileWriterBinary::writeHeader(const SampleProfileMap &ProfileMap) {
717fe013be4SDimitry Andric // When calling write on a different profile map, existing names should be
718fe013be4SDimitry Andric // cleared.
719fe013be4SDimitry Andric NameTable.clear();
720fe013be4SDimitry Andric
7218bcb0991SDimitry Andric writeMagicIdent(Format);
7220b57cec5SDimitry Andric
7230b57cec5SDimitry Andric computeSummary(ProfileMap);
7240b57cec5SDimitry Andric if (auto EC = writeSummary())
7250b57cec5SDimitry Andric return EC;
7260b57cec5SDimitry Andric
7270b57cec5SDimitry Andric // Generate the name table for all the functions referenced in the profile.
7280b57cec5SDimitry Andric for (const auto &I : ProfileMap) {
729*c9157d92SDimitry Andric addContext(I.second.getContext());
7300b57cec5SDimitry Andric addNames(I.second);
7310b57cec5SDimitry Andric }
7320b57cec5SDimitry Andric
7330b57cec5SDimitry Andric writeNameTable();
7340b57cec5SDimitry Andric return sampleprof_error::success;
7350b57cec5SDimitry Andric }
7360b57cec5SDimitry Andric
setToCompressAllSections()7378bcb0991SDimitry Andric void SampleProfileWriterExtBinaryBase::setToCompressAllSections() {
7388bcb0991SDimitry Andric for (auto &Entry : SectionHdrLayout)
7395ffd83dbSDimitry Andric addSecFlag(Entry, SecCommonFlags::SecFlagCompress);
7408bcb0991SDimitry Andric }
7418bcb0991SDimitry Andric
setToCompressSection(SecType Type)7428bcb0991SDimitry Andric void SampleProfileWriterExtBinaryBase::setToCompressSection(SecType Type) {
7435ffd83dbSDimitry Andric addSectionFlag(Type, SecCommonFlags::SecFlagCompress);
7448bcb0991SDimitry Andric }
7458bcb0991SDimitry Andric
allocSecHdrTable()7468bcb0991SDimitry Andric void SampleProfileWriterExtBinaryBase::allocSecHdrTable() {
747*c9157d92SDimitry Andric support::endian::Writer Writer(*OutputStream, llvm::endianness::little);
7488bcb0991SDimitry Andric
7498bcb0991SDimitry Andric Writer.write(static_cast<uint64_t>(SectionHdrLayout.size()));
7508bcb0991SDimitry Andric SecHdrTableOffset = OutputStream->tell();
7518bcb0991SDimitry Andric for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) {
7528bcb0991SDimitry Andric Writer.write(static_cast<uint64_t>(-1));
7538bcb0991SDimitry Andric Writer.write(static_cast<uint64_t>(-1));
7548bcb0991SDimitry Andric Writer.write(static_cast<uint64_t>(-1));
7558bcb0991SDimitry Andric Writer.write(static_cast<uint64_t>(-1));
7568bcb0991SDimitry Andric }
7578bcb0991SDimitry Andric }
7588bcb0991SDimitry Andric
writeSecHdrTable()7598bcb0991SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() {
760e8d8bef9SDimitry Andric assert(SecHdrTable.size() == SectionHdrLayout.size() &&
761e8d8bef9SDimitry Andric "SecHdrTable entries doesn't match SectionHdrLayout");
762e8d8bef9SDimitry Andric SmallVector<uint32_t, 16> IndexMap(SecHdrTable.size(), -1);
763e8d8bef9SDimitry Andric for (uint32_t TableIdx = 0; TableIdx < SecHdrTable.size(); TableIdx++) {
764e8d8bef9SDimitry Andric IndexMap[SecHdrTable[TableIdx].LayoutIndex] = TableIdx;
7658bcb0991SDimitry Andric }
7668bcb0991SDimitry Andric
7678bcb0991SDimitry Andric // Write the section header table in the order specified in
768e8d8bef9SDimitry Andric // SectionHdrLayout. SectionHdrLayout specifies the sections
769e8d8bef9SDimitry Andric // order in which profile reader expect to read, so the section
770e8d8bef9SDimitry Andric // header table should be written in the order in SectionHdrLayout.
771e8d8bef9SDimitry Andric // Note that the section order in SecHdrTable may be different
772e8d8bef9SDimitry Andric // from the order in SectionHdrLayout, for example, SecFuncOffsetTable
773e8d8bef9SDimitry Andric // needs to be computed after SecLBRProfile (the order in SecHdrTable),
774e8d8bef9SDimitry Andric // but it needs to be read before SecLBRProfile (the order in
775e8d8bef9SDimitry Andric // SectionHdrLayout). So we use IndexMap above to switch the order.
776fe013be4SDimitry Andric support::endian::SeekableWriter Writer(
777*c9157d92SDimitry Andric static_cast<raw_pwrite_stream &>(*OutputStream),
778*c9157d92SDimitry Andric llvm::endianness::little);
779e8d8bef9SDimitry Andric for (uint32_t LayoutIdx = 0; LayoutIdx < SectionHdrLayout.size();
780e8d8bef9SDimitry Andric LayoutIdx++) {
781e8d8bef9SDimitry Andric assert(IndexMap[LayoutIdx] < SecHdrTable.size() &&
782e8d8bef9SDimitry Andric "Incorrect LayoutIdx in SecHdrTable");
783e8d8bef9SDimitry Andric auto Entry = SecHdrTable[IndexMap[LayoutIdx]];
784fe013be4SDimitry Andric Writer.pwrite(static_cast<uint64_t>(Entry.Type),
785fe013be4SDimitry Andric SecHdrTableOffset + 4 * LayoutIdx * sizeof(uint64_t));
786fe013be4SDimitry Andric Writer.pwrite(static_cast<uint64_t>(Entry.Flags),
787fe013be4SDimitry Andric SecHdrTableOffset + (4 * LayoutIdx + 1) * sizeof(uint64_t));
788fe013be4SDimitry Andric Writer.pwrite(static_cast<uint64_t>(Entry.Offset),
789fe013be4SDimitry Andric SecHdrTableOffset + (4 * LayoutIdx + 2) * sizeof(uint64_t));
790fe013be4SDimitry Andric Writer.pwrite(static_cast<uint64_t>(Entry.Size),
791fe013be4SDimitry Andric SecHdrTableOffset + (4 * LayoutIdx + 3) * sizeof(uint64_t));
7928bcb0991SDimitry Andric }
7938bcb0991SDimitry Andric
7948bcb0991SDimitry Andric return sampleprof_error::success;
7958bcb0991SDimitry Andric }
7968bcb0991SDimitry Andric
writeHeader(const SampleProfileMap & ProfileMap)7978bcb0991SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeHeader(
798349cc55cSDimitry Andric const SampleProfileMap &ProfileMap) {
7998bcb0991SDimitry Andric auto &OS = *OutputStream;
8008bcb0991SDimitry Andric FileStart = OS.tell();
8018bcb0991SDimitry Andric writeMagicIdent(Format);
8028bcb0991SDimitry Andric
8038bcb0991SDimitry Andric allocSecHdrTable();
8048bcb0991SDimitry Andric return sampleprof_error::success;
8058bcb0991SDimitry Andric }
8068bcb0991SDimitry Andric
writeSummary()8070b57cec5SDimitry Andric std::error_code SampleProfileWriterBinary::writeSummary() {
8080b57cec5SDimitry Andric auto &OS = *OutputStream;
8090b57cec5SDimitry Andric encodeULEB128(Summary->getTotalCount(), OS);
8100b57cec5SDimitry Andric encodeULEB128(Summary->getMaxCount(), OS);
8110b57cec5SDimitry Andric encodeULEB128(Summary->getMaxFunctionCount(), OS);
8120b57cec5SDimitry Andric encodeULEB128(Summary->getNumCounts(), OS);
8130b57cec5SDimitry Andric encodeULEB128(Summary->getNumFunctions(), OS);
814349cc55cSDimitry Andric const std::vector<ProfileSummaryEntry> &Entries =
815349cc55cSDimitry Andric Summary->getDetailedSummary();
8160b57cec5SDimitry Andric encodeULEB128(Entries.size(), OS);
8170b57cec5SDimitry Andric for (auto Entry : Entries) {
8180b57cec5SDimitry Andric encodeULEB128(Entry.Cutoff, OS);
8190b57cec5SDimitry Andric encodeULEB128(Entry.MinCount, OS);
8200b57cec5SDimitry Andric encodeULEB128(Entry.NumCounts, OS);
8210b57cec5SDimitry Andric }
8220b57cec5SDimitry Andric return sampleprof_error::success;
8230b57cec5SDimitry Andric }
writeBody(const FunctionSamples & S)8240b57cec5SDimitry Andric std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
8250b57cec5SDimitry Andric auto &OS = *OutputStream;
826349cc55cSDimitry Andric if (std::error_code EC = writeContextIdx(S.getContext()))
8270b57cec5SDimitry Andric return EC;
8280b57cec5SDimitry Andric
8290b57cec5SDimitry Andric encodeULEB128(S.getTotalSamples(), OS);
8300b57cec5SDimitry Andric
8310b57cec5SDimitry Andric // Emit all the body samples.
8320b57cec5SDimitry Andric encodeULEB128(S.getBodySamples().size(), OS);
8330b57cec5SDimitry Andric for (const auto &I : S.getBodySamples()) {
8340b57cec5SDimitry Andric LineLocation Loc = I.first;
8350b57cec5SDimitry Andric const SampleRecord &Sample = I.second;
8360b57cec5SDimitry Andric encodeULEB128(Loc.LineOffset, OS);
8370b57cec5SDimitry Andric encodeULEB128(Loc.Discriminator, OS);
8380b57cec5SDimitry Andric encodeULEB128(Sample.getSamples(), OS);
8390b57cec5SDimitry Andric encodeULEB128(Sample.getCallTargets().size(), OS);
8408bcb0991SDimitry Andric for (const auto &J : Sample.getSortedCallTargets()) {
841*c9157d92SDimitry Andric FunctionId Callee = J.first;
8420b57cec5SDimitry Andric uint64_t CalleeSamples = J.second;
8430b57cec5SDimitry Andric if (std::error_code EC = writeNameIdx(Callee))
8440b57cec5SDimitry Andric return EC;
8450b57cec5SDimitry Andric encodeULEB128(CalleeSamples, OS);
8460b57cec5SDimitry Andric }
8470b57cec5SDimitry Andric }
8480b57cec5SDimitry Andric
8490b57cec5SDimitry Andric // Recursively emit all the callsite samples.
8500b57cec5SDimitry Andric uint64_t NumCallsites = 0;
8510b57cec5SDimitry Andric for (const auto &J : S.getCallsiteSamples())
8520b57cec5SDimitry Andric NumCallsites += J.second.size();
8530b57cec5SDimitry Andric encodeULEB128(NumCallsites, OS);
8540b57cec5SDimitry Andric for (const auto &J : S.getCallsiteSamples())
8550b57cec5SDimitry Andric for (const auto &FS : J.second) {
8560b57cec5SDimitry Andric LineLocation Loc = J.first;
8570b57cec5SDimitry Andric const FunctionSamples &CalleeSamples = FS.second;
8580b57cec5SDimitry Andric encodeULEB128(Loc.LineOffset, OS);
8590b57cec5SDimitry Andric encodeULEB128(Loc.Discriminator, OS);
8600b57cec5SDimitry Andric if (std::error_code EC = writeBody(CalleeSamples))
8610b57cec5SDimitry Andric return EC;
8620b57cec5SDimitry Andric }
8630b57cec5SDimitry Andric
8640b57cec5SDimitry Andric return sampleprof_error::success;
8650b57cec5SDimitry Andric }
8660b57cec5SDimitry Andric
8670b57cec5SDimitry Andric /// Write samples of a top-level function to a binary file.
8680b57cec5SDimitry Andric ///
8690b57cec5SDimitry Andric /// \returns true if the samples were written successfully, false otherwise.
8708bcb0991SDimitry Andric std::error_code
writeSample(const FunctionSamples & S)8718bcb0991SDimitry Andric SampleProfileWriterBinary::writeSample(const FunctionSamples &S) {
8720b57cec5SDimitry Andric encodeULEB128(S.getHeadSamples(), *OutputStream);
8730b57cec5SDimitry Andric return writeBody(S);
8740b57cec5SDimitry Andric }
8750b57cec5SDimitry Andric
8760b57cec5SDimitry Andric /// Create a sample profile file writer based on the specified format.
8770b57cec5SDimitry Andric ///
8780b57cec5SDimitry Andric /// \param Filename The file to create.
8790b57cec5SDimitry Andric ///
8800b57cec5SDimitry Andric /// \param Format Encoding format for the profile file.
8810b57cec5SDimitry Andric ///
8820b57cec5SDimitry Andric /// \returns an error code indicating the status of the created writer.
8830b57cec5SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileWriter>>
create(StringRef Filename,SampleProfileFormat Format)8840b57cec5SDimitry Andric SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
8850b57cec5SDimitry Andric std::error_code EC;
8860b57cec5SDimitry Andric std::unique_ptr<raw_ostream> OS;
887fe013be4SDimitry Andric if (Format == SPF_Binary || Format == SPF_Ext_Binary)
8888bcb0991SDimitry Andric OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None));
8890b57cec5SDimitry Andric else
890fe6060f1SDimitry Andric OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_TextWithCRLF));
8910b57cec5SDimitry Andric if (EC)
8920b57cec5SDimitry Andric return EC;
8930b57cec5SDimitry Andric
8940b57cec5SDimitry Andric return create(OS, Format);
8950b57cec5SDimitry Andric }
8960b57cec5SDimitry Andric
8970b57cec5SDimitry Andric /// Create a sample profile stream writer based on the specified format.
8980b57cec5SDimitry Andric ///
8990b57cec5SDimitry Andric /// \param OS The output stream to store the profile data to.
9000b57cec5SDimitry Andric ///
9010b57cec5SDimitry Andric /// \param Format Encoding format for the profile file.
9020b57cec5SDimitry Andric ///
9030b57cec5SDimitry Andric /// \returns an error code indicating the status of the created writer.
9040b57cec5SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileWriter>>
create(std::unique_ptr<raw_ostream> & OS,SampleProfileFormat Format)9050b57cec5SDimitry Andric SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
9060b57cec5SDimitry Andric SampleProfileFormat Format) {
9070b57cec5SDimitry Andric std::error_code EC;
9080b57cec5SDimitry Andric std::unique_ptr<SampleProfileWriter> Writer;
9090b57cec5SDimitry Andric
910fe6060f1SDimitry Andric // Currently only Text and Extended Binary format are supported for CSSPGO.
91181ad6265SDimitry Andric if ((FunctionSamples::ProfileIsCS || FunctionSamples::ProfileIsProbeBased) &&
912fe013be4SDimitry Andric Format == SPF_Binary)
913fe6060f1SDimitry Andric return sampleprof_error::unsupported_writing_format;
914fe6060f1SDimitry Andric
9150b57cec5SDimitry Andric if (Format == SPF_Binary)
9160b57cec5SDimitry Andric Writer.reset(new SampleProfileWriterRawBinary(OS));
9178bcb0991SDimitry Andric else if (Format == SPF_Ext_Binary)
9188bcb0991SDimitry Andric Writer.reset(new SampleProfileWriterExtBinary(OS));
9190b57cec5SDimitry Andric else if (Format == SPF_Text)
9200b57cec5SDimitry Andric Writer.reset(new SampleProfileWriterText(OS));
9210b57cec5SDimitry Andric else if (Format == SPF_GCC)
9220b57cec5SDimitry Andric EC = sampleprof_error::unsupported_writing_format;
9230b57cec5SDimitry Andric else
9240b57cec5SDimitry Andric EC = sampleprof_error::unrecognized_format;
9250b57cec5SDimitry Andric
9260b57cec5SDimitry Andric if (EC)
9270b57cec5SDimitry Andric return EC;
9280b57cec5SDimitry Andric
9298bcb0991SDimitry Andric Writer->Format = Format;
9300b57cec5SDimitry Andric return std::move(Writer);
9310b57cec5SDimitry Andric }
9320b57cec5SDimitry Andric
computeSummary(const SampleProfileMap & ProfileMap)933349cc55cSDimitry Andric void SampleProfileWriter::computeSummary(const SampleProfileMap &ProfileMap) {
9340b57cec5SDimitry Andric SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
935d409305fSDimitry Andric Summary = Builder.computeSummaryForProfiles(ProfileMap);
9360b57cec5SDimitry Andric }
937