1c572e92cSDiego Novillo //===- SampleProfWriter.cpp - Write LLVM sample profile data --------------===//
2c572e92cSDiego Novillo //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c572e92cSDiego Novillo //
7c572e92cSDiego Novillo //===----------------------------------------------------------------------===//
8c572e92cSDiego Novillo //
9c572e92cSDiego Novillo // This file implements the class that writes LLVM sample profiles. It
10c572e92cSDiego Novillo // supports two file formats: text and binary. The textual representation
11c572e92cSDiego Novillo // is useful for debugging and testing purposes. The binary representation
12c572e92cSDiego Novillo // is more compact, resulting in smaller file sizes. However, they can
13c572e92cSDiego Novillo // both be used interchangeably.
14c572e92cSDiego Novillo //
15c572e92cSDiego Novillo // See lib/ProfileData/SampleProfReader.cpp for documentation on each of the
16c572e92cSDiego Novillo // supported formats.
17c572e92cSDiego Novillo //
18c572e92cSDiego Novillo //===----------------------------------------------------------------------===//
19c572e92cSDiego Novillo 
206bda14b3SChandler Carruth #include "llvm/ProfileData/SampleProfWriter.h"
21e78d131aSEugene Zelenko #include "llvm/ADT/StringRef.h"
2221b1ad03SWei Mi #include "llvm/ADT/StringSet.h"
23e78d131aSEugene Zelenko #include "llvm/ProfileData/ProfileCommon.h"
24e78d131aSEugene Zelenko #include "llvm/ProfileData/SampleProf.h"
25b523790aSWei Mi #include "llvm/Support/Compression.h"
266a14325dSWei Mi #include "llvm/Support/Endian.h"
276a14325dSWei Mi #include "llvm/Support/EndianStream.h"
28c572e92cSDiego Novillo #include "llvm/Support/ErrorOr.h"
29e78d131aSEugene Zelenko #include "llvm/Support/FileSystem.h"
30c572e92cSDiego Novillo #include "llvm/Support/LEB128.h"
31a0c0857eSWei Mi #include "llvm/Support/MD5.h"
32e78d131aSEugene Zelenko #include "llvm/Support/raw_ostream.h"
33e78d131aSEugene Zelenko #include <algorithm>
34e78d131aSEugene Zelenko #include <cstdint>
35e78d131aSEugene Zelenko #include <memory>
368d1c983fSDehao Chen #include <set>
37e78d131aSEugene Zelenko #include <system_error>
38e78d131aSEugene Zelenko #include <utility>
39e78d131aSEugene Zelenko #include <vector>
40c572e92cSDiego Novillo 
41c572e92cSDiego Novillo using namespace llvm;
42e78d131aSEugene Zelenko using namespace sampleprof;
43c572e92cSDiego Novillo 
44be907324SWei Mi std::error_code SampleProfileWriter::writeFuncProfiles(
45be907324SWei Mi     const StringMap<FunctionSamples> &ProfileMap) {
468d1c983fSDehao Chen   // Sort the ProfileMap by total samples.
478d1c983fSDehao Chen   typedef std::pair<StringRef, const FunctionSamples *> NameFunctionSamples;
488d1c983fSDehao Chen   std::vector<NameFunctionSamples> V;
498d1c983fSDehao Chen   for (const auto &I : ProfileMap)
508d1c983fSDehao Chen     V.push_back(std::make_pair(I.getKey(), &I.second));
518d1c983fSDehao Chen 
52efd94c56SFangrui Song   llvm::stable_sort(
53efd94c56SFangrui Song       V, [](const NameFunctionSamples &A, const NameFunctionSamples &B) {
548d1c983fSDehao Chen         if (A.second->getTotalSamples() == B.second->getTotalSamples())
558d1c983fSDehao Chen           return A.first > B.first;
568d1c983fSDehao Chen         return A.second->getTotalSamples() > B.second->getTotalSamples();
578d1c983fSDehao Chen       });
588d1c983fSDehao Chen 
598d1c983fSDehao Chen   for (const auto &I : V) {
60be907324SWei Mi     if (std::error_code EC = writeSample(*I.second))
618d1c983fSDehao Chen       return EC;
628d1c983fSDehao Chen   }
638d1c983fSDehao Chen   return sampleprof_error::success;
648d1c983fSDehao Chen }
658d1c983fSDehao Chen 
66be907324SWei Mi std::error_code
67be907324SWei Mi SampleProfileWriter::write(const StringMap<FunctionSamples> &ProfileMap) {
68be907324SWei Mi   if (std::error_code EC = writeHeader(ProfileMap))
69be907324SWei Mi     return EC;
70be907324SWei Mi 
71be907324SWei Mi   if (std::error_code EC = writeFuncProfiles(ProfileMap))
72be907324SWei Mi     return EC;
73be907324SWei Mi 
74be907324SWei Mi   return sampleprof_error::success;
75be907324SWei Mi }
76be907324SWei Mi 
77b523790aSWei Mi /// Return the current position and prepare to use it as the start
78a906e3ecSWei Mi /// position of a section given the section type \p Type and its position
79a906e3ecSWei Mi /// \p LayoutIdx in SectionHdrLayout.
80a906e3ecSWei Mi uint64_t
81a906e3ecSWei Mi SampleProfileWriterExtBinaryBase::markSectionStart(SecType Type,
82a906e3ecSWei Mi                                                    uint32_t LayoutIdx) {
83b523790aSWei Mi   uint64_t SectionStart = OutputStream->tell();
84a906e3ecSWei Mi   assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range");
85a906e3ecSWei Mi   const auto &Entry = SectionHdrLayout[LayoutIdx];
86a906e3ecSWei Mi   assert(Entry.Type == Type && "Unexpected section type");
87b523790aSWei Mi   // Use LocalBuf as a temporary output for writting data.
88ebad6788SWei Mi   if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress))
89b523790aSWei Mi     LocalBufStream.swap(OutputStream);
90b523790aSWei Mi   return SectionStart;
91b523790aSWei Mi }
92b523790aSWei Mi 
93b523790aSWei Mi std::error_code SampleProfileWriterExtBinaryBase::compressAndOutput() {
94b523790aSWei Mi   if (!llvm::zlib::isAvailable())
95b523790aSWei Mi     return sampleprof_error::zlib_unavailable;
96b523790aSWei Mi   std::string &UncompressedStrings =
97b523790aSWei Mi       static_cast<raw_string_ostream *>(LocalBufStream.get())->str();
98b523790aSWei Mi   if (UncompressedStrings.size() == 0)
99b523790aSWei Mi     return sampleprof_error::success;
100b523790aSWei Mi   auto &OS = *OutputStream;
101b523790aSWei Mi   SmallString<128> CompressedStrings;
102b523790aSWei Mi   llvm::Error E = zlib::compress(UncompressedStrings, CompressedStrings,
103b523790aSWei Mi                                  zlib::BestSizeCompression);
104b523790aSWei Mi   if (E)
105b523790aSWei Mi     return sampleprof_error::compress_failed;
106b523790aSWei Mi   encodeULEB128(UncompressedStrings.size(), OS);
107b523790aSWei Mi   encodeULEB128(CompressedStrings.size(), OS);
108b523790aSWei Mi   OS << CompressedStrings.str();
109b523790aSWei Mi   UncompressedStrings.clear();
110b523790aSWei Mi   return sampleprof_error::success;
111b523790aSWei Mi }
112b523790aSWei Mi 
113a906e3ecSWei Mi /// Add a new section into section header table given the section type
114a906e3ecSWei Mi /// \p Type, its position \p LayoutIdx in SectionHdrLayout and the
115a906e3ecSWei Mi /// location \p SectionStart where the section should be written to.
116a906e3ecSWei Mi std::error_code SampleProfileWriterExtBinaryBase::addNewSection(
117a906e3ecSWei Mi     SecType Type, uint32_t LayoutIdx, uint64_t SectionStart) {
118a906e3ecSWei Mi   assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range");
119a906e3ecSWei Mi   const auto &Entry = SectionHdrLayout[LayoutIdx];
120a906e3ecSWei Mi   assert(Entry.Type == Type && "Unexpected section type");
121ebad6788SWei Mi   if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress)) {
122b523790aSWei Mi     LocalBufStream.swap(OutputStream);
123b523790aSWei Mi     if (std::error_code EC = compressAndOutput())
124b523790aSWei Mi       return EC;
125b523790aSWei Mi   }
126b523790aSWei Mi   SecHdrTable.push_back({Type, Entry.Flags, SectionStart - FileStart,
127a906e3ecSWei Mi                          OutputStream->tell() - SectionStart, LayoutIdx});
128b523790aSWei Mi   return sampleprof_error::success;
129be907324SWei Mi }
130be907324SWei Mi 
131be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::write(
132be907324SWei Mi     const StringMap<FunctionSamples> &ProfileMap) {
133be907324SWei Mi   if (std::error_code EC = writeHeader(ProfileMap))
134be907324SWei Mi     return EC;
135be907324SWei Mi 
136b523790aSWei Mi   std::string LocalBuf;
137b523790aSWei Mi   LocalBufStream = std::make_unique<raw_string_ostream>(LocalBuf);
138be907324SWei Mi   if (std::error_code EC = writeSections(ProfileMap))
139be907324SWei Mi     return EC;
140be907324SWei Mi 
141be907324SWei Mi   if (std::error_code EC = writeSecHdrTable())
142be907324SWei Mi     return EC;
143be907324SWei Mi 
144be907324SWei Mi   return sampleprof_error::success;
145be907324SWei Mi }
146be907324SWei Mi 
14709dcfe68SWei Mi std::error_code
14893953d41SWei Mi SampleProfileWriterExtBinaryBase::writeSample(const FunctionSamples &S) {
14909dcfe68SWei Mi   uint64_t Offset = OutputStream->tell();
1507e99bddfSHongtao Yu   StringRef Name = S.getNameWithContext(true);
15109dcfe68SWei Mi   FuncOffsetTable[Name] = Offset - SecLBRProfileStart;
15209dcfe68SWei Mi   encodeULEB128(S.getHeadSamples(), *OutputStream);
15309dcfe68SWei Mi   return writeBody(S);
15409dcfe68SWei Mi }
15509dcfe68SWei Mi 
15693953d41SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeFuncOffsetTable() {
15709dcfe68SWei Mi   auto &OS = *OutputStream;
15809dcfe68SWei Mi 
15909dcfe68SWei Mi   // Write out the table size.
16009dcfe68SWei Mi   encodeULEB128(FuncOffsetTable.size(), OS);
16109dcfe68SWei Mi 
16209dcfe68SWei Mi   // Write out FuncOffsetTable.
16309dcfe68SWei Mi   for (auto entry : FuncOffsetTable) {
16409dcfe68SWei Mi     writeNameIdx(entry.first);
16509dcfe68SWei Mi     encodeULEB128(entry.second, OS);
16609dcfe68SWei Mi   }
167a906e3ecSWei Mi   FuncOffsetTable.clear();
16809dcfe68SWei Mi   return sampleprof_error::success;
16909dcfe68SWei Mi }
17009dcfe68SWei Mi 
171ac068e01SHongtao Yu std::error_code SampleProfileWriterExtBinaryBase::writeFuncMetadata(
172ac068e01SHongtao Yu     const StringMap<FunctionSamples> &Profiles) {
173ac068e01SHongtao Yu   if (!FunctionSamples::ProfileIsProbeBased)
174ac068e01SHongtao Yu     return sampleprof_error::success;
175ac068e01SHongtao Yu   auto &OS = *OutputStream;
176ac068e01SHongtao Yu   for (const auto &Entry : Profiles) {
177ac068e01SHongtao Yu     writeNameIdx(Entry.first());
178ac068e01SHongtao Yu     encodeULEB128(Entry.second.getFunctionHash(), OS);
179ac068e01SHongtao Yu   }
180ac068e01SHongtao Yu   return sampleprof_error::success;
181ac068e01SHongtao Yu }
182ac068e01SHongtao Yu 
18393953d41SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeNameTable() {
184ebad6788SWei Mi   if (!UseMD5)
185ebad6788SWei Mi     return SampleProfileWriterBinary::writeNameTable();
186ebad6788SWei Mi 
187ebad6788SWei Mi   auto &OS = *OutputStream;
188ebad6788SWei Mi   std::set<StringRef> V;
189ebad6788SWei Mi   stablizeNameTable(V);
190ebad6788SWei Mi 
19164e76853SWei Mi   // Write out the MD5 name table. We wrote unencoded MD5 so reader can
19264e76853SWei Mi   // retrieve the name using the name index without having to read the
19364e76853SWei Mi   // whole name table.
194ebad6788SWei Mi   encodeULEB128(NameTable.size(), OS);
19564e76853SWei Mi   support::endian::Writer Writer(OS, support::little);
19664e76853SWei Mi   for (auto N : V)
19764e76853SWei Mi     Writer.write(MD5Hash(N));
198ebad6788SWei Mi   return sampleprof_error::success;
199ebad6788SWei Mi }
200ebad6788SWei Mi 
20193953d41SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeNameTableSection(
202be907324SWei Mi     const StringMap<FunctionSamples> &ProfileMap) {
203be907324SWei Mi   for (const auto &I : ProfileMap) {
204be907324SWei Mi     addName(I.first());
205be907324SWei Mi     addNames(I.second);
206be907324SWei Mi   }
207ee35784aSWei Mi 
208ee35784aSWei Mi   // If NameTable contains ".__uniq." suffix, set SecFlagUniqSuffix flag
209ee35784aSWei Mi   // so compiler won't strip the suffix during profile matching after
210ee35784aSWei Mi   // seeing the flag in the profile.
211ee35784aSWei Mi   for (const auto &I : NameTable) {
212ee35784aSWei Mi     if (I.first.find(FunctionSamples::UniqSuffix) != StringRef::npos) {
213ee35784aSWei Mi       addSectionFlag(SecNameTable, SecNameTableFlags::SecFlagUniqSuffix);
214ee35784aSWei Mi       break;
215ee35784aSWei Mi     }
216ee35784aSWei Mi   }
217ee35784aSWei Mi 
21893953d41SWei Mi   if (auto EC = writeNameTable())
219b523790aSWei Mi     return EC;
22093953d41SWei Mi   return sampleprof_error::success;
22193953d41SWei Mi }
222be907324SWei Mi 
22393953d41SWei Mi std::error_code
22493953d41SWei Mi SampleProfileWriterExtBinaryBase::writeProfileSymbolListSection() {
225798e59b8SWei Mi   if (ProfSymList && ProfSymList->size() > 0)
226798e59b8SWei Mi     if (std::error_code EC = ProfSymList->write(*OutputStream))
227798e59b8SWei Mi       return EC;
228be907324SWei Mi 
22993953d41SWei Mi   return sampleprof_error::success;
23093953d41SWei Mi }
23109dcfe68SWei Mi 
23293953d41SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeOneSection(
233a906e3ecSWei Mi     SecType Type, uint32_t LayoutIdx,
234a906e3ecSWei Mi     const StringMap<FunctionSamples> &ProfileMap) {
23593953d41SWei Mi   // The setting of SecFlagCompress should happen before markSectionStart.
23693953d41SWei Mi   if (Type == SecProfileSymbolList && ProfSymList && ProfSymList->toCompress())
23793953d41SWei Mi     setToCompressSection(SecProfileSymbolList);
238ac068e01SHongtao Yu   if (Type == SecFuncMetadata && FunctionSamples::ProfileIsProbeBased)
239ac068e01SHongtao Yu     addSectionFlag(SecFuncMetadata, SecFuncMetadataFlags::SecFlagIsProbeBased);
240*a5d30421SWenlei He   if (Type == SecProfSummary && FunctionSamples::ProfileIsCS)
241*a5d30421SWenlei He     addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagFullContext);
24293953d41SWei Mi 
243a906e3ecSWei Mi   uint64_t SectionStart = markSectionStart(Type, LayoutIdx);
24493953d41SWei Mi   switch (Type) {
24593953d41SWei Mi   case SecProfSummary:
24693953d41SWei Mi     computeSummary(ProfileMap);
24793953d41SWei Mi     if (auto EC = writeSummary())
24893953d41SWei Mi       return EC;
24993953d41SWei Mi     break;
25093953d41SWei Mi   case SecNameTable:
25193953d41SWei Mi     if (auto EC = writeNameTableSection(ProfileMap))
25293953d41SWei Mi       return EC;
25393953d41SWei Mi     break;
25493953d41SWei Mi   case SecLBRProfile:
25593953d41SWei Mi     SecLBRProfileStart = OutputStream->tell();
25693953d41SWei Mi     if (std::error_code EC = writeFuncProfiles(ProfileMap))
25793953d41SWei Mi       return EC;
25893953d41SWei Mi     break;
25993953d41SWei Mi   case SecFuncOffsetTable:
26093953d41SWei Mi     if (auto EC = writeFuncOffsetTable())
26193953d41SWei Mi       return EC;
26293953d41SWei Mi     break;
263ac068e01SHongtao Yu   case SecFuncMetadata:
264ac068e01SHongtao Yu     if (std::error_code EC = writeFuncMetadata(ProfileMap))
265ac068e01SHongtao Yu       return EC;
266ac068e01SHongtao Yu     break;
26793953d41SWei Mi   case SecProfileSymbolList:
26893953d41SWei Mi     if (auto EC = writeProfileSymbolListSection())
26993953d41SWei Mi       return EC;
27093953d41SWei Mi     break;
27193953d41SWei Mi   default:
27293953d41SWei Mi     if (auto EC = writeCustomSection(Type))
27393953d41SWei Mi       return EC;
27493953d41SWei Mi     break;
27593953d41SWei Mi   }
276a906e3ecSWei Mi   if (std::error_code EC = addNewSection(Type, LayoutIdx, SectionStart))
27793953d41SWei Mi     return EC;
27893953d41SWei Mi   return sampleprof_error::success;
27993953d41SWei Mi }
28093953d41SWei Mi 
28121b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeDefaultLayout(
28293953d41SWei Mi     const StringMap<FunctionSamples> &ProfileMap) {
283a906e3ecSWei Mi   // The const indices passed to writeOneSection below are specifying the
284a906e3ecSWei Mi   // positions of the sections in SectionHdrLayout. Look at
285a906e3ecSWei Mi   // initSectionHdrLayout to find out where each section is located in
286a906e3ecSWei Mi   // SectionHdrLayout.
287a906e3ecSWei Mi   if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap))
28893953d41SWei Mi     return EC;
289a906e3ecSWei Mi   if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap))
29093953d41SWei Mi     return EC;
291a906e3ecSWei Mi   if (auto EC = writeOneSection(SecLBRProfile, 3, ProfileMap))
29293953d41SWei Mi     return EC;
293a906e3ecSWei Mi   if (auto EC = writeOneSection(SecProfileSymbolList, 4, ProfileMap))
29493953d41SWei Mi     return EC;
295a906e3ecSWei Mi   if (auto EC = writeOneSection(SecFuncOffsetTable, 2, ProfileMap))
29693953d41SWei Mi     return EC;
297a906e3ecSWei Mi   if (auto EC = writeOneSection(SecFuncMetadata, 5, ProfileMap))
298ac068e01SHongtao Yu     return EC;
299be907324SWei Mi   return sampleprof_error::success;
300be907324SWei Mi }
301be907324SWei Mi 
30221b1ad03SWei Mi static void
30321b1ad03SWei Mi splitProfileMapToTwo(const StringMap<FunctionSamples> &ProfileMap,
30421b1ad03SWei Mi                      StringMap<FunctionSamples> &ContextProfileMap,
30521b1ad03SWei Mi                      StringMap<FunctionSamples> &NoContextProfileMap) {
30621b1ad03SWei Mi   for (const auto &I : ProfileMap) {
30721b1ad03SWei Mi     if (I.second.getCallsiteSamples().size())
30821b1ad03SWei Mi       ContextProfileMap.insert({I.first(), I.second});
30921b1ad03SWei Mi     else
31021b1ad03SWei Mi       NoContextProfileMap.insert({I.first(), I.second});
31121b1ad03SWei Mi   }
31221b1ad03SWei Mi }
31321b1ad03SWei Mi 
31421b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeCtxSplitLayout(
31521b1ad03SWei Mi     const StringMap<FunctionSamples> &ProfileMap) {
31621b1ad03SWei Mi   StringMap<FunctionSamples> ContextProfileMap, NoContextProfileMap;
31721b1ad03SWei Mi   splitProfileMapToTwo(ProfileMap, ContextProfileMap, NoContextProfileMap);
31821b1ad03SWei Mi 
31921b1ad03SWei Mi   if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap))
32021b1ad03SWei Mi     return EC;
32121b1ad03SWei Mi   if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap))
32221b1ad03SWei Mi     return EC;
32321b1ad03SWei Mi   if (auto EC = writeOneSection(SecLBRProfile, 3, ContextProfileMap))
32421b1ad03SWei Mi     return EC;
32521b1ad03SWei Mi   if (auto EC = writeOneSection(SecFuncOffsetTable, 2, ContextProfileMap))
32621b1ad03SWei Mi     return EC;
32721b1ad03SWei Mi   // Mark the section to have no context. Note section flag needs to be set
32821b1ad03SWei Mi   // before writing the section.
32921b1ad03SWei Mi   addSectionFlag(5, SecCommonFlags::SecFlagFlat);
33021b1ad03SWei Mi   if (auto EC = writeOneSection(SecLBRProfile, 5, NoContextProfileMap))
33121b1ad03SWei Mi     return EC;
33221b1ad03SWei Mi   // Mark the section to have no context. Note section flag needs to be set
33321b1ad03SWei Mi   // before writing the section.
33421b1ad03SWei Mi   addSectionFlag(4, SecCommonFlags::SecFlagFlat);
33521b1ad03SWei Mi   if (auto EC = writeOneSection(SecFuncOffsetTable, 4, NoContextProfileMap))
33621b1ad03SWei Mi     return EC;
33721b1ad03SWei Mi   if (auto EC = writeOneSection(SecProfileSymbolList, 6, ProfileMap))
33821b1ad03SWei Mi     return EC;
33921b1ad03SWei Mi   if (auto EC = writeOneSection(SecFuncMetadata, 7, ProfileMap))
34021b1ad03SWei Mi     return EC;
34121b1ad03SWei Mi 
34221b1ad03SWei Mi   return sampleprof_error::success;
34321b1ad03SWei Mi }
34421b1ad03SWei Mi 
34521b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeSections(
34621b1ad03SWei Mi     const StringMap<FunctionSamples> &ProfileMap) {
34721b1ad03SWei Mi   std::error_code EC;
34821b1ad03SWei Mi   if (SecLayout == DefaultLayout)
34921b1ad03SWei Mi     EC = writeDefaultLayout(ProfileMap);
35021b1ad03SWei Mi   else if (SecLayout == CtxSplitLayout)
35121b1ad03SWei Mi     EC = writeCtxSplitLayout(ProfileMap);
35221b1ad03SWei Mi   else
35321b1ad03SWei Mi     llvm_unreachable("Unsupported layout");
35421b1ad03SWei Mi   return EC;
35521b1ad03SWei Mi }
35621b1ad03SWei Mi 
3576a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::write(
3586a14325dSWei Mi     const StringMap<FunctionSamples> &ProfileMap) {
3596a14325dSWei Mi   if (std::error_code EC = SampleProfileWriter::write(ProfileMap))
3606a14325dSWei Mi     return EC;
3616a14325dSWei Mi   if (std::error_code EC = writeFuncOffsetTable())
3626a14325dSWei Mi     return EC;
3636a14325dSWei Mi   return sampleprof_error::success;
3646a14325dSWei Mi }
3656a14325dSWei Mi 
3665f8f34e4SAdrian Prantl /// Write samples to a text file.
3678e415a82SDiego Novillo ///
3688e415a82SDiego Novillo /// Note: it may be tempting to implement this in terms of
369ef548d29SDiego Novillo /// FunctionSamples::print().  Please don't.  The dump functionality is intended
3708e415a82SDiego Novillo /// for debugging and has no specified form.
3718e415a82SDiego Novillo ///
3728e415a82SDiego Novillo /// The format used here is more structured and deliberate because
3738e415a82SDiego Novillo /// it needs to be parsed by the SampleProfileReaderText class.
374be907324SWei Mi std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) {
37551abea74SNathan Slingerland   auto &OS = *OutputStream;
376c3aeabaeSwlei   OS << S.getNameWithContext(true) << ":" << S.getTotalSamples();
377aae1ed8eSDiego Novillo   if (Indent == 0)
378aae1ed8eSDiego Novillo     OS << ":" << S.getHeadSamples();
379aae1ed8eSDiego Novillo   OS << "\n";
380c572e92cSDiego Novillo 
381ef548d29SDiego Novillo   SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples());
382ef548d29SDiego Novillo   for (const auto &I : SortedSamples.get()) {
383ef548d29SDiego Novillo     LineLocation Loc = I->first;
384ef548d29SDiego Novillo     const SampleRecord &Sample = I->second;
385aae1ed8eSDiego Novillo     OS.indent(Indent + 1);
386c572e92cSDiego Novillo     if (Loc.Discriminator == 0)
387c572e92cSDiego Novillo       OS << Loc.LineOffset << ": ";
388c572e92cSDiego Novillo     else
389c572e92cSDiego Novillo       OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
390c572e92cSDiego Novillo 
391c572e92cSDiego Novillo     OS << Sample.getSamples();
392c572e92cSDiego Novillo 
3935adace35SWenlei He     for (const auto &J : Sample.getSortedCallTargets())
3945adace35SWenlei He       OS << " " << J.first << ":" << J.second;
395c572e92cSDiego Novillo     OS << "\n";
396c572e92cSDiego Novillo   }
397c572e92cSDiego Novillo 
3982c7ca9b5SDehao Chen   SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples(
399ef548d29SDiego Novillo       S.getCallsiteSamples());
400aae1ed8eSDiego Novillo   Indent += 1;
4012c7ca9b5SDehao Chen   for (const auto &I : SortedCallsiteSamples.get())
4022c7ca9b5SDehao Chen     for (const auto &FS : I->second) {
40357d1dda5SDehao Chen       LineLocation Loc = I->first;
4042c7ca9b5SDehao Chen       const FunctionSamples &CalleeSamples = FS.second;
405aae1ed8eSDiego Novillo       OS.indent(Indent);
406aae1ed8eSDiego Novillo       if (Loc.Discriminator == 0)
407aae1ed8eSDiego Novillo         OS << Loc.LineOffset << ": ";
408aae1ed8eSDiego Novillo       else
409aae1ed8eSDiego Novillo         OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
410be907324SWei Mi       if (std::error_code EC = writeSample(CalleeSamples))
411760c5a8fSDiego Novillo         return EC;
412aae1ed8eSDiego Novillo     }
413aae1ed8eSDiego Novillo   Indent -= 1;
414aae1ed8eSDiego Novillo 
415ac068e01SHongtao Yu   if (Indent == 0) {
416ac068e01SHongtao Yu     if (FunctionSamples::ProfileIsProbeBased) {
417ac068e01SHongtao Yu       OS.indent(Indent + 1);
418ac068e01SHongtao Yu       OS << "!CFGChecksum: " << S.getFunctionHash() << "\n";
419ac068e01SHongtao Yu     }
420ac068e01SHongtao Yu   }
421ac068e01SHongtao Yu 
422760c5a8fSDiego Novillo   return sampleprof_error::success;
423c572e92cSDiego Novillo }
424c572e92cSDiego Novillo 
425760c5a8fSDiego Novillo std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) {
426760c5a8fSDiego Novillo   const auto &ret = NameTable.find(FName);
427760c5a8fSDiego Novillo   if (ret == NameTable.end())
428760c5a8fSDiego Novillo     return sampleprof_error::truncated_name_table;
42951abea74SNathan Slingerland   encodeULEB128(ret->second, *OutputStream);
430760c5a8fSDiego Novillo   return sampleprof_error::success;
431760c5a8fSDiego Novillo }
432c572e92cSDiego Novillo 
433760c5a8fSDiego Novillo void SampleProfileWriterBinary::addName(StringRef FName) {
4348d1c983fSDehao Chen   NameTable.insert(std::make_pair(FName, 0));
435760c5a8fSDiego Novillo }
436760c5a8fSDiego Novillo 
437760c5a8fSDiego Novillo void SampleProfileWriterBinary::addNames(const FunctionSamples &S) {
438760c5a8fSDiego Novillo   // Add all the names in indirect call targets.
439760c5a8fSDiego Novillo   for (const auto &I : S.getBodySamples()) {
440760c5a8fSDiego Novillo     const SampleRecord &Sample = I.second;
441760c5a8fSDiego Novillo     for (const auto &J : Sample.getCallTargets())
442760c5a8fSDiego Novillo       addName(J.first());
443760c5a8fSDiego Novillo   }
444760c5a8fSDiego Novillo 
445760c5a8fSDiego Novillo   // Recursively add all the names for inlined callsites.
4462c7ca9b5SDehao Chen   for (const auto &J : S.getCallsiteSamples())
4472c7ca9b5SDehao Chen     for (const auto &FS : J.second) {
4482c7ca9b5SDehao Chen       const FunctionSamples &CalleeSamples = FS.second;
44957d1dda5SDehao Chen       addName(CalleeSamples.getName());
450760c5a8fSDiego Novillo       addNames(CalleeSamples);
451760c5a8fSDiego Novillo     }
452760c5a8fSDiego Novillo }
453760c5a8fSDiego Novillo 
454a0c0857eSWei Mi void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) {
455a0c0857eSWei Mi   // Sort the names to make NameTable deterministic.
456a0c0857eSWei Mi   for (const auto &I : NameTable)
457a0c0857eSWei Mi     V.insert(I.first);
458a0c0857eSWei Mi   int i = 0;
459a0c0857eSWei Mi   for (const StringRef &N : V)
460a0c0857eSWei Mi     NameTable[N] = i++;
461a0c0857eSWei Mi }
46251abea74SNathan Slingerland 
463be907324SWei Mi std::error_code SampleProfileWriterBinary::writeNameTable() {
464a0c0857eSWei Mi   auto &OS = *OutputStream;
465a0c0857eSWei Mi   std::set<StringRef> V;
466a0c0857eSWei Mi   stablizeNameTable(V);
467a0c0857eSWei Mi 
468a0c0857eSWei Mi   // Write out the name table.
469a0c0857eSWei Mi   encodeULEB128(NameTable.size(), OS);
470a0c0857eSWei Mi   for (auto N : V) {
471a0c0857eSWei Mi     OS << N;
472a0c0857eSWei Mi     encodeULEB128(0, OS);
473a0c0857eSWei Mi   }
474a0c0857eSWei Mi   return sampleprof_error::success;
475a0c0857eSWei Mi }
476a0c0857eSWei Mi 
4776a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() {
4786a14325dSWei Mi   auto &OS = *OutputStream;
4796a14325dSWei Mi 
4806a14325dSWei Mi   // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable.
4816a14325dSWei Mi   auto &OFS = static_cast<raw_fd_ostream &>(OS);
4826a14325dSWei Mi   uint64_t FuncOffsetTableStart = OS.tell();
4836a14325dSWei Mi   if (OFS.seek(TableOffset) == (uint64_t)-1)
4846a14325dSWei Mi     return sampleprof_error::ostream_seek_unsupported;
4856a14325dSWei Mi   support::endian::Writer Writer(*OutputStream, support::little);
4866a14325dSWei Mi   Writer.write(FuncOffsetTableStart);
4876a14325dSWei Mi   if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1)
4886a14325dSWei Mi     return sampleprof_error::ostream_seek_unsupported;
4896a14325dSWei Mi 
4906a14325dSWei Mi   // Write out the table size.
4916a14325dSWei Mi   encodeULEB128(FuncOffsetTable.size(), OS);
4926a14325dSWei Mi 
4936a14325dSWei Mi   // Write out FuncOffsetTable.
4946a14325dSWei Mi   for (auto entry : FuncOffsetTable) {
4956a14325dSWei Mi     writeNameIdx(entry.first);
4966a14325dSWei Mi     encodeULEB128(entry.second, OS);
4976a14325dSWei Mi   }
4986a14325dSWei Mi   return sampleprof_error::success;
4996a14325dSWei Mi }
5006a14325dSWei Mi 
501a0c0857eSWei Mi std::error_code SampleProfileWriterCompactBinary::writeNameTable() {
502a0c0857eSWei Mi   auto &OS = *OutputStream;
503a0c0857eSWei Mi   std::set<StringRef> V;
504a0c0857eSWei Mi   stablizeNameTable(V);
505a0c0857eSWei Mi 
506a0c0857eSWei Mi   // Write out the name table.
507a0c0857eSWei Mi   encodeULEB128(NameTable.size(), OS);
508a0c0857eSWei Mi   for (auto N : V) {
509a0c0857eSWei Mi     encodeULEB128(MD5Hash(N), OS);
510a0c0857eSWei Mi   }
511a0c0857eSWei Mi   return sampleprof_error::success;
512a0c0857eSWei Mi }
513a0c0857eSWei Mi 
514be907324SWei Mi std::error_code
515be907324SWei Mi SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) {
516a0c0857eSWei Mi   auto &OS = *OutputStream;
517760c5a8fSDiego Novillo   // Write file magic identifier.
518be907324SWei Mi   encodeULEB128(SPMagic(Format), OS);
519a0c0857eSWei Mi   encodeULEB128(SPVersion(), OS);
520a0c0857eSWei Mi   return sampleprof_error::success;
521a0c0857eSWei Mi }
522a0c0857eSWei Mi 
523a0c0857eSWei Mi std::error_code SampleProfileWriterBinary::writeHeader(
524a0c0857eSWei Mi     const StringMap<FunctionSamples> &ProfileMap) {
525be907324SWei Mi   writeMagicIdent(Format);
526760c5a8fSDiego Novillo 
52740ee23dbSEaswaran Raman   computeSummary(ProfileMap);
52840ee23dbSEaswaran Raman   if (auto EC = writeSummary())
52940ee23dbSEaswaran Raman     return EC;
53040ee23dbSEaswaran Raman 
531760c5a8fSDiego Novillo   // Generate the name table for all the functions referenced in the profile.
532760c5a8fSDiego Novillo   for (const auto &I : ProfileMap) {
533760c5a8fSDiego Novillo     addName(I.first());
534760c5a8fSDiego Novillo     addNames(I.second);
535760c5a8fSDiego Novillo   }
536760c5a8fSDiego Novillo 
537a0c0857eSWei Mi   writeNameTable();
538760c5a8fSDiego Novillo   return sampleprof_error::success;
539c572e92cSDiego Novillo }
540c572e92cSDiego Novillo 
541b523790aSWei Mi void SampleProfileWriterExtBinaryBase::setToCompressAllSections() {
54209dcfe68SWei Mi   for (auto &Entry : SectionHdrLayout)
543ebad6788SWei Mi     addSecFlag(Entry, SecCommonFlags::SecFlagCompress);
544b523790aSWei Mi }
545b523790aSWei Mi 
546b523790aSWei Mi void SampleProfileWriterExtBinaryBase::setToCompressSection(SecType Type) {
547ebad6788SWei Mi   addSectionFlag(Type, SecCommonFlags::SecFlagCompress);
548b523790aSWei Mi }
549b523790aSWei Mi 
550be907324SWei Mi void SampleProfileWriterExtBinaryBase::allocSecHdrTable() {
551be907324SWei Mi   support::endian::Writer Writer(*OutputStream, support::little);
552be907324SWei Mi 
55309dcfe68SWei Mi   Writer.write(static_cast<uint64_t>(SectionHdrLayout.size()));
554be907324SWei Mi   SecHdrTableOffset = OutputStream->tell();
55509dcfe68SWei Mi   for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) {
556be907324SWei Mi     Writer.write(static_cast<uint64_t>(-1));
557be907324SWei Mi     Writer.write(static_cast<uint64_t>(-1));
558be907324SWei Mi     Writer.write(static_cast<uint64_t>(-1));
559be907324SWei Mi     Writer.write(static_cast<uint64_t>(-1));
560be907324SWei Mi   }
561be907324SWei Mi }
562be907324SWei Mi 
563be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() {
564be907324SWei Mi   auto &OFS = static_cast<raw_fd_ostream &>(*OutputStream);
565be907324SWei Mi   uint64_t Saved = OutputStream->tell();
566be907324SWei Mi 
567be907324SWei Mi   // Set OutputStream to the location saved in SecHdrTableOffset.
568be907324SWei Mi   if (OFS.seek(SecHdrTableOffset) == (uint64_t)-1)
569be907324SWei Mi     return sampleprof_error::ostream_seek_unsupported;
570be907324SWei Mi   support::endian::Writer Writer(*OutputStream, support::little);
571be907324SWei Mi 
572a906e3ecSWei Mi   assert(SecHdrTable.size() == SectionHdrLayout.size() &&
573a906e3ecSWei Mi          "SecHdrTable entries doesn't match SectionHdrLayout");
574a906e3ecSWei Mi   SmallVector<uint32_t, 16> IndexMap(SecHdrTable.size(), -1);
575a906e3ecSWei Mi   for (uint32_t TableIdx = 0; TableIdx < SecHdrTable.size(); TableIdx++) {
576a906e3ecSWei Mi     IndexMap[SecHdrTable[TableIdx].LayoutIndex] = TableIdx;
577be907324SWei Mi   }
578be907324SWei Mi 
57909dcfe68SWei Mi   // Write the section header table in the order specified in
580a906e3ecSWei Mi   // SectionHdrLayout. SectionHdrLayout specifies the sections
581a906e3ecSWei Mi   // order in which profile reader expect to read, so the section
582a906e3ecSWei Mi   // header table should be written in the order in SectionHdrLayout.
583a906e3ecSWei Mi   // Note that the section order in SecHdrTable may be different
584a906e3ecSWei Mi   // from the order in SectionHdrLayout, for example, SecFuncOffsetTable
585a906e3ecSWei Mi   // needs to be computed after SecLBRProfile (the order in SecHdrTable),
586a906e3ecSWei Mi   // but it needs to be read before SecLBRProfile (the order in
587a906e3ecSWei Mi   // SectionHdrLayout). So we use IndexMap above to switch the order.
588a906e3ecSWei Mi   for (uint32_t LayoutIdx = 0; LayoutIdx < SectionHdrLayout.size();
589a906e3ecSWei Mi        LayoutIdx++) {
590a906e3ecSWei Mi     assert(IndexMap[LayoutIdx] < SecHdrTable.size() &&
591a906e3ecSWei Mi            "Incorrect LayoutIdx in SecHdrTable");
592a906e3ecSWei Mi     auto Entry = SecHdrTable[IndexMap[LayoutIdx]];
593a906e3ecSWei Mi     Writer.write(static_cast<uint64_t>(Entry.Type));
594a906e3ecSWei Mi     Writer.write(static_cast<uint64_t>(Entry.Flags));
595a906e3ecSWei Mi     Writer.write(static_cast<uint64_t>(Entry.Offset));
596a906e3ecSWei Mi     Writer.write(static_cast<uint64_t>(Entry.Size));
597be907324SWei Mi   }
598be907324SWei Mi 
599be907324SWei Mi   // Reset OutputStream.
600be907324SWei Mi   if (OFS.seek(Saved) == (uint64_t)-1)
601be907324SWei Mi     return sampleprof_error::ostream_seek_unsupported;
602be907324SWei Mi 
603be907324SWei Mi   return sampleprof_error::success;
604be907324SWei Mi }
605be907324SWei Mi 
606be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeHeader(
607be907324SWei Mi     const StringMap<FunctionSamples> &ProfileMap) {
608be907324SWei Mi   auto &OS = *OutputStream;
609be907324SWei Mi   FileStart = OS.tell();
610be907324SWei Mi   writeMagicIdent(Format);
611be907324SWei Mi 
612be907324SWei Mi   allocSecHdrTable();
613be907324SWei Mi   return sampleprof_error::success;
614be907324SWei Mi }
615be907324SWei Mi 
6166a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::writeHeader(
6176a14325dSWei Mi     const StringMap<FunctionSamples> &ProfileMap) {
6186a14325dSWei Mi   support::endian::Writer Writer(*OutputStream, support::little);
6196a14325dSWei Mi   if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap))
6206a14325dSWei Mi     return EC;
6216a14325dSWei Mi 
6226a14325dSWei Mi   // Reserve a slot for the offset of function offset table. The slot will
6236a14325dSWei Mi   // be populated with the offset of FuncOffsetTable later.
6246a14325dSWei Mi   TableOffset = OutputStream->tell();
6256a14325dSWei Mi   Writer.write(static_cast<uint64_t>(-2));
6266a14325dSWei Mi   return sampleprof_error::success;
6276a14325dSWei Mi }
6286a14325dSWei Mi 
62940ee23dbSEaswaran Raman std::error_code SampleProfileWriterBinary::writeSummary() {
63040ee23dbSEaswaran Raman   auto &OS = *OutputStream;
6317cefdb81SEaswaran Raman   encodeULEB128(Summary->getTotalCount(), OS);
6327cefdb81SEaswaran Raman   encodeULEB128(Summary->getMaxCount(), OS);
6336f4903d9SEaswaran Raman   encodeULEB128(Summary->getMaxFunctionCount(), OS);
6347cefdb81SEaswaran Raman   encodeULEB128(Summary->getNumCounts(), OS);
63540ee23dbSEaswaran Raman   encodeULEB128(Summary->getNumFunctions(), OS);
63640ee23dbSEaswaran Raman   std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary();
63740ee23dbSEaswaran Raman   encodeULEB128(Entries.size(), OS);
63840ee23dbSEaswaran Raman   for (auto Entry : Entries) {
63940ee23dbSEaswaran Raman     encodeULEB128(Entry.Cutoff, OS);
64040ee23dbSEaswaran Raman     encodeULEB128(Entry.MinCount, OS);
64140ee23dbSEaswaran Raman     encodeULEB128(Entry.NumCounts, OS);
64240ee23dbSEaswaran Raman   }
64340ee23dbSEaswaran Raman   return sampleprof_error::success;
64440ee23dbSEaswaran Raman }
64557d1dda5SDehao Chen std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
64651abea74SNathan Slingerland   auto &OS = *OutputStream;
64751abea74SNathan Slingerland 
6487e99bddfSHongtao Yu   if (std::error_code EC = writeNameIdx(S.getNameWithContext(true)))
649760c5a8fSDiego Novillo     return EC;
650760c5a8fSDiego Novillo 
651c572e92cSDiego Novillo   encodeULEB128(S.getTotalSamples(), OS);
652a7f1e8efSDiego Novillo 
653a7f1e8efSDiego Novillo   // Emit all the body samples.
654b93483dbSDiego Novillo   encodeULEB128(S.getBodySamples().size(), OS);
655d5336ae2SDiego Novillo   for (const auto &I : S.getBodySamples()) {
656d5336ae2SDiego Novillo     LineLocation Loc = I.first;
657d5336ae2SDiego Novillo     const SampleRecord &Sample = I.second;
658c572e92cSDiego Novillo     encodeULEB128(Loc.LineOffset, OS);
659c572e92cSDiego Novillo     encodeULEB128(Loc.Discriminator, OS);
660c572e92cSDiego Novillo     encodeULEB128(Sample.getSamples(), OS);
661c572e92cSDiego Novillo     encodeULEB128(Sample.getCallTargets().size(), OS);
6625adace35SWenlei He     for (const auto &J : Sample.getSortedCallTargets()) {
6635adace35SWenlei He       StringRef Callee = J.first;
66438be3330SDiego Novillo       uint64_t CalleeSamples = J.second;
665760c5a8fSDiego Novillo       if (std::error_code EC = writeNameIdx(Callee))
666760c5a8fSDiego Novillo         return EC;
667c572e92cSDiego Novillo       encodeULEB128(CalleeSamples, OS);
668c572e92cSDiego Novillo     }
669c572e92cSDiego Novillo   }
670c572e92cSDiego Novillo 
671a7f1e8efSDiego Novillo   // Recursively emit all the callsite samples.
6722c27daf7SDehao Chen   uint64_t NumCallsites = 0;
6732c27daf7SDehao Chen   for (const auto &J : S.getCallsiteSamples())
6742c27daf7SDehao Chen     NumCallsites += J.second.size();
6752c27daf7SDehao Chen   encodeULEB128(NumCallsites, OS);
6762c7ca9b5SDehao Chen   for (const auto &J : S.getCallsiteSamples())
6772c7ca9b5SDehao Chen     for (const auto &FS : J.second) {
67857d1dda5SDehao Chen       LineLocation Loc = J.first;
6792c7ca9b5SDehao Chen       const FunctionSamples &CalleeSamples = FS.second;
680a7f1e8efSDiego Novillo       encodeULEB128(Loc.LineOffset, OS);
681a7f1e8efSDiego Novillo       encodeULEB128(Loc.Discriminator, OS);
68257d1dda5SDehao Chen       if (std::error_code EC = writeBody(CalleeSamples))
683760c5a8fSDiego Novillo         return EC;
684a7f1e8efSDiego Novillo     }
685a7f1e8efSDiego Novillo 
686760c5a8fSDiego Novillo   return sampleprof_error::success;
687c572e92cSDiego Novillo }
688d5336ae2SDiego Novillo 
6895f8f34e4SAdrian Prantl /// Write samples of a top-level function to a binary file.
690b93483dbSDiego Novillo ///
691b93483dbSDiego Novillo /// \returns true if the samples were written successfully, false otherwise.
692be907324SWei Mi std::error_code
693be907324SWei Mi SampleProfileWriterBinary::writeSample(const FunctionSamples &S) {
69451abea74SNathan Slingerland   encodeULEB128(S.getHeadSamples(), *OutputStream);
69557d1dda5SDehao Chen   return writeBody(S);
696b93483dbSDiego Novillo }
697b93483dbSDiego Novillo 
6986a14325dSWei Mi std::error_code
699be907324SWei Mi SampleProfileWriterCompactBinary::writeSample(const FunctionSamples &S) {
7006a14325dSWei Mi   uint64_t Offset = OutputStream->tell();
7016a14325dSWei Mi   StringRef Name = S.getName();
7026a14325dSWei Mi   FuncOffsetTable[Name] = Offset;
7036a14325dSWei Mi   encodeULEB128(S.getHeadSamples(), *OutputStream);
7046a14325dSWei Mi   return writeBody(S);
7056a14325dSWei Mi }
7066a14325dSWei Mi 
7075f8f34e4SAdrian Prantl /// Create a sample profile file writer based on the specified format.
708d5336ae2SDiego Novillo ///
709d5336ae2SDiego Novillo /// \param Filename The file to create.
710d5336ae2SDiego Novillo ///
711d5336ae2SDiego Novillo /// \param Format Encoding format for the profile file.
712d5336ae2SDiego Novillo ///
713d5336ae2SDiego Novillo /// \returns an error code indicating the status of the created writer.
714fcd55607SDiego Novillo ErrorOr<std::unique_ptr<SampleProfileWriter>>
715fcd55607SDiego Novillo SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
716d5336ae2SDiego Novillo   std::error_code EC;
71751abea74SNathan Slingerland   std::unique_ptr<raw_ostream> OS;
718be907324SWei Mi   if (Format == SPF_Binary || Format == SPF_Ext_Binary ||
719be907324SWei Mi       Format == SPF_Compact_Binary)
720d9b948b6SFangrui Song     OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None));
72151abea74SNathan Slingerland   else
722d9b948b6SFangrui Song     OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_Text));
72351abea74SNathan Slingerland   if (EC)
72451abea74SNathan Slingerland     return EC;
72551abea74SNathan Slingerland 
72651abea74SNathan Slingerland   return create(OS, Format);
72751abea74SNathan Slingerland }
72851abea74SNathan Slingerland 
7295f8f34e4SAdrian Prantl /// Create a sample profile stream writer based on the specified format.
73051abea74SNathan Slingerland ///
73151abea74SNathan Slingerland /// \param OS The output stream to store the profile data to.
73251abea74SNathan Slingerland ///
73351abea74SNathan Slingerland /// \param Format Encoding format for the profile file.
73451abea74SNathan Slingerland ///
73551abea74SNathan Slingerland /// \returns an error code indicating the status of the created writer.
73651abea74SNathan Slingerland ErrorOr<std::unique_ptr<SampleProfileWriter>>
73751abea74SNathan Slingerland SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
73851abea74SNathan Slingerland                             SampleProfileFormat Format) {
73951abea74SNathan Slingerland   std::error_code EC;
740fcd55607SDiego Novillo   std::unique_ptr<SampleProfileWriter> Writer;
741d5336ae2SDiego Novillo 
742d9be2c7eSWei Mi   if (Format == SPF_Binary)
743a0c0857eSWei Mi     Writer.reset(new SampleProfileWriterRawBinary(OS));
744be907324SWei Mi   else if (Format == SPF_Ext_Binary)
745be907324SWei Mi     Writer.reset(new SampleProfileWriterExtBinary(OS));
746a0c0857eSWei Mi   else if (Format == SPF_Compact_Binary)
747a0c0857eSWei Mi     Writer.reset(new SampleProfileWriterCompactBinary(OS));
748d5336ae2SDiego Novillo   else if (Format == SPF_Text)
74951abea74SNathan Slingerland     Writer.reset(new SampleProfileWriterText(OS));
750760c5a8fSDiego Novillo   else if (Format == SPF_GCC)
751760c5a8fSDiego Novillo     EC = sampleprof_error::unsupported_writing_format;
752d5336ae2SDiego Novillo   else
753d5336ae2SDiego Novillo     EC = sampleprof_error::unrecognized_format;
754d5336ae2SDiego Novillo 
755fcd55607SDiego Novillo   if (EC)
756d5336ae2SDiego Novillo     return EC;
757fcd55607SDiego Novillo 
758be907324SWei Mi   Writer->Format = Format;
759c55cf4afSBill Wendling   return std::move(Writer);
760d5336ae2SDiego Novillo }
76140ee23dbSEaswaran Raman 
76240ee23dbSEaswaran Raman void SampleProfileWriter::computeSummary(
76340ee23dbSEaswaran Raman     const StringMap<FunctionSamples> &ProfileMap) {
764e5a17e3fSEaswaran Raman   SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
765801d9cc7SWenlei He   Summary = Builder.computeSummaryForProfiles(ProfileMap);
76640ee23dbSEaswaran Raman }
767