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;
4900ef28efSWenlei He   for (const auto &I : ProfileMap) {
5000ef28efSWenlei He     assert(I.getKey() == I.second.getNameWithContext() &&
5100ef28efSWenlei He            "Inconsistent profile map");
5200ef28efSWenlei He     V.push_back(std::make_pair(I.second.getNameWithContext(), &I.second));
5300ef28efSWenlei He   }
54efd94c56SFangrui Song   llvm::stable_sort(
55efd94c56SFangrui Song       V, [](const NameFunctionSamples &A, const NameFunctionSamples &B) {
568d1c983fSDehao Chen         if (A.second->getTotalSamples() == B.second->getTotalSamples())
578d1c983fSDehao Chen           return A.first > B.first;
588d1c983fSDehao Chen         return A.second->getTotalSamples() > B.second->getTotalSamples();
598d1c983fSDehao Chen       });
608d1c983fSDehao Chen 
618d1c983fSDehao Chen   for (const auto &I : V) {
62be907324SWei Mi     if (std::error_code EC = writeSample(*I.second))
638d1c983fSDehao Chen       return EC;
648d1c983fSDehao Chen   }
658d1c983fSDehao Chen   return sampleprof_error::success;
668d1c983fSDehao Chen }
678d1c983fSDehao Chen 
68be907324SWei Mi std::error_code
69be907324SWei Mi SampleProfileWriter::write(const StringMap<FunctionSamples> &ProfileMap) {
70be907324SWei Mi   if (std::error_code EC = writeHeader(ProfileMap))
71be907324SWei Mi     return EC;
72be907324SWei Mi 
73be907324SWei Mi   if (std::error_code EC = writeFuncProfiles(ProfileMap))
74be907324SWei Mi     return EC;
75be907324SWei Mi 
76be907324SWei Mi   return sampleprof_error::success;
77be907324SWei Mi }
78be907324SWei Mi 
79b523790aSWei Mi /// Return the current position and prepare to use it as the start
80a906e3ecSWei Mi /// position of a section given the section type \p Type and its position
81a906e3ecSWei Mi /// \p LayoutIdx in SectionHdrLayout.
82a906e3ecSWei Mi uint64_t
83a906e3ecSWei Mi SampleProfileWriterExtBinaryBase::markSectionStart(SecType Type,
84a906e3ecSWei Mi                                                    uint32_t LayoutIdx) {
85b523790aSWei Mi   uint64_t SectionStart = OutputStream->tell();
86a906e3ecSWei Mi   assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range");
87a906e3ecSWei Mi   const auto &Entry = SectionHdrLayout[LayoutIdx];
88a906e3ecSWei Mi   assert(Entry.Type == Type && "Unexpected section type");
89b523790aSWei Mi   // Use LocalBuf as a temporary output for writting data.
90ebad6788SWei Mi   if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress))
91b523790aSWei Mi     LocalBufStream.swap(OutputStream);
92b523790aSWei Mi   return SectionStart;
93b523790aSWei Mi }
94b523790aSWei Mi 
95b523790aSWei Mi std::error_code SampleProfileWriterExtBinaryBase::compressAndOutput() {
96b523790aSWei Mi   if (!llvm::zlib::isAvailable())
97b523790aSWei Mi     return sampleprof_error::zlib_unavailable;
98b523790aSWei Mi   std::string &UncompressedStrings =
99b523790aSWei Mi       static_cast<raw_string_ostream *>(LocalBufStream.get())->str();
100b523790aSWei Mi   if (UncompressedStrings.size() == 0)
101b523790aSWei Mi     return sampleprof_error::success;
102b523790aSWei Mi   auto &OS = *OutputStream;
103b523790aSWei Mi   SmallString<128> CompressedStrings;
104b523790aSWei Mi   llvm::Error E = zlib::compress(UncompressedStrings, CompressedStrings,
105b523790aSWei Mi                                  zlib::BestSizeCompression);
106b523790aSWei Mi   if (E)
107b523790aSWei Mi     return sampleprof_error::compress_failed;
108b523790aSWei Mi   encodeULEB128(UncompressedStrings.size(), OS);
109b523790aSWei Mi   encodeULEB128(CompressedStrings.size(), OS);
110b523790aSWei Mi   OS << CompressedStrings.str();
111b523790aSWei Mi   UncompressedStrings.clear();
112b523790aSWei Mi   return sampleprof_error::success;
113b523790aSWei Mi }
114b523790aSWei Mi 
115a906e3ecSWei Mi /// Add a new section into section header table given the section type
116a906e3ecSWei Mi /// \p Type, its position \p LayoutIdx in SectionHdrLayout and the
117a906e3ecSWei Mi /// location \p SectionStart where the section should be written to.
118a906e3ecSWei Mi std::error_code SampleProfileWriterExtBinaryBase::addNewSection(
119a906e3ecSWei Mi     SecType Type, uint32_t LayoutIdx, uint64_t SectionStart) {
120a906e3ecSWei Mi   assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range");
121a906e3ecSWei Mi   const auto &Entry = SectionHdrLayout[LayoutIdx];
122a906e3ecSWei Mi   assert(Entry.Type == Type && "Unexpected section type");
123ebad6788SWei Mi   if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress)) {
124b523790aSWei Mi     LocalBufStream.swap(OutputStream);
125b523790aSWei Mi     if (std::error_code EC = compressAndOutput())
126b523790aSWei Mi       return EC;
127b523790aSWei Mi   }
128b523790aSWei Mi   SecHdrTable.push_back({Type, Entry.Flags, SectionStart - FileStart,
129a906e3ecSWei Mi                          OutputStream->tell() - SectionStart, LayoutIdx});
130b523790aSWei Mi   return sampleprof_error::success;
131be907324SWei Mi }
132be907324SWei Mi 
133be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::write(
134be907324SWei Mi     const StringMap<FunctionSamples> &ProfileMap) {
135be907324SWei Mi   if (std::error_code EC = writeHeader(ProfileMap))
136be907324SWei Mi     return EC;
137be907324SWei Mi 
138b523790aSWei Mi   std::string LocalBuf;
139b523790aSWei Mi   LocalBufStream = std::make_unique<raw_string_ostream>(LocalBuf);
140be907324SWei Mi   if (std::error_code EC = writeSections(ProfileMap))
141be907324SWei Mi     return EC;
142be907324SWei Mi 
143be907324SWei Mi   if (std::error_code EC = writeSecHdrTable())
144be907324SWei Mi     return EC;
145be907324SWei Mi 
146be907324SWei Mi   return sampleprof_error::success;
147be907324SWei Mi }
148be907324SWei Mi 
14909dcfe68SWei Mi std::error_code
15093953d41SWei Mi SampleProfileWriterExtBinaryBase::writeSample(const FunctionSamples &S) {
15109dcfe68SWei Mi   uint64_t Offset = OutputStream->tell();
15200ef28efSWenlei He   StringRef Name = S.getNameWithContext();
15309dcfe68SWei Mi   FuncOffsetTable[Name] = Offset - SecLBRProfileStart;
15409dcfe68SWei Mi   encodeULEB128(S.getHeadSamples(), *OutputStream);
15509dcfe68SWei Mi   return writeBody(S);
15609dcfe68SWei Mi }
15709dcfe68SWei Mi 
15893953d41SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeFuncOffsetTable() {
15909dcfe68SWei Mi   auto &OS = *OutputStream;
16009dcfe68SWei Mi 
16109dcfe68SWei Mi   // Write out the table size.
16209dcfe68SWei Mi   encodeULEB128(FuncOffsetTable.size(), OS);
16309dcfe68SWei Mi 
16409dcfe68SWei Mi   // Write out FuncOffsetTable.
16500ef28efSWenlei He   for (auto Entry : FuncOffsetTable) {
16600ef28efSWenlei He     if (std::error_code EC =
16700ef28efSWenlei He             writeNameIdx(Entry.first, FunctionSamples::ProfileIsCS))
16800ef28efSWenlei He       return EC;
16900ef28efSWenlei He     encodeULEB128(Entry.second, OS);
17009dcfe68SWei Mi   }
171a906e3ecSWei Mi   FuncOffsetTable.clear();
17209dcfe68SWei Mi   return sampleprof_error::success;
17309dcfe68SWei Mi }
17409dcfe68SWei Mi 
175ac068e01SHongtao Yu std::error_code SampleProfileWriterExtBinaryBase::writeFuncMetadata(
176ac068e01SHongtao Yu     const StringMap<FunctionSamples> &Profiles) {
1771410db70SWenlei He   if (!FunctionSamples::ProfileIsProbeBased && !FunctionSamples::ProfileIsCS)
178ac068e01SHongtao Yu     return sampleprof_error::success;
179ac068e01SHongtao Yu   auto &OS = *OutputStream;
180ac068e01SHongtao Yu   for (const auto &Entry : Profiles) {
18100ef28efSWenlei He     if (std::error_code EC = writeNameIdx(Entry.second.getNameWithContext(),
18200ef28efSWenlei He                                           FunctionSamples::ProfileIsCS))
18300ef28efSWenlei He       return EC;
1841410db70SWenlei He     if (FunctionSamples::ProfileIsProbeBased)
185ac068e01SHongtao Yu       encodeULEB128(Entry.second.getFunctionHash(), OS);
1861410db70SWenlei He     if (FunctionSamples::ProfileIsCS)
1871410db70SWenlei He       encodeULEB128(Entry.second.getContext().getAllAttributes(), OS);
188ac068e01SHongtao Yu   }
189ac068e01SHongtao Yu   return sampleprof_error::success;
190ac068e01SHongtao Yu }
191ac068e01SHongtao Yu 
19293953d41SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeNameTable() {
193ebad6788SWei Mi   if (!UseMD5)
194ebad6788SWei Mi     return SampleProfileWriterBinary::writeNameTable();
195ebad6788SWei Mi 
196ebad6788SWei Mi   auto &OS = *OutputStream;
197ebad6788SWei Mi   std::set<StringRef> V;
198ebad6788SWei Mi   stablizeNameTable(V);
199ebad6788SWei Mi 
20064e76853SWei Mi   // Write out the MD5 name table. We wrote unencoded MD5 so reader can
20164e76853SWei Mi   // retrieve the name using the name index without having to read the
20264e76853SWei Mi   // whole name table.
203ebad6788SWei Mi   encodeULEB128(NameTable.size(), OS);
20464e76853SWei Mi   support::endian::Writer Writer(OS, support::little);
20564e76853SWei Mi   for (auto N : V)
20664e76853SWei Mi     Writer.write(MD5Hash(N));
207ebad6788SWei Mi   return sampleprof_error::success;
208ebad6788SWei Mi }
209ebad6788SWei Mi 
21093953d41SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeNameTableSection(
211be907324SWei Mi     const StringMap<FunctionSamples> &ProfileMap) {
212be907324SWei Mi   for (const auto &I : ProfileMap) {
21300ef28efSWenlei He     assert(I.first() == I.second.getNameWithContext() &&
21400ef28efSWenlei He            "Inconsistent profile map");
21500ef28efSWenlei He     addName(I.second.getNameWithContext(), FunctionSamples::ProfileIsCS);
216be907324SWei Mi     addNames(I.second);
217be907324SWei Mi   }
218ee35784aSWei Mi 
219ee35784aSWei Mi   // If NameTable contains ".__uniq." suffix, set SecFlagUniqSuffix flag
220ee35784aSWei Mi   // so compiler won't strip the suffix during profile matching after
221ee35784aSWei Mi   // seeing the flag in the profile.
222ee35784aSWei Mi   for (const auto &I : NameTable) {
223ee35784aSWei Mi     if (I.first.find(FunctionSamples::UniqSuffix) != StringRef::npos) {
224ee35784aSWei Mi       addSectionFlag(SecNameTable, SecNameTableFlags::SecFlagUniqSuffix);
225ee35784aSWei Mi       break;
226ee35784aSWei Mi     }
227ee35784aSWei Mi   }
228ee35784aSWei Mi 
22993953d41SWei Mi   if (auto EC = writeNameTable())
230b523790aSWei Mi     return EC;
23193953d41SWei Mi   return sampleprof_error::success;
23293953d41SWei Mi }
233be907324SWei Mi 
23493953d41SWei Mi std::error_code
23593953d41SWei Mi SampleProfileWriterExtBinaryBase::writeProfileSymbolListSection() {
236798e59b8SWei Mi   if (ProfSymList && ProfSymList->size() > 0)
237798e59b8SWei Mi     if (std::error_code EC = ProfSymList->write(*OutputStream))
238798e59b8SWei Mi       return EC;
239be907324SWei Mi 
24093953d41SWei Mi   return sampleprof_error::success;
24193953d41SWei Mi }
24209dcfe68SWei Mi 
24393953d41SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeOneSection(
244a906e3ecSWei Mi     SecType Type, uint32_t LayoutIdx,
245a906e3ecSWei Mi     const StringMap<FunctionSamples> &ProfileMap) {
24693953d41SWei Mi   // The setting of SecFlagCompress should happen before markSectionStart.
24793953d41SWei Mi   if (Type == SecProfileSymbolList && ProfSymList && ProfSymList->toCompress())
24893953d41SWei Mi     setToCompressSection(SecProfileSymbolList);
249ac068e01SHongtao Yu   if (Type == SecFuncMetadata && FunctionSamples::ProfileIsProbeBased)
250ac068e01SHongtao Yu     addSectionFlag(SecFuncMetadata, SecFuncMetadataFlags::SecFlagIsProbeBased);
251a5d30421SWenlei He   if (Type == SecProfSummary && FunctionSamples::ProfileIsCS)
252a5d30421SWenlei He     addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagFullContext);
2531410db70SWenlei He   if (Type == SecFuncMetadata && FunctionSamples::ProfileIsCS)
2541410db70SWenlei He     addSectionFlag(SecFuncMetadata, SecFuncMetadataFlags::SecFlagHasAttribute);
255*6745ffe4SRong Xu   if (Type == SecProfSummary && FunctionSamples::ProfileIsFS)
256*6745ffe4SRong Xu     addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagFSDiscriminator);
25793953d41SWei Mi 
258a906e3ecSWei Mi   uint64_t SectionStart = markSectionStart(Type, LayoutIdx);
25993953d41SWei Mi   switch (Type) {
26093953d41SWei Mi   case SecProfSummary:
26193953d41SWei Mi     computeSummary(ProfileMap);
26293953d41SWei Mi     if (auto EC = writeSummary())
26393953d41SWei Mi       return EC;
26493953d41SWei Mi     break;
26593953d41SWei Mi   case SecNameTable:
26693953d41SWei Mi     if (auto EC = writeNameTableSection(ProfileMap))
26793953d41SWei Mi       return EC;
26893953d41SWei Mi     break;
26993953d41SWei Mi   case SecLBRProfile:
27093953d41SWei Mi     SecLBRProfileStart = OutputStream->tell();
27193953d41SWei Mi     if (std::error_code EC = writeFuncProfiles(ProfileMap))
27293953d41SWei Mi       return EC;
27393953d41SWei Mi     break;
27493953d41SWei Mi   case SecFuncOffsetTable:
27593953d41SWei Mi     if (auto EC = writeFuncOffsetTable())
27693953d41SWei Mi       return EC;
27793953d41SWei Mi     break;
278ac068e01SHongtao Yu   case SecFuncMetadata:
279ac068e01SHongtao Yu     if (std::error_code EC = writeFuncMetadata(ProfileMap))
280ac068e01SHongtao Yu       return EC;
281ac068e01SHongtao Yu     break;
28293953d41SWei Mi   case SecProfileSymbolList:
28393953d41SWei Mi     if (auto EC = writeProfileSymbolListSection())
28493953d41SWei Mi       return EC;
28593953d41SWei Mi     break;
28693953d41SWei Mi   default:
28793953d41SWei Mi     if (auto EC = writeCustomSection(Type))
28893953d41SWei Mi       return EC;
28993953d41SWei Mi     break;
29093953d41SWei Mi   }
291a906e3ecSWei Mi   if (std::error_code EC = addNewSection(Type, LayoutIdx, SectionStart))
29293953d41SWei Mi     return EC;
29393953d41SWei Mi   return sampleprof_error::success;
29493953d41SWei Mi }
29593953d41SWei Mi 
29621b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeDefaultLayout(
29793953d41SWei Mi     const StringMap<FunctionSamples> &ProfileMap) {
298a906e3ecSWei Mi   // The const indices passed to writeOneSection below are specifying the
299a906e3ecSWei Mi   // positions of the sections in SectionHdrLayout. Look at
300a906e3ecSWei Mi   // initSectionHdrLayout to find out where each section is located in
301a906e3ecSWei Mi   // SectionHdrLayout.
302a906e3ecSWei Mi   if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap))
30393953d41SWei Mi     return EC;
304a906e3ecSWei Mi   if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap))
30593953d41SWei Mi     return EC;
306a906e3ecSWei Mi   if (auto EC = writeOneSection(SecLBRProfile, 3, ProfileMap))
30793953d41SWei Mi     return EC;
308a906e3ecSWei Mi   if (auto EC = writeOneSection(SecProfileSymbolList, 4, ProfileMap))
30993953d41SWei Mi     return EC;
310a906e3ecSWei Mi   if (auto EC = writeOneSection(SecFuncOffsetTable, 2, ProfileMap))
31193953d41SWei Mi     return EC;
312a906e3ecSWei Mi   if (auto EC = writeOneSection(SecFuncMetadata, 5, ProfileMap))
313ac068e01SHongtao Yu     return EC;
314be907324SWei Mi   return sampleprof_error::success;
315be907324SWei Mi }
316be907324SWei Mi 
31721b1ad03SWei Mi static void
31821b1ad03SWei Mi splitProfileMapToTwo(const StringMap<FunctionSamples> &ProfileMap,
31921b1ad03SWei Mi                      StringMap<FunctionSamples> &ContextProfileMap,
32021b1ad03SWei Mi                      StringMap<FunctionSamples> &NoContextProfileMap) {
32121b1ad03SWei Mi   for (const auto &I : ProfileMap) {
32221b1ad03SWei Mi     if (I.second.getCallsiteSamples().size())
32321b1ad03SWei Mi       ContextProfileMap.insert({I.first(), I.second});
32421b1ad03SWei Mi     else
32521b1ad03SWei Mi       NoContextProfileMap.insert({I.first(), I.second});
32621b1ad03SWei Mi   }
32721b1ad03SWei Mi }
32821b1ad03SWei Mi 
32921b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeCtxSplitLayout(
33021b1ad03SWei Mi     const StringMap<FunctionSamples> &ProfileMap) {
33121b1ad03SWei Mi   StringMap<FunctionSamples> ContextProfileMap, NoContextProfileMap;
33221b1ad03SWei Mi   splitProfileMapToTwo(ProfileMap, ContextProfileMap, NoContextProfileMap);
33321b1ad03SWei Mi 
33421b1ad03SWei Mi   if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap))
33521b1ad03SWei Mi     return EC;
33621b1ad03SWei Mi   if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap))
33721b1ad03SWei Mi     return EC;
33821b1ad03SWei Mi   if (auto EC = writeOneSection(SecLBRProfile, 3, ContextProfileMap))
33921b1ad03SWei Mi     return EC;
34021b1ad03SWei Mi   if (auto EC = writeOneSection(SecFuncOffsetTable, 2, ContextProfileMap))
34121b1ad03SWei Mi     return EC;
34221b1ad03SWei Mi   // Mark the section to have no context. Note section flag needs to be set
34321b1ad03SWei Mi   // before writing the section.
34421b1ad03SWei Mi   addSectionFlag(5, SecCommonFlags::SecFlagFlat);
34521b1ad03SWei Mi   if (auto EC = writeOneSection(SecLBRProfile, 5, NoContextProfileMap))
34621b1ad03SWei Mi     return EC;
34721b1ad03SWei Mi   // Mark the section to have no context. Note section flag needs to be set
34821b1ad03SWei Mi   // before writing the section.
34921b1ad03SWei Mi   addSectionFlag(4, SecCommonFlags::SecFlagFlat);
35021b1ad03SWei Mi   if (auto EC = writeOneSection(SecFuncOffsetTable, 4, NoContextProfileMap))
35121b1ad03SWei Mi     return EC;
35221b1ad03SWei Mi   if (auto EC = writeOneSection(SecProfileSymbolList, 6, ProfileMap))
35321b1ad03SWei Mi     return EC;
35421b1ad03SWei Mi   if (auto EC = writeOneSection(SecFuncMetadata, 7, ProfileMap))
35521b1ad03SWei Mi     return EC;
35621b1ad03SWei Mi 
35721b1ad03SWei Mi   return sampleprof_error::success;
35821b1ad03SWei Mi }
35921b1ad03SWei Mi 
36021b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeSections(
36121b1ad03SWei Mi     const StringMap<FunctionSamples> &ProfileMap) {
36221b1ad03SWei Mi   std::error_code EC;
36321b1ad03SWei Mi   if (SecLayout == DefaultLayout)
36421b1ad03SWei Mi     EC = writeDefaultLayout(ProfileMap);
36521b1ad03SWei Mi   else if (SecLayout == CtxSplitLayout)
36621b1ad03SWei Mi     EC = writeCtxSplitLayout(ProfileMap);
36721b1ad03SWei Mi   else
36821b1ad03SWei Mi     llvm_unreachable("Unsupported layout");
36921b1ad03SWei Mi   return EC;
37021b1ad03SWei Mi }
37121b1ad03SWei Mi 
3726a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::write(
3736a14325dSWei Mi     const StringMap<FunctionSamples> &ProfileMap) {
3746a14325dSWei Mi   if (std::error_code EC = SampleProfileWriter::write(ProfileMap))
3756a14325dSWei Mi     return EC;
3766a14325dSWei Mi   if (std::error_code EC = writeFuncOffsetTable())
3776a14325dSWei Mi     return EC;
3786a14325dSWei Mi   return sampleprof_error::success;
3796a14325dSWei Mi }
3806a14325dSWei Mi 
3815f8f34e4SAdrian Prantl /// Write samples to a text file.
3828e415a82SDiego Novillo ///
3838e415a82SDiego Novillo /// Note: it may be tempting to implement this in terms of
384ef548d29SDiego Novillo /// FunctionSamples::print().  Please don't.  The dump functionality is intended
3858e415a82SDiego Novillo /// for debugging and has no specified form.
3868e415a82SDiego Novillo ///
3878e415a82SDiego Novillo /// The format used here is more structured and deliberate because
3888e415a82SDiego Novillo /// it needs to be parsed by the SampleProfileReaderText class.
389be907324SWei Mi std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) {
39051abea74SNathan Slingerland   auto &OS = *OutputStream;
39100ef28efSWenlei He   if (FunctionSamples::ProfileIsCS)
39200ef28efSWenlei He     OS << "[" << S.getNameWithContext() << "]:" << S.getTotalSamples();
39300ef28efSWenlei He   else
39400ef28efSWenlei He     OS << S.getName() << ":" << S.getTotalSamples();
39500ef28efSWenlei He 
396aae1ed8eSDiego Novillo   if (Indent == 0)
397aae1ed8eSDiego Novillo     OS << ":" << S.getHeadSamples();
398aae1ed8eSDiego Novillo   OS << "\n";
399c572e92cSDiego Novillo 
400ef548d29SDiego Novillo   SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples());
401ef548d29SDiego Novillo   for (const auto &I : SortedSamples.get()) {
402ef548d29SDiego Novillo     LineLocation Loc = I->first;
403ef548d29SDiego Novillo     const SampleRecord &Sample = I->second;
404aae1ed8eSDiego Novillo     OS.indent(Indent + 1);
405c572e92cSDiego Novillo     if (Loc.Discriminator == 0)
406c572e92cSDiego Novillo       OS << Loc.LineOffset << ": ";
407c572e92cSDiego Novillo     else
408c572e92cSDiego Novillo       OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
409c572e92cSDiego Novillo 
410c572e92cSDiego Novillo     OS << Sample.getSamples();
411c572e92cSDiego Novillo 
4125adace35SWenlei He     for (const auto &J : Sample.getSortedCallTargets())
4135adace35SWenlei He       OS << " " << J.first << ":" << J.second;
414c572e92cSDiego Novillo     OS << "\n";
415c572e92cSDiego Novillo   }
416c572e92cSDiego Novillo 
4172c7ca9b5SDehao Chen   SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples(
418ef548d29SDiego Novillo       S.getCallsiteSamples());
419aae1ed8eSDiego Novillo   Indent += 1;
4202c7ca9b5SDehao Chen   for (const auto &I : SortedCallsiteSamples.get())
4212c7ca9b5SDehao Chen     for (const auto &FS : I->second) {
42257d1dda5SDehao Chen       LineLocation Loc = I->first;
4232c7ca9b5SDehao Chen       const FunctionSamples &CalleeSamples = FS.second;
424aae1ed8eSDiego Novillo       OS.indent(Indent);
425aae1ed8eSDiego Novillo       if (Loc.Discriminator == 0)
426aae1ed8eSDiego Novillo         OS << Loc.LineOffset << ": ";
427aae1ed8eSDiego Novillo       else
428aae1ed8eSDiego Novillo         OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
429be907324SWei Mi       if (std::error_code EC = writeSample(CalleeSamples))
430760c5a8fSDiego Novillo         return EC;
431aae1ed8eSDiego Novillo     }
432aae1ed8eSDiego Novillo   Indent -= 1;
433aae1ed8eSDiego Novillo 
434ac068e01SHongtao Yu   if (Indent == 0) {
435ac068e01SHongtao Yu     if (FunctionSamples::ProfileIsProbeBased) {
436ac068e01SHongtao Yu       OS.indent(Indent + 1);
437ac068e01SHongtao Yu       OS << "!CFGChecksum: " << S.getFunctionHash() << "\n";
438ac068e01SHongtao Yu     }
4391410db70SWenlei He     if (FunctionSamples::ProfileIsCS) {
4401410db70SWenlei He       OS.indent(Indent + 1);
4411410db70SWenlei He       OS << "!Attributes: " << S.getContext().getAllAttributes() << "\n";
4421410db70SWenlei He     }
443ac068e01SHongtao Yu   }
444ac068e01SHongtao Yu 
445760c5a8fSDiego Novillo   return sampleprof_error::success;
446c572e92cSDiego Novillo }
447c572e92cSDiego Novillo 
44800ef28efSWenlei He std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName,
44900ef28efSWenlei He                                                         bool IsContextName) {
45000ef28efSWenlei He   std::string BracketedName;
45100ef28efSWenlei He   if (IsContextName) {
45200ef28efSWenlei He     BracketedName = "[" + FName.str() + "]";
45300ef28efSWenlei He     FName = StringRef(BracketedName);
45400ef28efSWenlei He   }
45500ef28efSWenlei He 
45600ef28efSWenlei He   const auto &Ret = NameTable.find(FName);
45700ef28efSWenlei He   if (Ret == NameTable.end())
458760c5a8fSDiego Novillo     return sampleprof_error::truncated_name_table;
45900ef28efSWenlei He   encodeULEB128(Ret->second, *OutputStream);
460760c5a8fSDiego Novillo   return sampleprof_error::success;
461760c5a8fSDiego Novillo }
462c572e92cSDiego Novillo 
46300ef28efSWenlei He void SampleProfileWriterBinary::addName(StringRef FName, bool IsContextName) {
46400ef28efSWenlei He   if (IsContextName) {
46500ef28efSWenlei He     auto It = BracketedContextStr.insert("[" + FName.str() + "]");
46600ef28efSWenlei He     FName = StringRef(*It.first);
46700ef28efSWenlei He   }
4688d1c983fSDehao Chen   NameTable.insert(std::make_pair(FName, 0));
469760c5a8fSDiego Novillo }
470760c5a8fSDiego Novillo 
471760c5a8fSDiego Novillo void SampleProfileWriterBinary::addNames(const FunctionSamples &S) {
472760c5a8fSDiego Novillo   // Add all the names in indirect call targets.
473760c5a8fSDiego Novillo   for (const auto &I : S.getBodySamples()) {
474760c5a8fSDiego Novillo     const SampleRecord &Sample = I.second;
475760c5a8fSDiego Novillo     for (const auto &J : Sample.getCallTargets())
476760c5a8fSDiego Novillo       addName(J.first());
477760c5a8fSDiego Novillo   }
478760c5a8fSDiego Novillo 
479760c5a8fSDiego Novillo   // Recursively add all the names for inlined callsites.
4802c7ca9b5SDehao Chen   for (const auto &J : S.getCallsiteSamples())
4812c7ca9b5SDehao Chen     for (const auto &FS : J.second) {
4822c7ca9b5SDehao Chen       const FunctionSamples &CalleeSamples = FS.second;
48357d1dda5SDehao Chen       addName(CalleeSamples.getName());
484760c5a8fSDiego Novillo       addNames(CalleeSamples);
485760c5a8fSDiego Novillo     }
486760c5a8fSDiego Novillo }
487760c5a8fSDiego Novillo 
488a0c0857eSWei Mi void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) {
489a0c0857eSWei Mi   // Sort the names to make NameTable deterministic.
490a0c0857eSWei Mi   for (const auto &I : NameTable)
491a0c0857eSWei Mi     V.insert(I.first);
492a0c0857eSWei Mi   int i = 0;
493a0c0857eSWei Mi   for (const StringRef &N : V)
494a0c0857eSWei Mi     NameTable[N] = i++;
495a0c0857eSWei Mi }
49651abea74SNathan Slingerland 
497be907324SWei Mi std::error_code SampleProfileWriterBinary::writeNameTable() {
498a0c0857eSWei Mi   auto &OS = *OutputStream;
499a0c0857eSWei Mi   std::set<StringRef> V;
500a0c0857eSWei Mi   stablizeNameTable(V);
501a0c0857eSWei Mi 
502a0c0857eSWei Mi   // Write out the name table.
503a0c0857eSWei Mi   encodeULEB128(NameTable.size(), OS);
504a0c0857eSWei Mi   for (auto N : V) {
505a0c0857eSWei Mi     OS << N;
506a0c0857eSWei Mi     encodeULEB128(0, OS);
507a0c0857eSWei Mi   }
508a0c0857eSWei Mi   return sampleprof_error::success;
509a0c0857eSWei Mi }
510a0c0857eSWei Mi 
5116a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() {
5126a14325dSWei Mi   auto &OS = *OutputStream;
5136a14325dSWei Mi 
5146a14325dSWei Mi   // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable.
5156a14325dSWei Mi   auto &OFS = static_cast<raw_fd_ostream &>(OS);
5166a14325dSWei Mi   uint64_t FuncOffsetTableStart = OS.tell();
5176a14325dSWei Mi   if (OFS.seek(TableOffset) == (uint64_t)-1)
5186a14325dSWei Mi     return sampleprof_error::ostream_seek_unsupported;
5196a14325dSWei Mi   support::endian::Writer Writer(*OutputStream, support::little);
5206a14325dSWei Mi   Writer.write(FuncOffsetTableStart);
5216a14325dSWei Mi   if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1)
5226a14325dSWei Mi     return sampleprof_error::ostream_seek_unsupported;
5236a14325dSWei Mi 
5246a14325dSWei Mi   // Write out the table size.
5256a14325dSWei Mi   encodeULEB128(FuncOffsetTable.size(), OS);
5266a14325dSWei Mi 
5276a14325dSWei Mi   // Write out FuncOffsetTable.
52800ef28efSWenlei He   for (auto Entry : FuncOffsetTable) {
52900ef28efSWenlei He     if (std::error_code EC =
53000ef28efSWenlei He             writeNameIdx(Entry.first, FunctionSamples::ProfileIsCS))
53100ef28efSWenlei He       return EC;
53200ef28efSWenlei He     encodeULEB128(Entry.second, OS);
5336a14325dSWei Mi   }
5346a14325dSWei Mi   return sampleprof_error::success;
5356a14325dSWei Mi }
5366a14325dSWei Mi 
537a0c0857eSWei Mi std::error_code SampleProfileWriterCompactBinary::writeNameTable() {
538a0c0857eSWei Mi   auto &OS = *OutputStream;
539a0c0857eSWei Mi   std::set<StringRef> V;
540a0c0857eSWei Mi   stablizeNameTable(V);
541a0c0857eSWei Mi 
542a0c0857eSWei Mi   // Write out the name table.
543a0c0857eSWei Mi   encodeULEB128(NameTable.size(), OS);
544a0c0857eSWei Mi   for (auto N : V) {
545a0c0857eSWei Mi     encodeULEB128(MD5Hash(N), OS);
546a0c0857eSWei Mi   }
547a0c0857eSWei Mi   return sampleprof_error::success;
548a0c0857eSWei Mi }
549a0c0857eSWei Mi 
550be907324SWei Mi std::error_code
551be907324SWei Mi SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) {
552a0c0857eSWei Mi   auto &OS = *OutputStream;
553760c5a8fSDiego Novillo   // Write file magic identifier.
554be907324SWei Mi   encodeULEB128(SPMagic(Format), OS);
555a0c0857eSWei Mi   encodeULEB128(SPVersion(), OS);
556a0c0857eSWei Mi   return sampleprof_error::success;
557a0c0857eSWei Mi }
558a0c0857eSWei Mi 
559a0c0857eSWei Mi std::error_code SampleProfileWriterBinary::writeHeader(
560a0c0857eSWei Mi     const StringMap<FunctionSamples> &ProfileMap) {
561be907324SWei Mi   writeMagicIdent(Format);
562760c5a8fSDiego Novillo 
56340ee23dbSEaswaran Raman   computeSummary(ProfileMap);
56440ee23dbSEaswaran Raman   if (auto EC = writeSummary())
56540ee23dbSEaswaran Raman     return EC;
56640ee23dbSEaswaran Raman 
567760c5a8fSDiego Novillo   // Generate the name table for all the functions referenced in the profile.
568760c5a8fSDiego Novillo   for (const auto &I : ProfileMap) {
56900ef28efSWenlei He     assert(I.first() == I.second.getNameWithContext() &&
57000ef28efSWenlei He            "Inconsistent profile map");
57100ef28efSWenlei He     addName(I.first(), FunctionSamples::ProfileIsCS);
572760c5a8fSDiego Novillo     addNames(I.second);
573760c5a8fSDiego Novillo   }
574760c5a8fSDiego Novillo 
575a0c0857eSWei Mi   writeNameTable();
576760c5a8fSDiego Novillo   return sampleprof_error::success;
577c572e92cSDiego Novillo }
578c572e92cSDiego Novillo 
579b523790aSWei Mi void SampleProfileWriterExtBinaryBase::setToCompressAllSections() {
58009dcfe68SWei Mi   for (auto &Entry : SectionHdrLayout)
581ebad6788SWei Mi     addSecFlag(Entry, SecCommonFlags::SecFlagCompress);
582b523790aSWei Mi }
583b523790aSWei Mi 
584b523790aSWei Mi void SampleProfileWriterExtBinaryBase::setToCompressSection(SecType Type) {
585ebad6788SWei Mi   addSectionFlag(Type, SecCommonFlags::SecFlagCompress);
586b523790aSWei Mi }
587b523790aSWei Mi 
588be907324SWei Mi void SampleProfileWriterExtBinaryBase::allocSecHdrTable() {
589be907324SWei Mi   support::endian::Writer Writer(*OutputStream, support::little);
590be907324SWei Mi 
59109dcfe68SWei Mi   Writer.write(static_cast<uint64_t>(SectionHdrLayout.size()));
592be907324SWei Mi   SecHdrTableOffset = OutputStream->tell();
59309dcfe68SWei Mi   for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) {
594be907324SWei Mi     Writer.write(static_cast<uint64_t>(-1));
595be907324SWei Mi     Writer.write(static_cast<uint64_t>(-1));
596be907324SWei Mi     Writer.write(static_cast<uint64_t>(-1));
597be907324SWei Mi     Writer.write(static_cast<uint64_t>(-1));
598be907324SWei Mi   }
599be907324SWei Mi }
600be907324SWei Mi 
601be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() {
602be907324SWei Mi   auto &OFS = static_cast<raw_fd_ostream &>(*OutputStream);
603be907324SWei Mi   uint64_t Saved = OutputStream->tell();
604be907324SWei Mi 
605be907324SWei Mi   // Set OutputStream to the location saved in SecHdrTableOffset.
606be907324SWei Mi   if (OFS.seek(SecHdrTableOffset) == (uint64_t)-1)
607be907324SWei Mi     return sampleprof_error::ostream_seek_unsupported;
608be907324SWei Mi   support::endian::Writer Writer(*OutputStream, support::little);
609be907324SWei Mi 
610a906e3ecSWei Mi   assert(SecHdrTable.size() == SectionHdrLayout.size() &&
611a906e3ecSWei Mi          "SecHdrTable entries doesn't match SectionHdrLayout");
612a906e3ecSWei Mi   SmallVector<uint32_t, 16> IndexMap(SecHdrTable.size(), -1);
613a906e3ecSWei Mi   for (uint32_t TableIdx = 0; TableIdx < SecHdrTable.size(); TableIdx++) {
614a906e3ecSWei Mi     IndexMap[SecHdrTable[TableIdx].LayoutIndex] = TableIdx;
615be907324SWei Mi   }
616be907324SWei Mi 
61709dcfe68SWei Mi   // Write the section header table in the order specified in
618a906e3ecSWei Mi   // SectionHdrLayout. SectionHdrLayout specifies the sections
619a906e3ecSWei Mi   // order in which profile reader expect to read, so the section
620a906e3ecSWei Mi   // header table should be written in the order in SectionHdrLayout.
621a906e3ecSWei Mi   // Note that the section order in SecHdrTable may be different
622a906e3ecSWei Mi   // from the order in SectionHdrLayout, for example, SecFuncOffsetTable
623a906e3ecSWei Mi   // needs to be computed after SecLBRProfile (the order in SecHdrTable),
624a906e3ecSWei Mi   // but it needs to be read before SecLBRProfile (the order in
625a906e3ecSWei Mi   // SectionHdrLayout). So we use IndexMap above to switch the order.
626a906e3ecSWei Mi   for (uint32_t LayoutIdx = 0; LayoutIdx < SectionHdrLayout.size();
627a906e3ecSWei Mi        LayoutIdx++) {
628a906e3ecSWei Mi     assert(IndexMap[LayoutIdx] < SecHdrTable.size() &&
629a906e3ecSWei Mi            "Incorrect LayoutIdx in SecHdrTable");
630a906e3ecSWei Mi     auto Entry = SecHdrTable[IndexMap[LayoutIdx]];
631a906e3ecSWei Mi     Writer.write(static_cast<uint64_t>(Entry.Type));
632a906e3ecSWei Mi     Writer.write(static_cast<uint64_t>(Entry.Flags));
633a906e3ecSWei Mi     Writer.write(static_cast<uint64_t>(Entry.Offset));
634a906e3ecSWei Mi     Writer.write(static_cast<uint64_t>(Entry.Size));
635be907324SWei Mi   }
636be907324SWei Mi 
637be907324SWei Mi   // Reset OutputStream.
638be907324SWei Mi   if (OFS.seek(Saved) == (uint64_t)-1)
639be907324SWei Mi     return sampleprof_error::ostream_seek_unsupported;
640be907324SWei Mi 
641be907324SWei Mi   return sampleprof_error::success;
642be907324SWei Mi }
643be907324SWei Mi 
644be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeHeader(
645be907324SWei Mi     const StringMap<FunctionSamples> &ProfileMap) {
646be907324SWei Mi   auto &OS = *OutputStream;
647be907324SWei Mi   FileStart = OS.tell();
648be907324SWei Mi   writeMagicIdent(Format);
649be907324SWei Mi 
650be907324SWei Mi   allocSecHdrTable();
651be907324SWei Mi   return sampleprof_error::success;
652be907324SWei Mi }
653be907324SWei Mi 
6546a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::writeHeader(
6556a14325dSWei Mi     const StringMap<FunctionSamples> &ProfileMap) {
6566a14325dSWei Mi   support::endian::Writer Writer(*OutputStream, support::little);
6576a14325dSWei Mi   if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap))
6586a14325dSWei Mi     return EC;
6596a14325dSWei Mi 
6606a14325dSWei Mi   // Reserve a slot for the offset of function offset table. The slot will
6616a14325dSWei Mi   // be populated with the offset of FuncOffsetTable later.
6626a14325dSWei Mi   TableOffset = OutputStream->tell();
6636a14325dSWei Mi   Writer.write(static_cast<uint64_t>(-2));
6646a14325dSWei Mi   return sampleprof_error::success;
6656a14325dSWei Mi }
6666a14325dSWei Mi 
66740ee23dbSEaswaran Raman std::error_code SampleProfileWriterBinary::writeSummary() {
66840ee23dbSEaswaran Raman   auto &OS = *OutputStream;
6697cefdb81SEaswaran Raman   encodeULEB128(Summary->getTotalCount(), OS);
6707cefdb81SEaswaran Raman   encodeULEB128(Summary->getMaxCount(), OS);
6716f4903d9SEaswaran Raman   encodeULEB128(Summary->getMaxFunctionCount(), OS);
6727cefdb81SEaswaran Raman   encodeULEB128(Summary->getNumCounts(), OS);
67340ee23dbSEaswaran Raman   encodeULEB128(Summary->getNumFunctions(), OS);
67440ee23dbSEaswaran Raman   std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary();
67540ee23dbSEaswaran Raman   encodeULEB128(Entries.size(), OS);
67640ee23dbSEaswaran Raman   for (auto Entry : Entries) {
67740ee23dbSEaswaran Raman     encodeULEB128(Entry.Cutoff, OS);
67840ee23dbSEaswaran Raman     encodeULEB128(Entry.MinCount, OS);
67940ee23dbSEaswaran Raman     encodeULEB128(Entry.NumCounts, OS);
68040ee23dbSEaswaran Raman   }
68140ee23dbSEaswaran Raman   return sampleprof_error::success;
68240ee23dbSEaswaran Raman }
68357d1dda5SDehao Chen std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
68451abea74SNathan Slingerland   auto &OS = *OutputStream;
68551abea74SNathan Slingerland 
68600ef28efSWenlei He   if (std::error_code EC =
68700ef28efSWenlei He           writeNameIdx(S.getNameWithContext(), FunctionSamples::ProfileIsCS))
688760c5a8fSDiego Novillo     return EC;
689760c5a8fSDiego Novillo 
690c572e92cSDiego Novillo   encodeULEB128(S.getTotalSamples(), OS);
691a7f1e8efSDiego Novillo 
692a7f1e8efSDiego Novillo   // Emit all the body samples.
693b93483dbSDiego Novillo   encodeULEB128(S.getBodySamples().size(), OS);
694d5336ae2SDiego Novillo   for (const auto &I : S.getBodySamples()) {
695d5336ae2SDiego Novillo     LineLocation Loc = I.first;
696d5336ae2SDiego Novillo     const SampleRecord &Sample = I.second;
697c572e92cSDiego Novillo     encodeULEB128(Loc.LineOffset, OS);
698c572e92cSDiego Novillo     encodeULEB128(Loc.Discriminator, OS);
699c572e92cSDiego Novillo     encodeULEB128(Sample.getSamples(), OS);
700c572e92cSDiego Novillo     encodeULEB128(Sample.getCallTargets().size(), OS);
7015adace35SWenlei He     for (const auto &J : Sample.getSortedCallTargets()) {
7025adace35SWenlei He       StringRef Callee = J.first;
70338be3330SDiego Novillo       uint64_t CalleeSamples = J.second;
704760c5a8fSDiego Novillo       if (std::error_code EC = writeNameIdx(Callee))
705760c5a8fSDiego Novillo         return EC;
706c572e92cSDiego Novillo       encodeULEB128(CalleeSamples, OS);
707c572e92cSDiego Novillo     }
708c572e92cSDiego Novillo   }
709c572e92cSDiego Novillo 
710a7f1e8efSDiego Novillo   // Recursively emit all the callsite samples.
7112c27daf7SDehao Chen   uint64_t NumCallsites = 0;
7122c27daf7SDehao Chen   for (const auto &J : S.getCallsiteSamples())
7132c27daf7SDehao Chen     NumCallsites += J.second.size();
7142c27daf7SDehao Chen   encodeULEB128(NumCallsites, OS);
7152c7ca9b5SDehao Chen   for (const auto &J : S.getCallsiteSamples())
7162c7ca9b5SDehao Chen     for (const auto &FS : J.second) {
71757d1dda5SDehao Chen       LineLocation Loc = J.first;
7182c7ca9b5SDehao Chen       const FunctionSamples &CalleeSamples = FS.second;
719a7f1e8efSDiego Novillo       encodeULEB128(Loc.LineOffset, OS);
720a7f1e8efSDiego Novillo       encodeULEB128(Loc.Discriminator, OS);
72157d1dda5SDehao Chen       if (std::error_code EC = writeBody(CalleeSamples))
722760c5a8fSDiego Novillo         return EC;
723a7f1e8efSDiego Novillo     }
724a7f1e8efSDiego Novillo 
725760c5a8fSDiego Novillo   return sampleprof_error::success;
726c572e92cSDiego Novillo }
727d5336ae2SDiego Novillo 
7285f8f34e4SAdrian Prantl /// Write samples of a top-level function to a binary file.
729b93483dbSDiego Novillo ///
730b93483dbSDiego Novillo /// \returns true if the samples were written successfully, false otherwise.
731be907324SWei Mi std::error_code
732be907324SWei Mi SampleProfileWriterBinary::writeSample(const FunctionSamples &S) {
73351abea74SNathan Slingerland   encodeULEB128(S.getHeadSamples(), *OutputStream);
73457d1dda5SDehao Chen   return writeBody(S);
735b93483dbSDiego Novillo }
736b93483dbSDiego Novillo 
7376a14325dSWei Mi std::error_code
738be907324SWei Mi SampleProfileWriterCompactBinary::writeSample(const FunctionSamples &S) {
7396a14325dSWei Mi   uint64_t Offset = OutputStream->tell();
7406a14325dSWei Mi   StringRef Name = S.getName();
7416a14325dSWei Mi   FuncOffsetTable[Name] = Offset;
7426a14325dSWei Mi   encodeULEB128(S.getHeadSamples(), *OutputStream);
7436a14325dSWei Mi   return writeBody(S);
7446a14325dSWei Mi }
7456a14325dSWei Mi 
7465f8f34e4SAdrian Prantl /// Create a sample profile file writer based on the specified format.
747d5336ae2SDiego Novillo ///
748d5336ae2SDiego Novillo /// \param Filename The file to create.
749d5336ae2SDiego Novillo ///
750d5336ae2SDiego Novillo /// \param Format Encoding format for the profile file.
751d5336ae2SDiego Novillo ///
752d5336ae2SDiego Novillo /// \returns an error code indicating the status of the created writer.
753fcd55607SDiego Novillo ErrorOr<std::unique_ptr<SampleProfileWriter>>
754fcd55607SDiego Novillo SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
755d5336ae2SDiego Novillo   std::error_code EC;
75651abea74SNathan Slingerland   std::unique_ptr<raw_ostream> OS;
757be907324SWei Mi   if (Format == SPF_Binary || Format == SPF_Ext_Binary ||
758be907324SWei Mi       Format == SPF_Compact_Binary)
759d9b948b6SFangrui Song     OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None));
76051abea74SNathan Slingerland   else
76182b3e28eSAbhina Sreeskantharajan     OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_TextWithCRLF));
76251abea74SNathan Slingerland   if (EC)
76351abea74SNathan Slingerland     return EC;
76451abea74SNathan Slingerland 
76551abea74SNathan Slingerland   return create(OS, Format);
76651abea74SNathan Slingerland }
76751abea74SNathan Slingerland 
7685f8f34e4SAdrian Prantl /// Create a sample profile stream writer based on the specified format.
76951abea74SNathan Slingerland ///
77051abea74SNathan Slingerland /// \param OS The output stream to store the profile data to.
77151abea74SNathan Slingerland ///
77251abea74SNathan Slingerland /// \param Format Encoding format for the profile file.
77351abea74SNathan Slingerland ///
77451abea74SNathan Slingerland /// \returns an error code indicating the status of the created writer.
77551abea74SNathan Slingerland ErrorOr<std::unique_ptr<SampleProfileWriter>>
77651abea74SNathan Slingerland SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
77751abea74SNathan Slingerland                             SampleProfileFormat Format) {
77851abea74SNathan Slingerland   std::error_code EC;
779fcd55607SDiego Novillo   std::unique_ptr<SampleProfileWriter> Writer;
780d5336ae2SDiego Novillo 
781b2d07937SWenlei He   // Currently only Text and Extended Binary format are supported for CSSPGO.
782b2d07937SWenlei He   if ((FunctionSamples::ProfileIsCS || FunctionSamples::ProfileIsProbeBased) &&
783b2d07937SWenlei He       (Format == SPF_Binary || Format == SPF_Compact_Binary))
784b2d07937SWenlei He     return sampleprof_error::unsupported_writing_format;
785b2d07937SWenlei He 
786d9be2c7eSWei Mi   if (Format == SPF_Binary)
787a0c0857eSWei Mi     Writer.reset(new SampleProfileWriterRawBinary(OS));
788be907324SWei Mi   else if (Format == SPF_Ext_Binary)
789be907324SWei Mi     Writer.reset(new SampleProfileWriterExtBinary(OS));
790a0c0857eSWei Mi   else if (Format == SPF_Compact_Binary)
791a0c0857eSWei Mi     Writer.reset(new SampleProfileWriterCompactBinary(OS));
792d5336ae2SDiego Novillo   else if (Format == SPF_Text)
79351abea74SNathan Slingerland     Writer.reset(new SampleProfileWriterText(OS));
794760c5a8fSDiego Novillo   else if (Format == SPF_GCC)
795760c5a8fSDiego Novillo     EC = sampleprof_error::unsupported_writing_format;
796d5336ae2SDiego Novillo   else
797d5336ae2SDiego Novillo     EC = sampleprof_error::unrecognized_format;
798d5336ae2SDiego Novillo 
799fcd55607SDiego Novillo   if (EC)
800d5336ae2SDiego Novillo     return EC;
801fcd55607SDiego Novillo 
802be907324SWei Mi   Writer->Format = Format;
803c55cf4afSBill Wendling   return std::move(Writer);
804d5336ae2SDiego Novillo }
80540ee23dbSEaswaran Raman 
80640ee23dbSEaswaran Raman void SampleProfileWriter::computeSummary(
80740ee23dbSEaswaran Raman     const StringMap<FunctionSamples> &ProfileMap) {
808e5a17e3fSEaswaran Raman   SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
809801d9cc7SWenlei He   Summary = Builder.computeSummaryForProfiles(ProfileMap);
81040ee23dbSEaswaran Raman }
811