xref: /freebsd-src/contrib/llvm-project/llvm/lib/ProfileData/SampleProfWriter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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>
3306c3fb27SDimitry 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 
4106c3fb27SDimitry Andric #define DEBUG_TYPE "llvm-profdata"
4206c3fb27SDimitry Andric 
430b57cec5SDimitry Andric using namespace llvm;
440b57cec5SDimitry Andric using namespace sampleprof;
450b57cec5SDimitry Andric 
4606c3fb27SDimitry Andric namespace llvm {
4706c3fb27SDimitry Andric namespace support {
4806c3fb27SDimitry Andric namespace endian {
4906c3fb27SDimitry Andric namespace {
5006c3fb27SDimitry Andric 
5106c3fb27SDimitry Andric // Adapter class to llvm::support::endian::Writer for pwrite().
5206c3fb27SDimitry Andric struct SeekableWriter {
5306c3fb27SDimitry Andric   raw_pwrite_stream &OS;
5406c3fb27SDimitry Andric   endianness Endian;
5506c3fb27SDimitry Andric   SeekableWriter(raw_pwrite_stream &OS, endianness Endian)
5606c3fb27SDimitry Andric       : OS(OS), Endian(Endian) {}
5706c3fb27SDimitry Andric 
5806c3fb27SDimitry Andric   template <typename ValueType>
5906c3fb27SDimitry Andric   void pwrite(ValueType Val, size_t Offset) {
6006c3fb27SDimitry Andric     std::string StringBuf;
6106c3fb27SDimitry Andric     raw_string_ostream SStream(StringBuf);
6206c3fb27SDimitry Andric     Writer(SStream, Endian).write(Val);
6306c3fb27SDimitry Andric     OS.pwrite(StringBuf.data(), StringBuf.size(), Offset);
6406c3fb27SDimitry Andric   }
6506c3fb27SDimitry Andric };
6606c3fb27SDimitry Andric 
6706c3fb27SDimitry Andric } // namespace
6806c3fb27SDimitry Andric } // namespace endian
6906c3fb27SDimitry Andric } // namespace support
7006c3fb27SDimitry Andric } // namespace llvm
7106c3fb27SDimitry Andric 
7206c3fb27SDimitry Andric DefaultFunctionPruningStrategy::DefaultFunctionPruningStrategy(
7306c3fb27SDimitry Andric     SampleProfileMap &ProfileMap, size_t OutputSizeLimit)
7406c3fb27SDimitry Andric     : FunctionPruningStrategy(ProfileMap, OutputSizeLimit) {
7506c3fb27SDimitry Andric   sortFuncProfiles(ProfileMap, SortedFunctions);
7606c3fb27SDimitry Andric }
7706c3fb27SDimitry Andric 
7806c3fb27SDimitry Andric void DefaultFunctionPruningStrategy::Erase(size_t CurrentOutputSize) {
7906c3fb27SDimitry Andric   double D = (double)OutputSizeLimit / CurrentOutputSize;
8006c3fb27SDimitry Andric   size_t NewSize = (size_t)round(ProfileMap.size() * D * D);
8106c3fb27SDimitry Andric   size_t NumToRemove = ProfileMap.size() - NewSize;
8206c3fb27SDimitry Andric   if (NumToRemove < 1)
8306c3fb27SDimitry Andric     NumToRemove = 1;
8406c3fb27SDimitry Andric 
8506c3fb27SDimitry Andric   assert(NumToRemove <= SortedFunctions.size());
865f757f3fSDimitry Andric   for (const NameFunctionSamples &E :
875f757f3fSDimitry Andric        llvm::drop_begin(SortedFunctions, SortedFunctions.size() - NumToRemove))
885f757f3fSDimitry Andric     ProfileMap.erase(E.first);
8906c3fb27SDimitry Andric   SortedFunctions.resize(SortedFunctions.size() - NumToRemove);
9006c3fb27SDimitry Andric }
9106c3fb27SDimitry Andric 
9206c3fb27SDimitry Andric std::error_code SampleProfileWriter::writeWithSizeLimitInternal(
9306c3fb27SDimitry Andric     SampleProfileMap &ProfileMap, size_t OutputSizeLimit,
9406c3fb27SDimitry Andric     FunctionPruningStrategy *Strategy) {
9506c3fb27SDimitry Andric   if (OutputSizeLimit == 0)
9606c3fb27SDimitry Andric     return write(ProfileMap);
9706c3fb27SDimitry Andric 
9806c3fb27SDimitry Andric   size_t OriginalFunctionCount = ProfileMap.size();
9906c3fb27SDimitry Andric 
10006c3fb27SDimitry Andric   std::unique_ptr<raw_ostream> OriginalOutputStream;
10106c3fb27SDimitry Andric   OutputStream.swap(OriginalOutputStream);
10206c3fb27SDimitry Andric 
10306c3fb27SDimitry Andric   size_t IterationCount = 0;
10406c3fb27SDimitry Andric   size_t TotalSize;
10506c3fb27SDimitry Andric 
10606c3fb27SDimitry Andric   SmallVector<char> StringBuffer;
10706c3fb27SDimitry Andric   do {
10806c3fb27SDimitry Andric     StringBuffer.clear();
10906c3fb27SDimitry Andric     OutputStream.reset(new raw_svector_ostream(StringBuffer));
11006c3fb27SDimitry Andric     if (std::error_code EC = write(ProfileMap))
11106c3fb27SDimitry Andric       return EC;
11206c3fb27SDimitry Andric 
11306c3fb27SDimitry Andric     TotalSize = StringBuffer.size();
11406c3fb27SDimitry Andric     // On Windows every "\n" is actually written as "\r\n" to disk but not to
11506c3fb27SDimitry Andric     // memory buffer, this difference should be added when considering the total
11606c3fb27SDimitry Andric     // output size.
11706c3fb27SDimitry Andric #ifdef _WIN32
11806c3fb27SDimitry Andric     if (Format == SPF_Text)
11906c3fb27SDimitry Andric       TotalSize += LineCount;
12006c3fb27SDimitry Andric #endif
12106c3fb27SDimitry Andric     if (TotalSize <= OutputSizeLimit)
12206c3fb27SDimitry Andric       break;
12306c3fb27SDimitry Andric 
12406c3fb27SDimitry Andric     Strategy->Erase(TotalSize);
12506c3fb27SDimitry Andric     IterationCount++;
12606c3fb27SDimitry Andric   } while (ProfileMap.size() != 0);
12706c3fb27SDimitry Andric 
12806c3fb27SDimitry Andric   if (ProfileMap.size() == 0)
12906c3fb27SDimitry Andric     return sampleprof_error::too_large;
13006c3fb27SDimitry Andric 
13106c3fb27SDimitry Andric   OutputStream.swap(OriginalOutputStream);
13206c3fb27SDimitry Andric   OutputStream->write(StringBuffer.data(), StringBuffer.size());
13306c3fb27SDimitry Andric   LLVM_DEBUG(dbgs() << "Profile originally has " << OriginalFunctionCount
13406c3fb27SDimitry Andric                     << " functions, reduced to " << ProfileMap.size() << " in "
13506c3fb27SDimitry Andric                     << IterationCount << " iterations\n");
13606c3fb27SDimitry Andric   // Silence warning on Release build.
13706c3fb27SDimitry Andric   (void)OriginalFunctionCount;
13806c3fb27SDimitry Andric   (void)IterationCount;
13906c3fb27SDimitry Andric   return sampleprof_error::success;
14006c3fb27SDimitry Andric }
14106c3fb27SDimitry Andric 
142349cc55cSDimitry Andric std::error_code
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 
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
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 
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.
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
217349cc55cSDimitry Andric SampleProfileWriterExtBinaryBase::write(const SampleProfileMap &ProfileMap) {
21806c3fb27SDimitry Andric   // When calling write on a different profile map, existing states should be
21906c3fb27SDimitry Andric   // cleared.
22006c3fb27SDimitry Andric   NameTable.clear();
22106c3fb27SDimitry Andric   CSNameTable.clear();
22206c3fb27SDimitry Andric   SecHdrTable.clear();
22306c3fb27SDimitry 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 
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
2435f757f3fSDimitry Andric     return SampleProfileWriterBinary::writeNameIdx(Context.getFunction());
244349cc55cSDimitry Andric }
245349cc55cSDimitry Andric 
246349cc55cSDimitry Andric std::error_code
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
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 
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 
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 
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 
344e8d8bef9SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeNameTable() {
3455ffd83dbSDimitry Andric   if (!UseMD5)
3465ffd83dbSDimitry Andric     return SampleProfileWriterBinary::writeNameTable();
3475ffd83dbSDimitry Andric 
3485ffd83dbSDimitry Andric   auto &OS = *OutputStream;
3495f757f3fSDimitry 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);
3565f757f3fSDimitry Andric   support::endian::Writer Writer(OS, llvm::endianness::little);
357e8d8bef9SDimitry Andric   for (auto N : V)
3585f757f3fSDimitry Andric     Writer.write(N.getHashCode());
359e8d8bef9SDimitry Andric   return sampleprof_error::success;
3605ffd83dbSDimitry Andric }
361e8d8bef9SDimitry Andric 
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.
3725f757f3fSDimitry Andric   // Original names are unavailable if using MD5, so this option has no use.
3735f757f3fSDimitry Andric   if (!UseMD5) {
374fe6060f1SDimitry Andric     for (const auto &I : NameTable) {
3755f757f3fSDimitry Andric       if (I.first.stringRef().contains(FunctionSamples::UniqSuffix)) {
376fe6060f1SDimitry Andric         addSectionFlag(SecNameTable, SecNameTableFlags::SecFlagUniqSuffix);
377fe6060f1SDimitry Andric         break;
378fe6060f1SDimitry Andric       }
379fe6060f1SDimitry Andric     }
3805f757f3fSDimitry Andric   }
381fe6060f1SDimitry Andric 
382e8d8bef9SDimitry Andric   if (auto EC = writeNameTable())
383e8d8bef9SDimitry Andric     return EC;
384e8d8bef9SDimitry Andric   return sampleprof_error::success;
385e8d8bef9SDimitry Andric }
386e8d8bef9SDimitry Andric 
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);
4005f757f3fSDimitry 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) {
4055f757f3fSDimitry 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
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 
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 
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 
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 
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 
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.
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
5735f757f3fSDimitry Andric     OS << S.getFunction() << ":" << S.getTotalSamples();
574fe6060f1SDimitry Andric 
5750b57cec5SDimitry Andric   if (Indent == 0)
5760b57cec5SDimitry Andric     OS << ":" << S.getHeadSamples();
5770b57cec5SDimitry Andric   OS << "\n";
57806c3fb27SDimitry 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";
59506c3fb27SDimitry 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";
61806c3fb27SDimitry 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";
62406c3fb27SDimitry Andric     LineCount++;
625fe6060f1SDimitry Andric   }
626e8d8bef9SDimitry Andric 
6270b57cec5SDimitry Andric   return sampleprof_error::success;
6280b57cec5SDimitry Andric }
6290b57cec5SDimitry Andric 
630349cc55cSDimitry Andric std::error_code
631349cc55cSDimitry Andric SampleProfileWriterBinary::writeContextIdx(const SampleContext &Context) {
632349cc55cSDimitry Andric   assert(!Context.hasContext() && "cs profile is not supported");
6335f757f3fSDimitry Andric   return writeNameIdx(Context.getFunction());
634fe6060f1SDimitry Andric }
635fe6060f1SDimitry Andric 
6365f757f3fSDimitry 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 
6455f757f3fSDimitry Andric void SampleProfileWriterBinary::addName(FunctionId FName) {
646349cc55cSDimitry Andric   auto &NTable = getNameTable();
647349cc55cSDimitry Andric   NTable.insert(std::make_pair(FName, 0));
648fe6060f1SDimitry Andric }
649349cc55cSDimitry Andric 
650349cc55cSDimitry Andric void SampleProfileWriterBinary::addContext(const SampleContext &Context) {
6515f757f3fSDimitry Andric   addName(Context.getFunction());
6520b57cec5SDimitry Andric }
6530b57cec5SDimitry Andric 
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())
6595f757f3fSDimitry 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;
6665f757f3fSDimitry Andric       addName(CalleeSamples.getFunction());
6670b57cec5SDimitry Andric       addNames(CalleeSamples);
6680b57cec5SDimitry Andric     }
6690b57cec5SDimitry Andric }
6700b57cec5SDimitry Andric 
671349cc55cSDimitry Andric void SampleProfileWriterExtBinaryBase::addContext(
672349cc55cSDimitry Andric     const SampleContext &Context) {
673349cc55cSDimitry Andric   if (Context.hasContext()) {
674349cc55cSDimitry Andric     for (auto &Callsite : Context.getContextFrames())
6755f757f3fSDimitry Andric       SampleProfileWriterBinary::addName(Callsite.Func);
676349cc55cSDimitry Andric     CSNameTable.insert(std::make_pair(Context, 0));
677349cc55cSDimitry Andric   } else {
6785f757f3fSDimitry Andric     SampleProfileWriterBinary::addName(Context.getFunction());
679349cc55cSDimitry Andric   }
680349cc55cSDimitry Andric }
681349cc55cSDimitry Andric 
682349cc55cSDimitry Andric void SampleProfileWriterBinary::stablizeNameTable(
6835f757f3fSDimitry 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;
6885f757f3fSDimitry Andric   for (const FunctionId &N : V)
6890b57cec5SDimitry Andric     NameTable[N] = i++;
6900b57cec5SDimitry Andric }
6910b57cec5SDimitry Andric 
6928bcb0991SDimitry Andric std::error_code SampleProfileWriterBinary::writeNameTable() {
6930b57cec5SDimitry Andric   auto &OS = *OutputStream;
6945f757f3fSDimitry 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
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
716349cc55cSDimitry Andric SampleProfileWriterBinary::writeHeader(const SampleProfileMap &ProfileMap) {
71706c3fb27SDimitry Andric   // When calling write on a different profile map, existing names should be
71806c3fb27SDimitry Andric   // cleared.
71906c3fb27SDimitry Andric   NameTable.clear();
72006c3fb27SDimitry 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) {
7295f757f3fSDimitry 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 
7378bcb0991SDimitry Andric void SampleProfileWriterExtBinaryBase::setToCompressAllSections() {
7388bcb0991SDimitry Andric   for (auto &Entry : SectionHdrLayout)
7395ffd83dbSDimitry Andric     addSecFlag(Entry, SecCommonFlags::SecFlagCompress);
7408bcb0991SDimitry Andric }
7418bcb0991SDimitry Andric 
7428bcb0991SDimitry Andric void SampleProfileWriterExtBinaryBase::setToCompressSection(SecType Type) {
7435ffd83dbSDimitry Andric   addSectionFlag(Type, SecCommonFlags::SecFlagCompress);
7448bcb0991SDimitry Andric }
7458bcb0991SDimitry Andric 
7468bcb0991SDimitry Andric void SampleProfileWriterExtBinaryBase::allocSecHdrTable() {
7475f757f3fSDimitry 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 
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.
77606c3fb27SDimitry Andric   support::endian::SeekableWriter Writer(
7775f757f3fSDimitry Andric       static_cast<raw_pwrite_stream &>(*OutputStream),
7785f757f3fSDimitry 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]];
78406c3fb27SDimitry Andric     Writer.pwrite(static_cast<uint64_t>(Entry.Type),
78506c3fb27SDimitry Andric                   SecHdrTableOffset + 4 * LayoutIdx * sizeof(uint64_t));
78606c3fb27SDimitry Andric     Writer.pwrite(static_cast<uint64_t>(Entry.Flags),
78706c3fb27SDimitry Andric                   SecHdrTableOffset + (4 * LayoutIdx + 1) * sizeof(uint64_t));
78806c3fb27SDimitry Andric     Writer.pwrite(static_cast<uint64_t>(Entry.Offset),
78906c3fb27SDimitry Andric                   SecHdrTableOffset + (4 * LayoutIdx + 2) * sizeof(uint64_t));
79006c3fb27SDimitry Andric     Writer.pwrite(static_cast<uint64_t>(Entry.Size),
79106c3fb27SDimitry Andric                   SecHdrTableOffset + (4 * LayoutIdx + 3) * sizeof(uint64_t));
7928bcb0991SDimitry Andric   }
7938bcb0991SDimitry Andric 
7948bcb0991SDimitry Andric   return sampleprof_error::success;
7958bcb0991SDimitry Andric }
7968bcb0991SDimitry Andric 
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 
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);
814*0fca6ea1SDimitry Andric   ArrayRef<ProfileSummaryEntry> Entries = Summary->getDetailedSummary();
8150b57cec5SDimitry Andric   encodeULEB128(Entries.size(), OS);
8160b57cec5SDimitry Andric   for (auto Entry : Entries) {
8170b57cec5SDimitry Andric     encodeULEB128(Entry.Cutoff, OS);
8180b57cec5SDimitry Andric     encodeULEB128(Entry.MinCount, OS);
8190b57cec5SDimitry Andric     encodeULEB128(Entry.NumCounts, OS);
8200b57cec5SDimitry Andric   }
8210b57cec5SDimitry Andric   return sampleprof_error::success;
8220b57cec5SDimitry Andric }
8230b57cec5SDimitry Andric std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
8240b57cec5SDimitry Andric   auto &OS = *OutputStream;
825349cc55cSDimitry Andric   if (std::error_code EC = writeContextIdx(S.getContext()))
8260b57cec5SDimitry Andric     return EC;
8270b57cec5SDimitry Andric 
8280b57cec5SDimitry Andric   encodeULEB128(S.getTotalSamples(), OS);
8290b57cec5SDimitry Andric 
8300b57cec5SDimitry Andric   // Emit all the body samples.
8310b57cec5SDimitry Andric   encodeULEB128(S.getBodySamples().size(), OS);
8320b57cec5SDimitry Andric   for (const auto &I : S.getBodySamples()) {
8330b57cec5SDimitry Andric     LineLocation Loc = I.first;
8340b57cec5SDimitry Andric     const SampleRecord &Sample = I.second;
8350b57cec5SDimitry Andric     encodeULEB128(Loc.LineOffset, OS);
8360b57cec5SDimitry Andric     encodeULEB128(Loc.Discriminator, OS);
8370b57cec5SDimitry Andric     encodeULEB128(Sample.getSamples(), OS);
8380b57cec5SDimitry Andric     encodeULEB128(Sample.getCallTargets().size(), OS);
8398bcb0991SDimitry Andric     for (const auto &J : Sample.getSortedCallTargets()) {
8405f757f3fSDimitry Andric       FunctionId Callee = J.first;
8410b57cec5SDimitry Andric       uint64_t CalleeSamples = J.second;
8420b57cec5SDimitry Andric       if (std::error_code EC = writeNameIdx(Callee))
8430b57cec5SDimitry Andric         return EC;
8440b57cec5SDimitry Andric       encodeULEB128(CalleeSamples, OS);
8450b57cec5SDimitry Andric     }
8460b57cec5SDimitry Andric   }
8470b57cec5SDimitry Andric 
8480b57cec5SDimitry Andric   // Recursively emit all the callsite samples.
8490b57cec5SDimitry Andric   uint64_t NumCallsites = 0;
8500b57cec5SDimitry Andric   for (const auto &J : S.getCallsiteSamples())
8510b57cec5SDimitry Andric     NumCallsites += J.second.size();
8520b57cec5SDimitry Andric   encodeULEB128(NumCallsites, OS);
8530b57cec5SDimitry Andric   for (const auto &J : S.getCallsiteSamples())
8540b57cec5SDimitry Andric     for (const auto &FS : J.second) {
8550b57cec5SDimitry Andric       LineLocation Loc = J.first;
8560b57cec5SDimitry Andric       const FunctionSamples &CalleeSamples = FS.second;
8570b57cec5SDimitry Andric       encodeULEB128(Loc.LineOffset, OS);
8580b57cec5SDimitry Andric       encodeULEB128(Loc.Discriminator, OS);
8590b57cec5SDimitry Andric       if (std::error_code EC = writeBody(CalleeSamples))
8600b57cec5SDimitry Andric         return EC;
8610b57cec5SDimitry Andric     }
8620b57cec5SDimitry Andric 
8630b57cec5SDimitry Andric   return sampleprof_error::success;
8640b57cec5SDimitry Andric }
8650b57cec5SDimitry Andric 
8660b57cec5SDimitry Andric /// Write samples of a top-level function to a binary file.
8670b57cec5SDimitry Andric ///
8680b57cec5SDimitry Andric /// \returns true if the samples were written successfully, false otherwise.
8698bcb0991SDimitry Andric std::error_code
8708bcb0991SDimitry Andric SampleProfileWriterBinary::writeSample(const FunctionSamples &S) {
8710b57cec5SDimitry Andric   encodeULEB128(S.getHeadSamples(), *OutputStream);
8720b57cec5SDimitry Andric   return writeBody(S);
8730b57cec5SDimitry Andric }
8740b57cec5SDimitry Andric 
8750b57cec5SDimitry Andric /// Create a sample profile file writer based on the specified format.
8760b57cec5SDimitry Andric ///
8770b57cec5SDimitry Andric /// \param Filename The file to create.
8780b57cec5SDimitry Andric ///
8790b57cec5SDimitry Andric /// \param Format Encoding format for the profile file.
8800b57cec5SDimitry Andric ///
8810b57cec5SDimitry Andric /// \returns an error code indicating the status of the created writer.
8820b57cec5SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileWriter>>
8830b57cec5SDimitry Andric SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
8840b57cec5SDimitry Andric   std::error_code EC;
8850b57cec5SDimitry Andric   std::unique_ptr<raw_ostream> OS;
88606c3fb27SDimitry Andric   if (Format == SPF_Binary || Format == SPF_Ext_Binary)
8878bcb0991SDimitry Andric     OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None));
8880b57cec5SDimitry Andric   else
889fe6060f1SDimitry Andric     OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_TextWithCRLF));
8900b57cec5SDimitry Andric   if (EC)
8910b57cec5SDimitry Andric     return EC;
8920b57cec5SDimitry Andric 
8930b57cec5SDimitry Andric   return create(OS, Format);
8940b57cec5SDimitry Andric }
8950b57cec5SDimitry Andric 
8960b57cec5SDimitry Andric /// Create a sample profile stream writer based on the specified format.
8970b57cec5SDimitry Andric ///
8980b57cec5SDimitry Andric /// \param OS The output stream to store the profile data to.
8990b57cec5SDimitry Andric ///
9000b57cec5SDimitry Andric /// \param Format Encoding format for the profile file.
9010b57cec5SDimitry Andric ///
9020b57cec5SDimitry Andric /// \returns an error code indicating the status of the created writer.
9030b57cec5SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileWriter>>
9040b57cec5SDimitry Andric SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
9050b57cec5SDimitry Andric                             SampleProfileFormat Format) {
9060b57cec5SDimitry Andric   std::error_code EC;
9070b57cec5SDimitry Andric   std::unique_ptr<SampleProfileWriter> Writer;
9080b57cec5SDimitry Andric 
909fe6060f1SDimitry Andric   // Currently only Text and Extended Binary format are supported for CSSPGO.
91081ad6265SDimitry Andric   if ((FunctionSamples::ProfileIsCS || FunctionSamples::ProfileIsProbeBased) &&
91106c3fb27SDimitry Andric       Format == SPF_Binary)
912fe6060f1SDimitry Andric     return sampleprof_error::unsupported_writing_format;
913fe6060f1SDimitry Andric 
9140b57cec5SDimitry Andric   if (Format == SPF_Binary)
9150b57cec5SDimitry Andric     Writer.reset(new SampleProfileWriterRawBinary(OS));
9168bcb0991SDimitry Andric   else if (Format == SPF_Ext_Binary)
9178bcb0991SDimitry Andric     Writer.reset(new SampleProfileWriterExtBinary(OS));
9180b57cec5SDimitry Andric   else if (Format == SPF_Text)
9190b57cec5SDimitry Andric     Writer.reset(new SampleProfileWriterText(OS));
9200b57cec5SDimitry Andric   else if (Format == SPF_GCC)
9210b57cec5SDimitry Andric     EC = sampleprof_error::unsupported_writing_format;
9220b57cec5SDimitry Andric   else
9230b57cec5SDimitry Andric     EC = sampleprof_error::unrecognized_format;
9240b57cec5SDimitry Andric 
9250b57cec5SDimitry Andric   if (EC)
9260b57cec5SDimitry Andric     return EC;
9270b57cec5SDimitry Andric 
9288bcb0991SDimitry Andric   Writer->Format = Format;
9290b57cec5SDimitry Andric   return std::move(Writer);
9300b57cec5SDimitry Andric }
9310b57cec5SDimitry Andric 
932349cc55cSDimitry Andric void SampleProfileWriter::computeSummary(const SampleProfileMap &ProfileMap) {
9330b57cec5SDimitry Andric   SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
934d409305fSDimitry Andric   Summary = Builder.computeSummaryForProfiles(ProfileMap);
9350b57cec5SDimitry Andric }
936