xref: /freebsd/contrib/llvm-project/llvm/lib/ProfileData/SampleProfWriter.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
1 //===- SampleProfWriter.cpp - Write LLVM sample profile data --------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements the class that writes LLVM sample profiles. It
10 // supports two file formats: text and binary. The textual representation
11 // is useful for debugging and testing purposes. The binary representation
12 // is more compact, resulting in smaller file sizes. However, they can
13 // both be used interchangeably.
14 //
15 // See lib/ProfileData/SampleProfReader.cpp for documentation on each of the
16 // supported formats.
17 //
18 //===----------------------------------------------------------------------===//
19 
20 #include "llvm/ProfileData/SampleProfWriter.h"
21 #include "llvm/ADT/StringRef.h"
22 #include "llvm/ProfileData/ProfileCommon.h"
23 #include "llvm/ProfileData/SampleProf.h"
24 #include "llvm/Support/Compression.h"
25 #include "llvm/Support/EndianStream.h"
26 #include "llvm/Support/ErrorOr.h"
27 #include "llvm/Support/FileSystem.h"
28 #include "llvm/Support/LEB128.h"
29 #include "llvm/Support/MD5.h"
30 #include "llvm/Support/raw_ostream.h"
31 #include <cmath>
32 #include <cstdint>
33 #include <memory>
34 #include <set>
35 #include <system_error>
36 #include <utility>
37 #include <vector>
38 
39 #define DEBUG_TYPE "llvm-profdata"
40 
41 using namespace llvm;
42 using namespace sampleprof;
43 
44 namespace llvm {
45 namespace support {
46 namespace endian {
47 namespace {
48 
49 // Adapter class to llvm::support::endian::Writer for pwrite().
50 struct SeekableWriter {
51   raw_pwrite_stream &OS;
52   endianness Endian;
53   SeekableWriter(raw_pwrite_stream &OS, endianness Endian)
54       : OS(OS), Endian(Endian) {}
55 
56   template <typename ValueType>
57   void pwrite(ValueType Val, size_t Offset) {
58     std::string StringBuf;
59     raw_string_ostream SStream(StringBuf);
60     Writer(SStream, Endian).write(Val);
61     OS.pwrite(StringBuf.data(), StringBuf.size(), Offset);
62   }
63 };
64 
65 } // namespace
66 } // namespace endian
67 } // namespace support
68 } // namespace llvm
69 
70 DefaultFunctionPruningStrategy::DefaultFunctionPruningStrategy(
71     SampleProfileMap &ProfileMap, size_t OutputSizeLimit)
72     : FunctionPruningStrategy(ProfileMap, OutputSizeLimit) {
73   sortFuncProfiles(ProfileMap, SortedFunctions);
74 }
75 
76 void DefaultFunctionPruningStrategy::Erase(size_t CurrentOutputSize) {
77   double D = (double)OutputSizeLimit / CurrentOutputSize;
78   size_t NewSize = (size_t)round(ProfileMap.size() * D * D);
79   size_t NumToRemove = ProfileMap.size() - NewSize;
80   if (NumToRemove < 1)
81     NumToRemove = 1;
82 
83   assert(NumToRemove <= SortedFunctions.size());
84   for (const NameFunctionSamples &E :
85        llvm::drop_begin(SortedFunctions, SortedFunctions.size() - NumToRemove))
86     ProfileMap.erase(E.first);
87   SortedFunctions.resize(SortedFunctions.size() - NumToRemove);
88 }
89 
90 std::error_code SampleProfileWriter::writeWithSizeLimitInternal(
91     SampleProfileMap &ProfileMap, size_t OutputSizeLimit,
92     FunctionPruningStrategy *Strategy) {
93   if (OutputSizeLimit == 0)
94     return write(ProfileMap);
95 
96   size_t OriginalFunctionCount = ProfileMap.size();
97 
98   std::unique_ptr<raw_ostream> OriginalOutputStream;
99   OutputStream.swap(OriginalOutputStream);
100 
101   size_t IterationCount = 0;
102   size_t TotalSize;
103 
104   SmallVector<char> StringBuffer;
105   do {
106     StringBuffer.clear();
107     OutputStream.reset(new raw_svector_ostream(StringBuffer));
108     if (std::error_code EC = write(ProfileMap))
109       return EC;
110 
111     TotalSize = StringBuffer.size();
112     // On Windows every "\n" is actually written as "\r\n" to disk but not to
113     // memory buffer, this difference should be added when considering the total
114     // output size.
115 #ifdef _WIN32
116     if (Format == SPF_Text)
117       TotalSize += LineCount;
118 #endif
119     if (TotalSize <= OutputSizeLimit)
120       break;
121 
122     Strategy->Erase(TotalSize);
123     IterationCount++;
124   } while (ProfileMap.size() != 0);
125 
126   if (ProfileMap.size() == 0)
127     return sampleprof_error::too_large;
128 
129   OutputStream.swap(OriginalOutputStream);
130   OutputStream->write(StringBuffer.data(), StringBuffer.size());
131   LLVM_DEBUG(dbgs() << "Profile originally has " << OriginalFunctionCount
132                     << " functions, reduced to " << ProfileMap.size() << " in "
133                     << IterationCount << " iterations\n");
134   // Silence warning on Release build.
135   (void)OriginalFunctionCount;
136   (void)IterationCount;
137   return sampleprof_error::success;
138 }
139 
140 std::error_code
141 SampleProfileWriter::writeFuncProfiles(const SampleProfileMap &ProfileMap) {
142   std::vector<NameFunctionSamples> V;
143   sortFuncProfiles(ProfileMap, V);
144   for (const auto &I : V) {
145     if (std::error_code EC = writeSample(*I.second))
146       return EC;
147   }
148   return sampleprof_error::success;
149 }
150 
151 std::error_code SampleProfileWriter::write(const SampleProfileMap &ProfileMap) {
152   if (std::error_code EC = writeHeader(ProfileMap))
153     return EC;
154 
155   if (std::error_code EC = writeFuncProfiles(ProfileMap))
156     return EC;
157 
158   return sampleprof_error::success;
159 }
160 
161 /// Return the current position and prepare to use it as the start
162 /// position of a section given the section type \p Type and its position
163 /// \p LayoutIdx in SectionHdrLayout.
164 uint64_t
165 SampleProfileWriterExtBinaryBase::markSectionStart(SecType Type,
166                                                    uint32_t LayoutIdx) {
167   uint64_t SectionStart = OutputStream->tell();
168   assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range");
169   const auto &Entry = SectionHdrLayout[LayoutIdx];
170   assert(Entry.Type == Type && "Unexpected section type");
171   // Use LocalBuf as a temporary output for writting data.
172   if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress))
173     LocalBufStream.swap(OutputStream);
174   return SectionStart;
175 }
176 
177 std::error_code SampleProfileWriterExtBinaryBase::compressAndOutput() {
178   if (!llvm::compression::zlib::isAvailable())
179     return sampleprof_error::zlib_unavailable;
180   std::string &UncompressedStrings =
181       static_cast<raw_string_ostream *>(LocalBufStream.get())->str();
182   if (UncompressedStrings.size() == 0)
183     return sampleprof_error::success;
184   auto &OS = *OutputStream;
185   SmallVector<uint8_t, 128> CompressedStrings;
186   compression::zlib::compress(arrayRefFromStringRef(UncompressedStrings),
187                               CompressedStrings,
188                               compression::zlib::BestSizeCompression);
189   encodeULEB128(UncompressedStrings.size(), OS);
190   encodeULEB128(CompressedStrings.size(), OS);
191   OS << toStringRef(CompressedStrings);
192   UncompressedStrings.clear();
193   return sampleprof_error::success;
194 }
195 
196 /// Add a new section into section header table given the section type
197 /// \p Type, its position \p LayoutIdx in SectionHdrLayout and the
198 /// location \p SectionStart where the section should be written to.
199 std::error_code SampleProfileWriterExtBinaryBase::addNewSection(
200     SecType Type, uint32_t LayoutIdx, uint64_t SectionStart) {
201   assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range");
202   const auto &Entry = SectionHdrLayout[LayoutIdx];
203   assert(Entry.Type == Type && "Unexpected section type");
204   if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress)) {
205     LocalBufStream.swap(OutputStream);
206     if (std::error_code EC = compressAndOutput())
207       return EC;
208   }
209   SecHdrTable.push_back({Type, Entry.Flags, SectionStart - FileStart,
210                          OutputStream->tell() - SectionStart, LayoutIdx});
211   return sampleprof_error::success;
212 }
213 
214 std::error_code
215 SampleProfileWriterExtBinaryBase::write(const SampleProfileMap &ProfileMap) {
216   // When calling write on a different profile map, existing states should be
217   // cleared.
218   NameTable.clear();
219   CSNameTable.clear();
220   SecHdrTable.clear();
221 
222   if (std::error_code EC = writeHeader(ProfileMap))
223     return EC;
224 
225   std::string LocalBuf;
226   LocalBufStream = std::make_unique<raw_string_ostream>(LocalBuf);
227   if (std::error_code EC = writeSections(ProfileMap))
228     return EC;
229 
230   if (std::error_code EC = writeSecHdrTable())
231     return EC;
232 
233   return sampleprof_error::success;
234 }
235 
236 std::error_code SampleProfileWriterExtBinaryBase::writeContextIdx(
237     const SampleContext &Context) {
238   if (Context.hasContext())
239     return writeCSNameIdx(Context);
240   else
241     return SampleProfileWriterBinary::writeNameIdx(Context.getFunction());
242 }
243 
244 std::error_code
245 SampleProfileWriterExtBinaryBase::writeCSNameIdx(const SampleContext &Context) {
246   const auto &Ret = CSNameTable.find(Context);
247   if (Ret == CSNameTable.end())
248     return sampleprof_error::truncated_name_table;
249   encodeULEB128(Ret->second, *OutputStream);
250   return sampleprof_error::success;
251 }
252 
253 std::error_code
254 SampleProfileWriterExtBinaryBase::writeSample(const FunctionSamples &S) {
255   uint64_t Offset = OutputStream->tell();
256   auto &Context = S.getContext();
257   FuncOffsetTable[Context] = Offset - SecLBRProfileStart;
258   encodeULEB128(S.getHeadSamples(), *OutputStream);
259   return writeBody(S);
260 }
261 
262 std::error_code SampleProfileWriterExtBinaryBase::writeFuncOffsetTable() {
263   auto &OS = *OutputStream;
264 
265   // Write out the table size.
266   encodeULEB128(FuncOffsetTable.size(), OS);
267 
268   // Write out FuncOffsetTable.
269   auto WriteItem = [&](const SampleContext &Context, uint64_t Offset) {
270     if (std::error_code EC = writeContextIdx(Context))
271       return EC;
272     encodeULEB128(Offset, OS);
273     return (std::error_code)sampleprof_error::success;
274   };
275 
276   if (FunctionSamples::ProfileIsCS) {
277     // Sort the contexts before writing them out. This is to help fast load all
278     // context profiles for a function as well as their callee contexts which
279     // can help profile-guided importing for ThinLTO.
280     std::map<SampleContext, uint64_t> OrderedFuncOffsetTable(
281         FuncOffsetTable.begin(), FuncOffsetTable.end());
282     for (const auto &Entry : OrderedFuncOffsetTable) {
283       if (std::error_code EC = WriteItem(Entry.first, Entry.second))
284         return EC;
285     }
286     addSectionFlag(SecFuncOffsetTable, SecFuncOffsetFlags::SecFlagOrdered);
287   } else {
288     for (const auto &Entry : FuncOffsetTable) {
289       if (std::error_code EC = WriteItem(Entry.first, Entry.second))
290         return EC;
291     }
292   }
293 
294   FuncOffsetTable.clear();
295   return sampleprof_error::success;
296 }
297 
298 std::error_code SampleProfileWriterExtBinaryBase::writeFuncMetadata(
299     const FunctionSamples &FunctionProfile) {
300   auto &OS = *OutputStream;
301   if (std::error_code EC = writeContextIdx(FunctionProfile.getContext()))
302     return EC;
303 
304   if (FunctionSamples::ProfileIsProbeBased)
305     encodeULEB128(FunctionProfile.getFunctionHash(), OS);
306   if (FunctionSamples::ProfileIsCS || FunctionSamples::ProfileIsPreInlined) {
307     encodeULEB128(FunctionProfile.getContext().getAllAttributes(), OS);
308   }
309 
310   if (!FunctionSamples::ProfileIsCS) {
311     // Recursively emit attributes for all callee samples.
312     uint64_t NumCallsites = 0;
313     for (const auto &J : FunctionProfile.getCallsiteSamples())
314       NumCallsites += J.second.size();
315     encodeULEB128(NumCallsites, OS);
316     for (const auto &J : FunctionProfile.getCallsiteSamples()) {
317       for (const auto &FS : J.second) {
318         LineLocation Loc = J.first;
319         encodeULEB128(Loc.LineOffset, OS);
320         encodeULEB128(Loc.Discriminator, OS);
321         if (std::error_code EC = writeFuncMetadata(FS.second))
322           return EC;
323       }
324     }
325   }
326 
327   return sampleprof_error::success;
328 }
329 
330 std::error_code SampleProfileWriterExtBinaryBase::writeFuncMetadata(
331     const SampleProfileMap &Profiles) {
332   if (!FunctionSamples::ProfileIsProbeBased && !FunctionSamples::ProfileIsCS &&
333       !FunctionSamples::ProfileIsPreInlined)
334     return sampleprof_error::success;
335   for (const auto &Entry : Profiles) {
336     if (std::error_code EC = writeFuncMetadata(Entry.second))
337       return EC;
338   }
339   return sampleprof_error::success;
340 }
341 
342 std::error_code SampleProfileWriterExtBinaryBase::writeNameTable() {
343   if (!UseMD5)
344     return SampleProfileWriterBinary::writeNameTable();
345 
346   auto &OS = *OutputStream;
347   std::set<FunctionId> V;
348   stablizeNameTable(NameTable, V);
349 
350   // Write out the MD5 name table. We wrote unencoded MD5 so reader can
351   // retrieve the name using the name index without having to read the
352   // whole name table.
353   encodeULEB128(NameTable.size(), OS);
354   support::endian::Writer Writer(OS, llvm::endianness::little);
355   for (auto N : V)
356     Writer.write(N.getHashCode());
357   return sampleprof_error::success;
358 }
359 
360 std::error_code SampleProfileWriterExtBinaryBase::writeNameTableSection(
361     const SampleProfileMap &ProfileMap) {
362   for (const auto &I : ProfileMap) {
363     addContext(I.second.getContext());
364     addNames(I.second);
365   }
366 
367   // If NameTable contains ".__uniq." suffix, set SecFlagUniqSuffix flag
368   // so compiler won't strip the suffix during profile matching after
369   // seeing the flag in the profile.
370   // Original names are unavailable if using MD5, so this option has no use.
371   if (!UseMD5) {
372     for (const auto &I : NameTable) {
373       if (I.first.stringRef().contains(FunctionSamples::UniqSuffix)) {
374         addSectionFlag(SecNameTable, SecNameTableFlags::SecFlagUniqSuffix);
375         break;
376       }
377     }
378   }
379 
380   if (auto EC = writeNameTable())
381     return EC;
382   return sampleprof_error::success;
383 }
384 
385 std::error_code SampleProfileWriterExtBinaryBase::writeCSNameTableSection() {
386   // Sort the names to make CSNameTable deterministic.
387   std::set<SampleContext> OrderedContexts;
388   for (const auto &I : CSNameTable)
389     OrderedContexts.insert(I.first);
390   assert(OrderedContexts.size() == CSNameTable.size() &&
391          "Unmatched ordered and unordered contexts");
392   uint64_t I = 0;
393   for (auto &Context : OrderedContexts)
394     CSNameTable[Context] = I++;
395 
396   auto &OS = *OutputStream;
397   encodeULEB128(OrderedContexts.size(), OS);
398   support::endian::Writer Writer(OS, llvm::endianness::little);
399   for (auto Context : OrderedContexts) {
400     auto Frames = Context.getContextFrames();
401     encodeULEB128(Frames.size(), OS);
402     for (auto &Callsite : Frames) {
403       if (std::error_code EC = writeNameIdx(Callsite.Func))
404         return EC;
405       encodeULEB128(Callsite.Location.LineOffset, OS);
406       encodeULEB128(Callsite.Location.Discriminator, OS);
407     }
408   }
409 
410   return sampleprof_error::success;
411 }
412 
413 std::error_code
414 SampleProfileWriterExtBinaryBase::writeProfileSymbolListSection() {
415   if (ProfSymList && ProfSymList->size() > 0)
416     if (std::error_code EC = ProfSymList->write(*OutputStream))
417       return EC;
418 
419   return sampleprof_error::success;
420 }
421 
422 std::error_code SampleProfileWriterExtBinaryBase::writeOneSection(
423     SecType Type, uint32_t LayoutIdx, const SampleProfileMap &ProfileMap) {
424   // The setting of SecFlagCompress should happen before markSectionStart.
425   if (Type == SecProfileSymbolList && ProfSymList && ProfSymList->toCompress())
426     setToCompressSection(SecProfileSymbolList);
427   if (Type == SecFuncMetadata && FunctionSamples::ProfileIsProbeBased)
428     addSectionFlag(SecFuncMetadata, SecFuncMetadataFlags::SecFlagIsProbeBased);
429   if (Type == SecFuncMetadata &&
430       (FunctionSamples::ProfileIsCS || FunctionSamples::ProfileIsPreInlined))
431     addSectionFlag(SecFuncMetadata, SecFuncMetadataFlags::SecFlagHasAttribute);
432   if (Type == SecProfSummary && FunctionSamples::ProfileIsCS)
433     addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagFullContext);
434   if (Type == SecProfSummary && FunctionSamples::ProfileIsPreInlined)
435     addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagIsPreInlined);
436   if (Type == SecProfSummary && FunctionSamples::ProfileIsFS)
437     addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagFSDiscriminator);
438 
439   uint64_t SectionStart = markSectionStart(Type, LayoutIdx);
440   switch (Type) {
441   case SecProfSummary:
442     computeSummary(ProfileMap);
443     if (auto EC = writeSummary())
444       return EC;
445     break;
446   case SecNameTable:
447     if (auto EC = writeNameTableSection(ProfileMap))
448       return EC;
449     break;
450   case SecCSNameTable:
451     if (auto EC = writeCSNameTableSection())
452       return EC;
453     break;
454   case SecLBRProfile:
455     SecLBRProfileStart = OutputStream->tell();
456     if (std::error_code EC = writeFuncProfiles(ProfileMap))
457       return EC;
458     break;
459   case SecFuncOffsetTable:
460     if (auto EC = writeFuncOffsetTable())
461       return EC;
462     break;
463   case SecFuncMetadata:
464     if (std::error_code EC = writeFuncMetadata(ProfileMap))
465       return EC;
466     break;
467   case SecProfileSymbolList:
468     if (auto EC = writeProfileSymbolListSection())
469       return EC;
470     break;
471   default:
472     if (auto EC = writeCustomSection(Type))
473       return EC;
474     break;
475   }
476   if (std::error_code EC = addNewSection(Type, LayoutIdx, SectionStart))
477     return EC;
478   return sampleprof_error::success;
479 }
480 
481 std::error_code SampleProfileWriterExtBinary::writeDefaultLayout(
482     const SampleProfileMap &ProfileMap) {
483   // The const indices passed to writeOneSection below are specifying the
484   // positions of the sections in SectionHdrLayout. Look at
485   // initSectionHdrLayout to find out where each section is located in
486   // SectionHdrLayout.
487   if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap))
488     return EC;
489   if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap))
490     return EC;
491   if (auto EC = writeOneSection(SecCSNameTable, 2, ProfileMap))
492     return EC;
493   if (auto EC = writeOneSection(SecLBRProfile, 4, ProfileMap))
494     return EC;
495   if (auto EC = writeOneSection(SecProfileSymbolList, 5, ProfileMap))
496     return EC;
497   if (auto EC = writeOneSection(SecFuncOffsetTable, 3, ProfileMap))
498     return EC;
499   if (auto EC = writeOneSection(SecFuncMetadata, 6, ProfileMap))
500     return EC;
501   return sampleprof_error::success;
502 }
503 
504 static void splitProfileMapToTwo(const SampleProfileMap &ProfileMap,
505                                  SampleProfileMap &ContextProfileMap,
506                                  SampleProfileMap &NoContextProfileMap) {
507   for (const auto &I : ProfileMap) {
508     if (I.second.getCallsiteSamples().size())
509       ContextProfileMap.insert({I.first, I.second});
510     else
511       NoContextProfileMap.insert({I.first, I.second});
512   }
513 }
514 
515 std::error_code SampleProfileWriterExtBinary::writeCtxSplitLayout(
516     const SampleProfileMap &ProfileMap) {
517   SampleProfileMap ContextProfileMap, NoContextProfileMap;
518   splitProfileMapToTwo(ProfileMap, ContextProfileMap, NoContextProfileMap);
519 
520   if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap))
521     return EC;
522   if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap))
523     return EC;
524   if (auto EC = writeOneSection(SecLBRProfile, 3, ContextProfileMap))
525     return EC;
526   if (auto EC = writeOneSection(SecFuncOffsetTable, 2, ContextProfileMap))
527     return EC;
528   // Mark the section to have no context. Note section flag needs to be set
529   // before writing the section.
530   addSectionFlag(5, SecCommonFlags::SecFlagFlat);
531   if (auto EC = writeOneSection(SecLBRProfile, 5, NoContextProfileMap))
532     return EC;
533   // Mark the section to have no context. Note section flag needs to be set
534   // before writing the section.
535   addSectionFlag(4, SecCommonFlags::SecFlagFlat);
536   if (auto EC = writeOneSection(SecFuncOffsetTable, 4, NoContextProfileMap))
537     return EC;
538   if (auto EC = writeOneSection(SecProfileSymbolList, 6, ProfileMap))
539     return EC;
540   if (auto EC = writeOneSection(SecFuncMetadata, 7, ProfileMap))
541     return EC;
542 
543   return sampleprof_error::success;
544 }
545 
546 std::error_code SampleProfileWriterExtBinary::writeSections(
547     const SampleProfileMap &ProfileMap) {
548   std::error_code EC;
549   if (SecLayout == DefaultLayout)
550     EC = writeDefaultLayout(ProfileMap);
551   else if (SecLayout == CtxSplitLayout)
552     EC = writeCtxSplitLayout(ProfileMap);
553   else
554     llvm_unreachable("Unsupported layout");
555   return EC;
556 }
557 
558 /// Write samples to a text file.
559 ///
560 /// Note: it may be tempting to implement this in terms of
561 /// FunctionSamples::print().  Please don't.  The dump functionality is intended
562 /// for debugging and has no specified form.
563 ///
564 /// The format used here is more structured and deliberate because
565 /// it needs to be parsed by the SampleProfileReaderText class.
566 std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) {
567   auto &OS = *OutputStream;
568   if (FunctionSamples::ProfileIsCS)
569     OS << "[" << S.getContext().toString() << "]:" << S.getTotalSamples();
570   else
571     OS << S.getFunction() << ":" << S.getTotalSamples();
572 
573   if (Indent == 0)
574     OS << ":" << S.getHeadSamples();
575   OS << "\n";
576   LineCount++;
577 
578   SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples());
579   for (const auto &I : SortedSamples.get()) {
580     LineLocation Loc = I->first;
581     const SampleRecord &Sample = I->second;
582     OS.indent(Indent + 1);
583     Loc.print(OS);
584     OS << ": " << Sample.getSamples();
585 
586     for (const auto &J : Sample.getSortedCallTargets())
587       OS << " " << J.first << ":" << J.second;
588     OS << "\n";
589     LineCount++;
590   }
591 
592   SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples(
593       S.getCallsiteSamples());
594   Indent += 1;
595   for (const auto *Element : SortedCallsiteSamples.get()) {
596     // Element is a pointer to a pair of LineLocation and FunctionSamplesMap.
597     const auto &[Loc, FunctionSamplesMap] = *Element;
598     for (const FunctionSamples &CalleeSamples :
599          make_second_range(FunctionSamplesMap)) {
600       OS.indent(Indent);
601       Loc.print(OS);
602       OS << ": ";
603       if (std::error_code EC = writeSample(CalleeSamples))
604         return EC;
605     }
606   }
607   Indent -= 1;
608 
609   if (FunctionSamples::ProfileIsProbeBased) {
610     OS.indent(Indent + 1);
611     OS << "!CFGChecksum: " << S.getFunctionHash() << "\n";
612     LineCount++;
613   }
614 
615   if (S.getContext().getAllAttributes()) {
616     OS.indent(Indent + 1);
617     OS << "!Attributes: " << S.getContext().getAllAttributes() << "\n";
618     LineCount++;
619   }
620 
621   if (Indent == 0 && MarkFlatProfiles && S.getCallsiteSamples().size() == 0)
622     OS << " !Flat\n";
623 
624   return sampleprof_error::success;
625 }
626 
627 std::error_code
628 SampleProfileWriterBinary::writeContextIdx(const SampleContext &Context) {
629   assert(!Context.hasContext() && "cs profile is not supported");
630   return writeNameIdx(Context.getFunction());
631 }
632 
633 std::error_code SampleProfileWriterBinary::writeNameIdx(FunctionId FName) {
634   auto &NTable = getNameTable();
635   const auto &Ret = NTable.find(FName);
636   if (Ret == NTable.end())
637     return sampleprof_error::truncated_name_table;
638   encodeULEB128(Ret->second, *OutputStream);
639   return sampleprof_error::success;
640 }
641 
642 void SampleProfileWriterBinary::addName(FunctionId FName) {
643   auto &NTable = getNameTable();
644   NTable.insert(std::make_pair(FName, 0));
645 }
646 
647 void SampleProfileWriterBinary::addContext(const SampleContext &Context) {
648   addName(Context.getFunction());
649 }
650 
651 void SampleProfileWriterBinary::addNames(const FunctionSamples &S) {
652   // Add all the names in indirect call targets.
653   for (const auto &I : S.getBodySamples()) {
654     const SampleRecord &Sample = I.second;
655     for (const auto &J : Sample.getCallTargets())
656       addName(J.first);
657   }
658 
659   // Recursively add all the names for inlined callsites.
660   for (const auto &J : S.getCallsiteSamples())
661     for (const auto &FS : J.second) {
662       const FunctionSamples &CalleeSamples = FS.second;
663       addName(CalleeSamples.getFunction());
664       addNames(CalleeSamples);
665     }
666 }
667 
668 void SampleProfileWriterExtBinaryBase::addContext(
669     const SampleContext &Context) {
670   if (Context.hasContext()) {
671     for (auto &Callsite : Context.getContextFrames())
672       SampleProfileWriterBinary::addName(Callsite.Func);
673     CSNameTable.insert(std::make_pair(Context, 0));
674   } else {
675     SampleProfileWriterBinary::addName(Context.getFunction());
676   }
677 }
678 
679 void SampleProfileWriterBinary::stablizeNameTable(
680     MapVector<FunctionId, uint32_t> &NameTable, std::set<FunctionId> &V) {
681   // Sort the names to make NameTable deterministic.
682   for (const auto &I : NameTable)
683     V.insert(I.first);
684   int i = 0;
685   for (const FunctionId &N : V)
686     NameTable[N] = i++;
687 }
688 
689 std::error_code SampleProfileWriterBinary::writeNameTable() {
690   auto &OS = *OutputStream;
691   std::set<FunctionId> V;
692   stablizeNameTable(NameTable, V);
693 
694   // Write out the name table.
695   encodeULEB128(NameTable.size(), OS);
696   for (auto N : V) {
697     OS << N;
698     encodeULEB128(0, OS);
699   }
700   return sampleprof_error::success;
701 }
702 
703 std::error_code
704 SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) {
705   auto &OS = *OutputStream;
706   // Write file magic identifier.
707   encodeULEB128(SPMagic(Format), OS);
708   encodeULEB128(SPVersion(), OS);
709   return sampleprof_error::success;
710 }
711 
712 std::error_code
713 SampleProfileWriterBinary::writeHeader(const SampleProfileMap &ProfileMap) {
714   // When calling write on a different profile map, existing names should be
715   // cleared.
716   NameTable.clear();
717 
718   writeMagicIdent(Format);
719 
720   computeSummary(ProfileMap);
721   if (auto EC = writeSummary())
722     return EC;
723 
724   // Generate the name table for all the functions referenced in the profile.
725   for (const auto &I : ProfileMap) {
726     addContext(I.second.getContext());
727     addNames(I.second);
728   }
729 
730   writeNameTable();
731   return sampleprof_error::success;
732 }
733 
734 void SampleProfileWriterExtBinaryBase::setToCompressAllSections() {
735   for (auto &Entry : SectionHdrLayout)
736     addSecFlag(Entry, SecCommonFlags::SecFlagCompress);
737 }
738 
739 void SampleProfileWriterExtBinaryBase::setToCompressSection(SecType Type) {
740   addSectionFlag(Type, SecCommonFlags::SecFlagCompress);
741 }
742 
743 void SampleProfileWriterExtBinaryBase::allocSecHdrTable() {
744   support::endian::Writer Writer(*OutputStream, llvm::endianness::little);
745 
746   Writer.write(static_cast<uint64_t>(SectionHdrLayout.size()));
747   SecHdrTableOffset = OutputStream->tell();
748   for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) {
749     Writer.write(static_cast<uint64_t>(-1));
750     Writer.write(static_cast<uint64_t>(-1));
751     Writer.write(static_cast<uint64_t>(-1));
752     Writer.write(static_cast<uint64_t>(-1));
753   }
754 }
755 
756 std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() {
757   assert(SecHdrTable.size() == SectionHdrLayout.size() &&
758          "SecHdrTable entries doesn't match SectionHdrLayout");
759   SmallVector<uint32_t, 16> IndexMap(SecHdrTable.size(), -1);
760   for (uint32_t TableIdx = 0; TableIdx < SecHdrTable.size(); TableIdx++) {
761     IndexMap[SecHdrTable[TableIdx].LayoutIndex] = TableIdx;
762   }
763 
764   // Write the section header table in the order specified in
765   // SectionHdrLayout. SectionHdrLayout specifies the sections
766   // order in which profile reader expect to read, so the section
767   // header table should be written in the order in SectionHdrLayout.
768   // Note that the section order in SecHdrTable may be different
769   // from the order in SectionHdrLayout, for example, SecFuncOffsetTable
770   // needs to be computed after SecLBRProfile (the order in SecHdrTable),
771   // but it needs to be read before SecLBRProfile (the order in
772   // SectionHdrLayout). So we use IndexMap above to switch the order.
773   support::endian::SeekableWriter Writer(
774       static_cast<raw_pwrite_stream &>(*OutputStream),
775       llvm::endianness::little);
776   for (uint32_t LayoutIdx = 0; LayoutIdx < SectionHdrLayout.size();
777        LayoutIdx++) {
778     assert(IndexMap[LayoutIdx] < SecHdrTable.size() &&
779            "Incorrect LayoutIdx in SecHdrTable");
780     auto Entry = SecHdrTable[IndexMap[LayoutIdx]];
781     Writer.pwrite(static_cast<uint64_t>(Entry.Type),
782                   SecHdrTableOffset + 4 * LayoutIdx * sizeof(uint64_t));
783     Writer.pwrite(static_cast<uint64_t>(Entry.Flags),
784                   SecHdrTableOffset + (4 * LayoutIdx + 1) * sizeof(uint64_t));
785     Writer.pwrite(static_cast<uint64_t>(Entry.Offset),
786                   SecHdrTableOffset + (4 * LayoutIdx + 2) * sizeof(uint64_t));
787     Writer.pwrite(static_cast<uint64_t>(Entry.Size),
788                   SecHdrTableOffset + (4 * LayoutIdx + 3) * sizeof(uint64_t));
789   }
790 
791   return sampleprof_error::success;
792 }
793 
794 std::error_code SampleProfileWriterExtBinaryBase::writeHeader(
795     const SampleProfileMap &ProfileMap) {
796   auto &OS = *OutputStream;
797   FileStart = OS.tell();
798   writeMagicIdent(Format);
799 
800   allocSecHdrTable();
801   return sampleprof_error::success;
802 }
803 
804 std::error_code SampleProfileWriterBinary::writeSummary() {
805   auto &OS = *OutputStream;
806   encodeULEB128(Summary->getTotalCount(), OS);
807   encodeULEB128(Summary->getMaxCount(), OS);
808   encodeULEB128(Summary->getMaxFunctionCount(), OS);
809   encodeULEB128(Summary->getNumCounts(), OS);
810   encodeULEB128(Summary->getNumFunctions(), OS);
811   ArrayRef<ProfileSummaryEntry> Entries = Summary->getDetailedSummary();
812   encodeULEB128(Entries.size(), OS);
813   for (auto Entry : Entries) {
814     encodeULEB128(Entry.Cutoff, OS);
815     encodeULEB128(Entry.MinCount, OS);
816     encodeULEB128(Entry.NumCounts, OS);
817   }
818   return sampleprof_error::success;
819 }
820 std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
821   auto &OS = *OutputStream;
822   if (std::error_code EC = writeContextIdx(S.getContext()))
823     return EC;
824 
825   encodeULEB128(S.getTotalSamples(), OS);
826 
827   // Emit all the body samples.
828   encodeULEB128(S.getBodySamples().size(), OS);
829   for (const auto &I : S.getBodySamples()) {
830     LineLocation Loc = I.first;
831     const SampleRecord &Sample = I.second;
832     Loc.serialize(OS);
833     Sample.serialize(OS, getNameTable());
834   }
835 
836   // Recursively emit all the callsite samples.
837   uint64_t NumCallsites = 0;
838   for (const auto &J : S.getCallsiteSamples())
839     NumCallsites += J.second.size();
840   encodeULEB128(NumCallsites, OS);
841   for (const auto &[Loc, CalleeFunctionSampleMap] : S.getCallsiteSamples())
842     for (const auto &FunctionSample :
843          llvm::make_second_range(CalleeFunctionSampleMap)) {
844       Loc.serialize(OS);
845       if (std::error_code EC = writeBody(FunctionSample))
846         return EC;
847     }
848 
849   return sampleprof_error::success;
850 }
851 
852 /// Write samples of a top-level function to a binary file.
853 ///
854 /// \returns true if the samples were written successfully, false otherwise.
855 std::error_code
856 SampleProfileWriterBinary::writeSample(const FunctionSamples &S) {
857   encodeULEB128(S.getHeadSamples(), *OutputStream);
858   return writeBody(S);
859 }
860 
861 /// Create a sample profile file writer based on the specified format.
862 ///
863 /// \param Filename The file to create.
864 ///
865 /// \param Format Encoding format for the profile file.
866 ///
867 /// \returns an error code indicating the status of the created writer.
868 ErrorOr<std::unique_ptr<SampleProfileWriter>>
869 SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
870   std::error_code EC;
871   std::unique_ptr<raw_ostream> OS;
872   if (Format == SPF_Binary || Format == SPF_Ext_Binary)
873     OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None));
874   else
875     OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_TextWithCRLF));
876   if (EC)
877     return EC;
878 
879   return create(OS, Format);
880 }
881 
882 /// Create a sample profile stream writer based on the specified format.
883 ///
884 /// \param OS The output stream to store the profile data to.
885 ///
886 /// \param Format Encoding format for the profile file.
887 ///
888 /// \returns an error code indicating the status of the created writer.
889 ErrorOr<std::unique_ptr<SampleProfileWriter>>
890 SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
891                             SampleProfileFormat Format) {
892   std::error_code EC;
893   std::unique_ptr<SampleProfileWriter> Writer;
894 
895   // Currently only Text and Extended Binary format are supported for CSSPGO.
896   if ((FunctionSamples::ProfileIsCS || FunctionSamples::ProfileIsProbeBased) &&
897       Format == SPF_Binary)
898     return sampleprof_error::unsupported_writing_format;
899 
900   if (Format == SPF_Binary)
901     Writer.reset(new SampleProfileWriterRawBinary(OS));
902   else if (Format == SPF_Ext_Binary)
903     Writer.reset(new SampleProfileWriterExtBinary(OS));
904   else if (Format == SPF_Text)
905     Writer.reset(new SampleProfileWriterText(OS));
906   else if (Format == SPF_GCC)
907     EC = sampleprof_error::unsupported_writing_format;
908   else
909     EC = sampleprof_error::unrecognized_format;
910 
911   if (EC)
912     return EC;
913 
914   Writer->Format = Format;
915   return std::move(Writer);
916 }
917 
918 void SampleProfileWriter::computeSummary(const SampleProfileMap &ProfileMap) {
919   SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
920   Summary = Builder.computeSummaryForProfiles(ProfileMap);
921 }
922