xref: /llvm-project/llvm/lib/ProfileData/SampleProfWriter.cpp (revision 4f1b20f023626a2ae9aab627e918974ce81199fe)
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     if (Loc.Discriminator == 0)
584       OS << Loc.LineOffset << ": ";
585     else
586       OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
587 
588     OS << Sample.getSamples();
589 
590     for (const auto &J : Sample.getSortedCallTargets())
591       OS << " " << J.first << ":" << J.second;
592     OS << "\n";
593     LineCount++;
594   }
595 
596   SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples(
597       S.getCallsiteSamples());
598   Indent += 1;
599   for (const auto &I : SortedCallsiteSamples.get())
600     for (const auto &FS : I->second) {
601       LineLocation Loc = I->first;
602       const FunctionSamples &CalleeSamples = FS.second;
603       OS.indent(Indent);
604       if (Loc.Discriminator == 0)
605         OS << Loc.LineOffset << ": ";
606       else
607         OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
608       if (std::error_code EC = writeSample(CalleeSamples))
609         return EC;
610     }
611   Indent -= 1;
612 
613   if (FunctionSamples::ProfileIsProbeBased) {
614     OS.indent(Indent + 1);
615     OS << "!CFGChecksum: " << S.getFunctionHash() << "\n";
616     LineCount++;
617   }
618 
619   if (S.getContext().getAllAttributes()) {
620     OS.indent(Indent + 1);
621     OS << "!Attributes: " << S.getContext().getAllAttributes() << "\n";
622     LineCount++;
623   }
624 
625   if (Indent == 0 && MarkFlatProfiles && S.getCallsiteSamples().size() == 0)
626     OS << " !Flat\n";
627 
628   return sampleprof_error::success;
629 }
630 
631 std::error_code
632 SampleProfileWriterBinary::writeContextIdx(const SampleContext &Context) {
633   assert(!Context.hasContext() && "cs profile is not supported");
634   return writeNameIdx(Context.getFunction());
635 }
636 
637 std::error_code SampleProfileWriterBinary::writeNameIdx(FunctionId FName) {
638   auto &NTable = getNameTable();
639   const auto &Ret = NTable.find(FName);
640   if (Ret == NTable.end())
641     return sampleprof_error::truncated_name_table;
642   encodeULEB128(Ret->second, *OutputStream);
643   return sampleprof_error::success;
644 }
645 
646 void SampleProfileWriterBinary::addName(FunctionId FName) {
647   auto &NTable = getNameTable();
648   NTable.insert(std::make_pair(FName, 0));
649 }
650 
651 void SampleProfileWriterBinary::addContext(const SampleContext &Context) {
652   addName(Context.getFunction());
653 }
654 
655 void SampleProfileWriterBinary::addNames(const FunctionSamples &S) {
656   // Add all the names in indirect call targets.
657   for (const auto &I : S.getBodySamples()) {
658     const SampleRecord &Sample = I.second;
659     for (const auto &J : Sample.getCallTargets())
660       addName(J.first);
661   }
662 
663   // Recursively add all the names for inlined callsites.
664   for (const auto &J : S.getCallsiteSamples())
665     for (const auto &FS : J.second) {
666       const FunctionSamples &CalleeSamples = FS.second;
667       addName(CalleeSamples.getFunction());
668       addNames(CalleeSamples);
669     }
670 }
671 
672 void SampleProfileWriterExtBinaryBase::addContext(
673     const SampleContext &Context) {
674   if (Context.hasContext()) {
675     for (auto &Callsite : Context.getContextFrames())
676       SampleProfileWriterBinary::addName(Callsite.Func);
677     CSNameTable.insert(std::make_pair(Context, 0));
678   } else {
679     SampleProfileWriterBinary::addName(Context.getFunction());
680   }
681 }
682 
683 void SampleProfileWriterBinary::stablizeNameTable(
684     MapVector<FunctionId, uint32_t> &NameTable, std::set<FunctionId> &V) {
685   // Sort the names to make NameTable deterministic.
686   for (const auto &I : NameTable)
687     V.insert(I.first);
688   int i = 0;
689   for (const FunctionId &N : V)
690     NameTable[N] = i++;
691 }
692 
693 std::error_code SampleProfileWriterBinary::writeNameTable() {
694   auto &OS = *OutputStream;
695   std::set<FunctionId> V;
696   stablizeNameTable(NameTable, V);
697 
698   // Write out the name table.
699   encodeULEB128(NameTable.size(), OS);
700   for (auto N : V) {
701     OS << N;
702     encodeULEB128(0, OS);
703   }
704   return sampleprof_error::success;
705 }
706 
707 std::error_code
708 SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) {
709   auto &OS = *OutputStream;
710   // Write file magic identifier.
711   encodeULEB128(SPMagic(Format), OS);
712   encodeULEB128(SPVersion(), OS);
713   return sampleprof_error::success;
714 }
715 
716 std::error_code
717 SampleProfileWriterBinary::writeHeader(const SampleProfileMap &ProfileMap) {
718   // When calling write on a different profile map, existing names should be
719   // cleared.
720   NameTable.clear();
721 
722   writeMagicIdent(Format);
723 
724   computeSummary(ProfileMap);
725   if (auto EC = writeSummary())
726     return EC;
727 
728   // Generate the name table for all the functions referenced in the profile.
729   for (const auto &I : ProfileMap) {
730     addContext(I.second.getContext());
731     addNames(I.second);
732   }
733 
734   writeNameTable();
735   return sampleprof_error::success;
736 }
737 
738 void SampleProfileWriterExtBinaryBase::setToCompressAllSections() {
739   for (auto &Entry : SectionHdrLayout)
740     addSecFlag(Entry, SecCommonFlags::SecFlagCompress);
741 }
742 
743 void SampleProfileWriterExtBinaryBase::setToCompressSection(SecType Type) {
744   addSectionFlag(Type, SecCommonFlags::SecFlagCompress);
745 }
746 
747 void SampleProfileWriterExtBinaryBase::allocSecHdrTable() {
748   support::endian::Writer Writer(*OutputStream, llvm::endianness::little);
749 
750   Writer.write(static_cast<uint64_t>(SectionHdrLayout.size()));
751   SecHdrTableOffset = OutputStream->tell();
752   for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) {
753     Writer.write(static_cast<uint64_t>(-1));
754     Writer.write(static_cast<uint64_t>(-1));
755     Writer.write(static_cast<uint64_t>(-1));
756     Writer.write(static_cast<uint64_t>(-1));
757   }
758 }
759 
760 std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() {
761   assert(SecHdrTable.size() == SectionHdrLayout.size() &&
762          "SecHdrTable entries doesn't match SectionHdrLayout");
763   SmallVector<uint32_t, 16> IndexMap(SecHdrTable.size(), -1);
764   for (uint32_t TableIdx = 0; TableIdx < SecHdrTable.size(); TableIdx++) {
765     IndexMap[SecHdrTable[TableIdx].LayoutIndex] = TableIdx;
766   }
767 
768   // Write the section header table in the order specified in
769   // SectionHdrLayout. SectionHdrLayout specifies the sections
770   // order in which profile reader expect to read, so the section
771   // header table should be written in the order in SectionHdrLayout.
772   // Note that the section order in SecHdrTable may be different
773   // from the order in SectionHdrLayout, for example, SecFuncOffsetTable
774   // needs to be computed after SecLBRProfile (the order in SecHdrTable),
775   // but it needs to be read before SecLBRProfile (the order in
776   // SectionHdrLayout). So we use IndexMap above to switch the order.
777   support::endian::SeekableWriter Writer(
778       static_cast<raw_pwrite_stream &>(*OutputStream),
779       llvm::endianness::little);
780   for (uint32_t LayoutIdx = 0; LayoutIdx < SectionHdrLayout.size();
781        LayoutIdx++) {
782     assert(IndexMap[LayoutIdx] < SecHdrTable.size() &&
783            "Incorrect LayoutIdx in SecHdrTable");
784     auto Entry = SecHdrTable[IndexMap[LayoutIdx]];
785     Writer.pwrite(static_cast<uint64_t>(Entry.Type),
786                   SecHdrTableOffset + 4 * LayoutIdx * sizeof(uint64_t));
787     Writer.pwrite(static_cast<uint64_t>(Entry.Flags),
788                   SecHdrTableOffset + (4 * LayoutIdx + 1) * sizeof(uint64_t));
789     Writer.pwrite(static_cast<uint64_t>(Entry.Offset),
790                   SecHdrTableOffset + (4 * LayoutIdx + 2) * sizeof(uint64_t));
791     Writer.pwrite(static_cast<uint64_t>(Entry.Size),
792                   SecHdrTableOffset + (4 * LayoutIdx + 3) * sizeof(uint64_t));
793   }
794 
795   return sampleprof_error::success;
796 }
797 
798 std::error_code SampleProfileWriterExtBinaryBase::writeHeader(
799     const SampleProfileMap &ProfileMap) {
800   auto &OS = *OutputStream;
801   FileStart = OS.tell();
802   writeMagicIdent(Format);
803 
804   allocSecHdrTable();
805   return sampleprof_error::success;
806 }
807 
808 std::error_code SampleProfileWriterBinary::writeSummary() {
809   auto &OS = *OutputStream;
810   encodeULEB128(Summary->getTotalCount(), OS);
811   encodeULEB128(Summary->getMaxCount(), OS);
812   encodeULEB128(Summary->getMaxFunctionCount(), OS);
813   encodeULEB128(Summary->getNumCounts(), OS);
814   encodeULEB128(Summary->getNumFunctions(), OS);
815   ArrayRef<ProfileSummaryEntry> Entries = Summary->getDetailedSummary();
816   encodeULEB128(Entries.size(), OS);
817   for (auto Entry : Entries) {
818     encodeULEB128(Entry.Cutoff, OS);
819     encodeULEB128(Entry.MinCount, OS);
820     encodeULEB128(Entry.NumCounts, OS);
821   }
822   return sampleprof_error::success;
823 }
824 std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
825   auto &OS = *OutputStream;
826   if (std::error_code EC = writeContextIdx(S.getContext()))
827     return EC;
828 
829   encodeULEB128(S.getTotalSamples(), OS);
830 
831   // Emit all the body samples.
832   encodeULEB128(S.getBodySamples().size(), OS);
833   for (const auto &I : S.getBodySamples()) {
834     LineLocation Loc = I.first;
835     const SampleRecord &Sample = I.second;
836     encodeULEB128(Loc.LineOffset, OS);
837     encodeULEB128(Loc.Discriminator, OS);
838     encodeULEB128(Sample.getSamples(), OS);
839     encodeULEB128(Sample.getCallTargets().size(), OS);
840     for (const auto &J : Sample.getSortedCallTargets()) {
841       FunctionId Callee = J.first;
842       uint64_t CalleeSamples = J.second;
843       if (std::error_code EC = writeNameIdx(Callee))
844         return EC;
845       encodeULEB128(CalleeSamples, OS);
846     }
847   }
848 
849   // Recursively emit all the callsite samples.
850   uint64_t NumCallsites = 0;
851   for (const auto &J : S.getCallsiteSamples())
852     NumCallsites += J.second.size();
853   encodeULEB128(NumCallsites, OS);
854   for (const auto &J : S.getCallsiteSamples())
855     for (const auto &FS : J.second) {
856       LineLocation Loc = J.first;
857       const FunctionSamples &CalleeSamples = FS.second;
858       encodeULEB128(Loc.LineOffset, OS);
859       encodeULEB128(Loc.Discriminator, OS);
860       if (std::error_code EC = writeBody(CalleeSamples))
861         return EC;
862     }
863 
864   return sampleprof_error::success;
865 }
866 
867 /// Write samples of a top-level function to a binary file.
868 ///
869 /// \returns true if the samples were written successfully, false otherwise.
870 std::error_code
871 SampleProfileWriterBinary::writeSample(const FunctionSamples &S) {
872   encodeULEB128(S.getHeadSamples(), *OutputStream);
873   return writeBody(S);
874 }
875 
876 /// Create a sample profile file writer based on the specified format.
877 ///
878 /// \param Filename The file to create.
879 ///
880 /// \param Format Encoding format for the profile file.
881 ///
882 /// \returns an error code indicating the status of the created writer.
883 ErrorOr<std::unique_ptr<SampleProfileWriter>>
884 SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
885   std::error_code EC;
886   std::unique_ptr<raw_ostream> OS;
887   if (Format == SPF_Binary || Format == SPF_Ext_Binary)
888     OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None));
889   else
890     OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_TextWithCRLF));
891   if (EC)
892     return EC;
893 
894   return create(OS, Format);
895 }
896 
897 /// Create a sample profile stream writer based on the specified format.
898 ///
899 /// \param OS The output stream to store the profile data to.
900 ///
901 /// \param Format Encoding format for the profile file.
902 ///
903 /// \returns an error code indicating the status of the created writer.
904 ErrorOr<std::unique_ptr<SampleProfileWriter>>
905 SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
906                             SampleProfileFormat Format) {
907   std::error_code EC;
908   std::unique_ptr<SampleProfileWriter> Writer;
909 
910   // Currently only Text and Extended Binary format are supported for CSSPGO.
911   if ((FunctionSamples::ProfileIsCS || FunctionSamples::ProfileIsProbeBased) &&
912       Format == SPF_Binary)
913     return sampleprof_error::unsupported_writing_format;
914 
915   if (Format == SPF_Binary)
916     Writer.reset(new SampleProfileWriterRawBinary(OS));
917   else if (Format == SPF_Ext_Binary)
918     Writer.reset(new SampleProfileWriterExtBinary(OS));
919   else if (Format == SPF_Text)
920     Writer.reset(new SampleProfileWriterText(OS));
921   else if (Format == SPF_GCC)
922     EC = sampleprof_error::unsupported_writing_format;
923   else
924     EC = sampleprof_error::unrecognized_format;
925 
926   if (EC)
927     return EC;
928 
929   Writer->Format = Format;
930   return std::move(Writer);
931 }
932 
933 void SampleProfileWriter::computeSummary(const SampleProfileMap &ProfileMap) {
934   SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
935   Summary = Builder.computeSummaryForProfiles(ProfileMap);
936 }
937