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