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"
22e78d131aSEugene Zelenko #include "llvm/ProfileData/ProfileCommon.h"
23e78d131aSEugene Zelenko #include "llvm/ProfileData/SampleProf.h"
24b523790aSWei Mi #include "llvm/Support/Compression.h"
256a14325dSWei Mi #include "llvm/Support/Endian.h"
266a14325dSWei Mi #include "llvm/Support/EndianStream.h"
27c572e92cSDiego Novillo #include "llvm/Support/ErrorOr.h"
28e78d131aSEugene Zelenko #include "llvm/Support/FileSystem.h"
29c572e92cSDiego Novillo #include "llvm/Support/LEB128.h"
30a0c0857eSWei Mi #include "llvm/Support/MD5.h"
31e78d131aSEugene Zelenko #include "llvm/Support/raw_ostream.h"
32e78d131aSEugene Zelenko #include <algorithm>
33e78d131aSEugene Zelenko #include <cstdint>
34e78d131aSEugene Zelenko #include <memory>
358d1c983fSDehao Chen #include <set>
36e78d131aSEugene Zelenko #include <system_error>
37e78d131aSEugene Zelenko #include <utility>
38e78d131aSEugene Zelenko #include <vector>
39c572e92cSDiego Novillo 
40c572e92cSDiego Novillo using namespace llvm;
41e78d131aSEugene Zelenko using namespace sampleprof;
42c572e92cSDiego Novillo 
43b9db7036SHongtao Yu std::error_code
writeFuncProfiles(const SampleProfileMap & ProfileMap)44b9db7036SHongtao Yu SampleProfileWriter::writeFuncProfiles(const SampleProfileMap &ProfileMap) {
458d1c983fSDehao Chen   std::vector<NameFunctionSamples> V;
46f27fee62SHongtao Yu   sortFuncProfiles(ProfileMap, V);
478d1c983fSDehao Chen   for (const auto &I : V) {
48be907324SWei Mi     if (std::error_code EC = writeSample(*I.second))
498d1c983fSDehao Chen       return EC;
508d1c983fSDehao Chen   }
518d1c983fSDehao Chen   return sampleprof_error::success;
528d1c983fSDehao Chen }
538d1c983fSDehao Chen 
write(const SampleProfileMap & ProfileMap)54b9db7036SHongtao Yu std::error_code SampleProfileWriter::write(const SampleProfileMap &ProfileMap) {
55be907324SWei Mi   if (std::error_code EC = writeHeader(ProfileMap))
56be907324SWei Mi     return EC;
57be907324SWei Mi 
58be907324SWei Mi   if (std::error_code EC = writeFuncProfiles(ProfileMap))
59be907324SWei Mi     return EC;
60be907324SWei Mi 
61be907324SWei Mi   return sampleprof_error::success;
62be907324SWei Mi }
63be907324SWei Mi 
64b523790aSWei Mi /// Return the current position and prepare to use it as the start
65a906e3ecSWei Mi /// position of a section given the section type \p Type and its position
66a906e3ecSWei Mi /// \p LayoutIdx in SectionHdrLayout.
67a906e3ecSWei Mi uint64_t
markSectionStart(SecType Type,uint32_t LayoutIdx)68a906e3ecSWei Mi SampleProfileWriterExtBinaryBase::markSectionStart(SecType Type,
69a906e3ecSWei Mi                                                    uint32_t LayoutIdx) {
70b523790aSWei Mi   uint64_t SectionStart = OutputStream->tell();
71a906e3ecSWei Mi   assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range");
72a906e3ecSWei Mi   const auto &Entry = SectionHdrLayout[LayoutIdx];
73a906e3ecSWei Mi   assert(Entry.Type == Type && "Unexpected section type");
74b523790aSWei Mi   // Use LocalBuf as a temporary output for writting data.
75ebad6788SWei Mi   if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress))
76b523790aSWei Mi     LocalBufStream.swap(OutputStream);
77b523790aSWei Mi   return SectionStart;
78b523790aSWei Mi }
79b523790aSWei Mi 
compressAndOutput()80b523790aSWei Mi std::error_code SampleProfileWriterExtBinaryBase::compressAndOutput() {
81ea61750cSCole Kissane   if (!llvm::compression::zlib::isAvailable())
82b523790aSWei Mi     return sampleprof_error::zlib_unavailable;
83b523790aSWei Mi   std::string &UncompressedStrings =
84b523790aSWei Mi       static_cast<raw_string_ostream *>(LocalBufStream.get())->str();
85b523790aSWei Mi   if (UncompressedStrings.size() == 0)
86b523790aSWei Mi     return sampleprof_error::success;
87b523790aSWei Mi   auto &OS = *OutputStream;
88*e690137dSFangrui Song   SmallVector<uint8_t, 128> CompressedStrings;
89*e690137dSFangrui Song   compression::zlib::compress(arrayRefFromStringRef(UncompressedStrings),
90*e690137dSFangrui Song                               CompressedStrings,
91ea61750cSCole Kissane                               compression::zlib::BestSizeCompression);
92b523790aSWei Mi   encodeULEB128(UncompressedStrings.size(), OS);
93b523790aSWei Mi   encodeULEB128(CompressedStrings.size(), OS);
94*e690137dSFangrui Song   OS << toStringRef(CompressedStrings);
95b523790aSWei Mi   UncompressedStrings.clear();
96b523790aSWei Mi   return sampleprof_error::success;
97b523790aSWei Mi }
98b523790aSWei Mi 
99a906e3ecSWei Mi /// Add a new section into section header table given the section type
100a906e3ecSWei Mi /// \p Type, its position \p LayoutIdx in SectionHdrLayout and the
101a906e3ecSWei Mi /// location \p SectionStart where the section should be written to.
addNewSection(SecType Type,uint32_t LayoutIdx,uint64_t SectionStart)102a906e3ecSWei Mi std::error_code SampleProfileWriterExtBinaryBase::addNewSection(
103a906e3ecSWei Mi     SecType Type, uint32_t LayoutIdx, uint64_t SectionStart) {
104a906e3ecSWei Mi   assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range");
105a906e3ecSWei Mi   const auto &Entry = SectionHdrLayout[LayoutIdx];
106a906e3ecSWei Mi   assert(Entry.Type == Type && "Unexpected section type");
107ebad6788SWei Mi   if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress)) {
108b523790aSWei Mi     LocalBufStream.swap(OutputStream);
109b523790aSWei Mi     if (std::error_code EC = compressAndOutput())
110b523790aSWei Mi       return EC;
111b523790aSWei Mi   }
112b523790aSWei Mi   SecHdrTable.push_back({Type, Entry.Flags, SectionStart - FileStart,
113a906e3ecSWei Mi                          OutputStream->tell() - SectionStart, LayoutIdx});
114b523790aSWei Mi   return sampleprof_error::success;
115be907324SWei Mi }
116be907324SWei Mi 
117b9db7036SHongtao Yu std::error_code
write(const SampleProfileMap & ProfileMap)118b9db7036SHongtao Yu SampleProfileWriterExtBinaryBase::write(const SampleProfileMap &ProfileMap) {
119be907324SWei Mi   if (std::error_code EC = writeHeader(ProfileMap))
120be907324SWei Mi     return EC;
121be907324SWei Mi 
122b523790aSWei Mi   std::string LocalBuf;
123b523790aSWei Mi   LocalBufStream = std::make_unique<raw_string_ostream>(LocalBuf);
124be907324SWei Mi   if (std::error_code EC = writeSections(ProfileMap))
125be907324SWei Mi     return EC;
126be907324SWei Mi 
127be907324SWei Mi   if (std::error_code EC = writeSecHdrTable())
128be907324SWei Mi     return EC;
129be907324SWei Mi 
130be907324SWei Mi   return sampleprof_error::success;
131be907324SWei Mi }
132be907324SWei Mi 
writeContextIdx(const SampleContext & Context)133b9db7036SHongtao Yu std::error_code SampleProfileWriterExtBinaryBase::writeContextIdx(
134b9db7036SHongtao Yu     const SampleContext &Context) {
135b9db7036SHongtao Yu   if (Context.hasContext())
136b9db7036SHongtao Yu     return writeCSNameIdx(Context);
137b9db7036SHongtao Yu   else
138b9db7036SHongtao Yu     return SampleProfileWriterBinary::writeNameIdx(Context.getName());
139b9db7036SHongtao Yu }
140b9db7036SHongtao Yu 
141b9db7036SHongtao Yu std::error_code
writeCSNameIdx(const SampleContext & Context)142b9db7036SHongtao Yu SampleProfileWriterExtBinaryBase::writeCSNameIdx(const SampleContext &Context) {
143b9db7036SHongtao Yu   const auto &Ret = CSNameTable.find(Context);
144b9db7036SHongtao Yu   if (Ret == CSNameTable.end())
145b9db7036SHongtao Yu     return sampleprof_error::truncated_name_table;
146b9db7036SHongtao Yu   encodeULEB128(Ret->second, *OutputStream);
147b9db7036SHongtao Yu   return sampleprof_error::success;
148b9db7036SHongtao Yu }
149b9db7036SHongtao Yu 
15009dcfe68SWei Mi std::error_code
writeSample(const FunctionSamples & S)15193953d41SWei Mi SampleProfileWriterExtBinaryBase::writeSample(const FunctionSamples &S) {
15209dcfe68SWei Mi   uint64_t Offset = OutputStream->tell();
153b9db7036SHongtao Yu   auto &Context = S.getContext();
154b9db7036SHongtao Yu   FuncOffsetTable[Context] = Offset - SecLBRProfileStart;
15509dcfe68SWei Mi   encodeULEB128(S.getHeadSamples(), *OutputStream);
15609dcfe68SWei Mi   return writeBody(S);
15709dcfe68SWei Mi }
15809dcfe68SWei Mi 
writeFuncOffsetTable()15993953d41SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeFuncOffsetTable() {
16009dcfe68SWei Mi   auto &OS = *OutputStream;
16109dcfe68SWei Mi 
16209dcfe68SWei Mi   // Write out the table size.
16309dcfe68SWei Mi   encodeULEB128(FuncOffsetTable.size(), OS);
16409dcfe68SWei Mi 
16509dcfe68SWei Mi   // Write out FuncOffsetTable.
166f4711e0dSHongtao Yu   auto WriteItem = [&](const SampleContext &Context, uint64_t Offset) {
167f4711e0dSHongtao Yu     if (std::error_code EC = writeContextIdx(Context))
16800ef28efSWenlei He       return EC;
169f4711e0dSHongtao Yu     encodeULEB128(Offset, OS);
170f4711e0dSHongtao Yu     return (std::error_code)sampleprof_error::success;
171f4711e0dSHongtao Yu   };
172f4711e0dSHongtao Yu 
173e36786d1SHongtao Yu   if (FunctionSamples::ProfileIsCS) {
174f4711e0dSHongtao Yu     // Sort the contexts before writing them out. This is to help fast load all
175f4711e0dSHongtao Yu     // context profiles for a function as well as their callee contexts which
176f4711e0dSHongtao Yu     // can help profile-guided importing for ThinLTO.
177f4711e0dSHongtao Yu     std::map<SampleContext, uint64_t> OrderedFuncOffsetTable(
178f4711e0dSHongtao Yu         FuncOffsetTable.begin(), FuncOffsetTable.end());
179f4711e0dSHongtao Yu     for (const auto &Entry : OrderedFuncOffsetTable) {
180f4711e0dSHongtao Yu       if (std::error_code EC = WriteItem(Entry.first, Entry.second))
181f4711e0dSHongtao Yu         return EC;
18209dcfe68SWei Mi     }
183f4711e0dSHongtao Yu     addSectionFlag(SecFuncOffsetTable, SecFuncOffsetFlags::SecFlagOrdered);
184f4711e0dSHongtao Yu   } else {
185f4711e0dSHongtao Yu     for (const auto &Entry : FuncOffsetTable) {
186f4711e0dSHongtao Yu       if (std::error_code EC = WriteItem(Entry.first, Entry.second))
187f4711e0dSHongtao Yu         return EC;
188f4711e0dSHongtao Yu     }
189f4711e0dSHongtao Yu   }
190f4711e0dSHongtao Yu 
191a906e3ecSWei Mi   FuncOffsetTable.clear();
19209dcfe68SWei Mi   return sampleprof_error::success;
19309dcfe68SWei Mi }
19409dcfe68SWei Mi 
writeFuncMetadata(const FunctionSamples & FunctionProfile)195ac068e01SHongtao Yu std::error_code SampleProfileWriterExtBinaryBase::writeFuncMetadata(
1965740bb80SHongtao Yu     const FunctionSamples &FunctionProfile) {
197ac068e01SHongtao Yu   auto &OS = *OutputStream;
1985740bb80SHongtao Yu   if (std::error_code EC = writeContextIdx(FunctionProfile.getContext()))
19900ef28efSWenlei He     return EC;
2005740bb80SHongtao Yu 
2011410db70SWenlei He   if (FunctionSamples::ProfileIsProbeBased)
2025740bb80SHongtao Yu     encodeULEB128(FunctionProfile.getFunctionHash(), OS);
203e36786d1SHongtao Yu   if (FunctionSamples::ProfileIsCS || FunctionSamples::ProfileIsPreInlined) {
2045740bb80SHongtao Yu     encodeULEB128(FunctionProfile.getContext().getAllAttributes(), OS);
2055740bb80SHongtao Yu   }
2065740bb80SHongtao Yu 
207e36786d1SHongtao Yu   if (!FunctionSamples::ProfileIsCS) {
2085740bb80SHongtao Yu     // Recursively emit attributes for all callee samples.
2095740bb80SHongtao Yu     uint64_t NumCallsites = 0;
2105740bb80SHongtao Yu     for (const auto &J : FunctionProfile.getCallsiteSamples())
2115740bb80SHongtao Yu       NumCallsites += J.second.size();
2125740bb80SHongtao Yu     encodeULEB128(NumCallsites, OS);
2135740bb80SHongtao Yu     for (const auto &J : FunctionProfile.getCallsiteSamples()) {
2145740bb80SHongtao Yu       for (const auto &FS : J.second) {
2155740bb80SHongtao Yu         LineLocation Loc = J.first;
2165740bb80SHongtao Yu         encodeULEB128(Loc.LineOffset, OS);
2175740bb80SHongtao Yu         encodeULEB128(Loc.Discriminator, OS);
2185740bb80SHongtao Yu         if (std::error_code EC = writeFuncMetadata(FS.second))
2195740bb80SHongtao Yu           return EC;
2205740bb80SHongtao Yu       }
2215740bb80SHongtao Yu     }
2225740bb80SHongtao Yu   }
2235740bb80SHongtao Yu 
2245740bb80SHongtao Yu   return sampleprof_error::success;
2255740bb80SHongtao Yu }
2265740bb80SHongtao Yu 
writeFuncMetadata(const SampleProfileMap & Profiles)2275740bb80SHongtao Yu std::error_code SampleProfileWriterExtBinaryBase::writeFuncMetadata(
2285740bb80SHongtao Yu     const SampleProfileMap &Profiles) {
229e36786d1SHongtao Yu   if (!FunctionSamples::ProfileIsProbeBased && !FunctionSamples::ProfileIsCS &&
230e36786d1SHongtao Yu       !FunctionSamples::ProfileIsPreInlined)
2315740bb80SHongtao Yu     return sampleprof_error::success;
2325740bb80SHongtao Yu   for (const auto &Entry : Profiles) {
2335740bb80SHongtao Yu     if (std::error_code EC = writeFuncMetadata(Entry.second))
2345740bb80SHongtao Yu       return EC;
235ac068e01SHongtao Yu   }
236ac068e01SHongtao Yu   return sampleprof_error::success;
237ac068e01SHongtao Yu }
238ac068e01SHongtao Yu 
writeNameTable()23993953d41SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeNameTable() {
240ebad6788SWei Mi   if (!UseMD5)
241ebad6788SWei Mi     return SampleProfileWriterBinary::writeNameTable();
242ebad6788SWei Mi 
243ebad6788SWei Mi   auto &OS = *OutputStream;
244ebad6788SWei Mi   std::set<StringRef> V;
245b9db7036SHongtao Yu   stablizeNameTable(NameTable, V);
246ebad6788SWei Mi 
24764e76853SWei Mi   // Write out the MD5 name table. We wrote unencoded MD5 so reader can
24864e76853SWei Mi   // retrieve the name using the name index without having to read the
24964e76853SWei Mi   // whole name table.
250ebad6788SWei Mi   encodeULEB128(NameTable.size(), OS);
25164e76853SWei Mi   support::endian::Writer Writer(OS, support::little);
25264e76853SWei Mi   for (auto N : V)
25364e76853SWei Mi     Writer.write(MD5Hash(N));
254ebad6788SWei Mi   return sampleprof_error::success;
255ebad6788SWei Mi }
256ebad6788SWei Mi 
writeNameTableSection(const SampleProfileMap & ProfileMap)25793953d41SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeNameTableSection(
258b9db7036SHongtao Yu     const SampleProfileMap &ProfileMap) {
259be907324SWei Mi   for (const auto &I : ProfileMap) {
260b9db7036SHongtao Yu     assert(I.first == I.second.getContext() && "Inconsistent profile map");
261b9db7036SHongtao Yu     addContext(I.second.getContext());
262be907324SWei Mi     addNames(I.second);
263be907324SWei Mi   }
264ee35784aSWei Mi 
265ee35784aSWei Mi   // If NameTable contains ".__uniq." suffix, set SecFlagUniqSuffix flag
266ee35784aSWei Mi   // so compiler won't strip the suffix during profile matching after
267ee35784aSWei Mi   // seeing the flag in the profile.
268ee35784aSWei Mi   for (const auto &I : NameTable) {
269d14d7068SKazu Hirata     if (I.first.contains(FunctionSamples::UniqSuffix)) {
270ee35784aSWei Mi       addSectionFlag(SecNameTable, SecNameTableFlags::SecFlagUniqSuffix);
271ee35784aSWei Mi       break;
272ee35784aSWei Mi     }
273ee35784aSWei Mi   }
274ee35784aSWei Mi 
27593953d41SWei Mi   if (auto EC = writeNameTable())
276b523790aSWei Mi     return EC;
27793953d41SWei Mi   return sampleprof_error::success;
27893953d41SWei Mi }
279be907324SWei Mi 
writeCSNameTableSection()280b9db7036SHongtao Yu std::error_code SampleProfileWriterExtBinaryBase::writeCSNameTableSection() {
281b9db7036SHongtao Yu   // Sort the names to make CSNameTable deterministic.
282b9db7036SHongtao Yu   std::set<SampleContext> OrderedContexts;
283b9db7036SHongtao Yu   for (const auto &I : CSNameTable)
284b9db7036SHongtao Yu     OrderedContexts.insert(I.first);
285b9db7036SHongtao Yu   assert(OrderedContexts.size() == CSNameTable.size() &&
286b9db7036SHongtao Yu          "Unmatched ordered and unordered contexts");
287b9db7036SHongtao Yu   uint64_t I = 0;
288b9db7036SHongtao Yu   for (auto &Context : OrderedContexts)
289b9db7036SHongtao Yu     CSNameTable[Context] = I++;
290b9db7036SHongtao Yu 
291b9db7036SHongtao Yu   auto &OS = *OutputStream;
292b9db7036SHongtao Yu   encodeULEB128(OrderedContexts.size(), OS);
293b9db7036SHongtao Yu   support::endian::Writer Writer(OS, support::little);
294b9db7036SHongtao Yu   for (auto Context : OrderedContexts) {
295b9db7036SHongtao Yu     auto Frames = Context.getContextFrames();
296b9db7036SHongtao Yu     encodeULEB128(Frames.size(), OS);
297b9db7036SHongtao Yu     for (auto &Callsite : Frames) {
298fb29d812Swlei       if (std::error_code EC = writeNameIdx(Callsite.FuncName))
299b9db7036SHongtao Yu         return EC;
300fb29d812Swlei       encodeULEB128(Callsite.Location.LineOffset, OS);
301fb29d812Swlei       encodeULEB128(Callsite.Location.Discriminator, OS);
302b9db7036SHongtao Yu     }
303b9db7036SHongtao Yu   }
304b9db7036SHongtao Yu 
305b9db7036SHongtao Yu   return sampleprof_error::success;
306b9db7036SHongtao Yu }
307b9db7036SHongtao Yu 
30893953d41SWei Mi std::error_code
writeProfileSymbolListSection()30993953d41SWei Mi SampleProfileWriterExtBinaryBase::writeProfileSymbolListSection() {
310798e59b8SWei Mi   if (ProfSymList && ProfSymList->size() > 0)
311798e59b8SWei Mi     if (std::error_code EC = ProfSymList->write(*OutputStream))
312798e59b8SWei Mi       return EC;
313be907324SWei Mi 
31493953d41SWei Mi   return sampleprof_error::success;
31593953d41SWei Mi }
31609dcfe68SWei Mi 
writeOneSection(SecType Type,uint32_t LayoutIdx,const SampleProfileMap & ProfileMap)31793953d41SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeOneSection(
318b9db7036SHongtao Yu     SecType Type, uint32_t LayoutIdx, const SampleProfileMap &ProfileMap) {
31993953d41SWei Mi   // The setting of SecFlagCompress should happen before markSectionStart.
32093953d41SWei Mi   if (Type == SecProfileSymbolList && ProfSymList && ProfSymList->toCompress())
32193953d41SWei Mi     setToCompressSection(SecProfileSymbolList);
322ac068e01SHongtao Yu   if (Type == SecFuncMetadata && FunctionSamples::ProfileIsProbeBased)
323ac068e01SHongtao Yu     addSectionFlag(SecFuncMetadata, SecFuncMetadataFlags::SecFlagIsProbeBased);
3245740bb80SHongtao Yu   if (Type == SecFuncMetadata &&
325e36786d1SHongtao Yu       (FunctionSamples::ProfileIsCS || FunctionSamples::ProfileIsPreInlined))
3261410db70SWenlei He     addSectionFlag(SecFuncMetadata, SecFuncMetadataFlags::SecFlagHasAttribute);
327e36786d1SHongtao Yu   if (Type == SecProfSummary && FunctionSamples::ProfileIsCS)
3285740bb80SHongtao Yu     addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagFullContext);
329e36786d1SHongtao Yu   if (Type == SecProfSummary && FunctionSamples::ProfileIsPreInlined)
330e36786d1SHongtao Yu     addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagIsPreInlined);
3316745ffe4SRong Xu   if (Type == SecProfSummary && FunctionSamples::ProfileIsFS)
3326745ffe4SRong Xu     addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagFSDiscriminator);
33393953d41SWei Mi 
334a906e3ecSWei Mi   uint64_t SectionStart = markSectionStart(Type, LayoutIdx);
33593953d41SWei Mi   switch (Type) {
33693953d41SWei Mi   case SecProfSummary:
33793953d41SWei Mi     computeSummary(ProfileMap);
33893953d41SWei Mi     if (auto EC = writeSummary())
33993953d41SWei Mi       return EC;
34093953d41SWei Mi     break;
34193953d41SWei Mi   case SecNameTable:
34293953d41SWei Mi     if (auto EC = writeNameTableSection(ProfileMap))
34393953d41SWei Mi       return EC;
34493953d41SWei Mi     break;
345b9db7036SHongtao Yu   case SecCSNameTable:
346b9db7036SHongtao Yu     if (auto EC = writeCSNameTableSection())
347b9db7036SHongtao Yu       return EC;
348b9db7036SHongtao Yu     break;
34993953d41SWei Mi   case SecLBRProfile:
35093953d41SWei Mi     SecLBRProfileStart = OutputStream->tell();
35193953d41SWei Mi     if (std::error_code EC = writeFuncProfiles(ProfileMap))
35293953d41SWei Mi       return EC;
35393953d41SWei Mi     break;
35493953d41SWei Mi   case SecFuncOffsetTable:
35593953d41SWei Mi     if (auto EC = writeFuncOffsetTable())
35693953d41SWei Mi       return EC;
35793953d41SWei Mi     break;
358ac068e01SHongtao Yu   case SecFuncMetadata:
359ac068e01SHongtao Yu     if (std::error_code EC = writeFuncMetadata(ProfileMap))
360ac068e01SHongtao Yu       return EC;
361ac068e01SHongtao Yu     break;
36293953d41SWei Mi   case SecProfileSymbolList:
36393953d41SWei Mi     if (auto EC = writeProfileSymbolListSection())
36493953d41SWei Mi       return EC;
36593953d41SWei Mi     break;
36693953d41SWei Mi   default:
36793953d41SWei Mi     if (auto EC = writeCustomSection(Type))
36893953d41SWei Mi       return EC;
36993953d41SWei Mi     break;
37093953d41SWei Mi   }
371a906e3ecSWei Mi   if (std::error_code EC = addNewSection(Type, LayoutIdx, SectionStart))
37293953d41SWei Mi     return EC;
37393953d41SWei Mi   return sampleprof_error::success;
37493953d41SWei Mi }
37593953d41SWei Mi 
writeDefaultLayout(const SampleProfileMap & ProfileMap)37621b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeDefaultLayout(
377b9db7036SHongtao Yu     const SampleProfileMap &ProfileMap) {
378a906e3ecSWei Mi   // The const indices passed to writeOneSection below are specifying the
379a906e3ecSWei Mi   // positions of the sections in SectionHdrLayout. Look at
380a906e3ecSWei Mi   // initSectionHdrLayout to find out where each section is located in
381a906e3ecSWei Mi   // SectionHdrLayout.
382a906e3ecSWei Mi   if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap))
38393953d41SWei Mi     return EC;
384a906e3ecSWei Mi   if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap))
38593953d41SWei Mi     return EC;
386b9db7036SHongtao Yu   if (auto EC = writeOneSection(SecCSNameTable, 2, ProfileMap))
38793953d41SWei Mi     return EC;
388b9db7036SHongtao Yu   if (auto EC = writeOneSection(SecLBRProfile, 4, ProfileMap))
38993953d41SWei Mi     return EC;
390b9db7036SHongtao Yu   if (auto EC = writeOneSection(SecProfileSymbolList, 5, ProfileMap))
39193953d41SWei Mi     return EC;
392b9db7036SHongtao Yu   if (auto EC = writeOneSection(SecFuncOffsetTable, 3, ProfileMap))
393b9db7036SHongtao Yu     return EC;
394b9db7036SHongtao Yu   if (auto EC = writeOneSection(SecFuncMetadata, 6, ProfileMap))
395ac068e01SHongtao Yu     return EC;
396be907324SWei Mi   return sampleprof_error::success;
397be907324SWei Mi }
398be907324SWei Mi 
splitProfileMapToTwo(const SampleProfileMap & ProfileMap,SampleProfileMap & ContextProfileMap,SampleProfileMap & NoContextProfileMap)399b9db7036SHongtao Yu static void splitProfileMapToTwo(const SampleProfileMap &ProfileMap,
400b9db7036SHongtao Yu                                  SampleProfileMap &ContextProfileMap,
401b9db7036SHongtao Yu                                  SampleProfileMap &NoContextProfileMap) {
40221b1ad03SWei Mi   for (const auto &I : ProfileMap) {
40321b1ad03SWei Mi     if (I.second.getCallsiteSamples().size())
404b9db7036SHongtao Yu       ContextProfileMap.insert({I.first, I.second});
40521b1ad03SWei Mi     else
406b9db7036SHongtao Yu       NoContextProfileMap.insert({I.first, I.second});
40721b1ad03SWei Mi   }
40821b1ad03SWei Mi }
40921b1ad03SWei Mi 
writeCtxSplitLayout(const SampleProfileMap & ProfileMap)41021b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeCtxSplitLayout(
411b9db7036SHongtao Yu     const SampleProfileMap &ProfileMap) {
412b9db7036SHongtao Yu   SampleProfileMap ContextProfileMap, NoContextProfileMap;
41321b1ad03SWei Mi   splitProfileMapToTwo(ProfileMap, ContextProfileMap, NoContextProfileMap);
41421b1ad03SWei Mi 
41521b1ad03SWei Mi   if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap))
41621b1ad03SWei Mi     return EC;
41721b1ad03SWei Mi   if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap))
41821b1ad03SWei Mi     return EC;
41921b1ad03SWei Mi   if (auto EC = writeOneSection(SecLBRProfile, 3, ContextProfileMap))
42021b1ad03SWei Mi     return EC;
42121b1ad03SWei Mi   if (auto EC = writeOneSection(SecFuncOffsetTable, 2, ContextProfileMap))
42221b1ad03SWei Mi     return EC;
42321b1ad03SWei Mi   // Mark the section to have no context. Note section flag needs to be set
42421b1ad03SWei Mi   // before writing the section.
42521b1ad03SWei Mi   addSectionFlag(5, SecCommonFlags::SecFlagFlat);
42621b1ad03SWei Mi   if (auto EC = writeOneSection(SecLBRProfile, 5, NoContextProfileMap))
42721b1ad03SWei Mi     return EC;
42821b1ad03SWei Mi   // Mark the section to have no context. Note section flag needs to be set
42921b1ad03SWei Mi   // before writing the section.
43021b1ad03SWei Mi   addSectionFlag(4, SecCommonFlags::SecFlagFlat);
43121b1ad03SWei Mi   if (auto EC = writeOneSection(SecFuncOffsetTable, 4, NoContextProfileMap))
43221b1ad03SWei Mi     return EC;
43321b1ad03SWei Mi   if (auto EC = writeOneSection(SecProfileSymbolList, 6, ProfileMap))
43421b1ad03SWei Mi     return EC;
43521b1ad03SWei Mi   if (auto EC = writeOneSection(SecFuncMetadata, 7, ProfileMap))
43621b1ad03SWei Mi     return EC;
43721b1ad03SWei Mi 
43821b1ad03SWei Mi   return sampleprof_error::success;
43921b1ad03SWei Mi }
44021b1ad03SWei Mi 
writeSections(const SampleProfileMap & ProfileMap)44121b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeSections(
442b9db7036SHongtao Yu     const SampleProfileMap &ProfileMap) {
44321b1ad03SWei Mi   std::error_code EC;
44421b1ad03SWei Mi   if (SecLayout == DefaultLayout)
44521b1ad03SWei Mi     EC = writeDefaultLayout(ProfileMap);
44621b1ad03SWei Mi   else if (SecLayout == CtxSplitLayout)
44721b1ad03SWei Mi     EC = writeCtxSplitLayout(ProfileMap);
44821b1ad03SWei Mi   else
44921b1ad03SWei Mi     llvm_unreachable("Unsupported layout");
45021b1ad03SWei Mi   return EC;
45121b1ad03SWei Mi }
45221b1ad03SWei Mi 
453b9db7036SHongtao Yu std::error_code
write(const SampleProfileMap & ProfileMap)454b9db7036SHongtao Yu SampleProfileWriterCompactBinary::write(const SampleProfileMap &ProfileMap) {
4556a14325dSWei Mi   if (std::error_code EC = SampleProfileWriter::write(ProfileMap))
4566a14325dSWei Mi     return EC;
4576a14325dSWei Mi   if (std::error_code EC = writeFuncOffsetTable())
4586a14325dSWei Mi     return EC;
4596a14325dSWei Mi   return sampleprof_error::success;
4606a14325dSWei Mi }
4616a14325dSWei Mi 
4625f8f34e4SAdrian Prantl /// Write samples to a text file.
4638e415a82SDiego Novillo ///
4648e415a82SDiego Novillo /// Note: it may be tempting to implement this in terms of
465ef548d29SDiego Novillo /// FunctionSamples::print().  Please don't.  The dump functionality is intended
4668e415a82SDiego Novillo /// for debugging and has no specified form.
4678e415a82SDiego Novillo ///
4688e415a82SDiego Novillo /// The format used here is more structured and deliberate because
4698e415a82SDiego Novillo /// it needs to be parsed by the SampleProfileReaderText class.
writeSample(const FunctionSamples & S)470be907324SWei Mi std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) {
47151abea74SNathan Slingerland   auto &OS = *OutputStream;
472e36786d1SHongtao Yu   if (FunctionSamples::ProfileIsCS)
473b9db7036SHongtao Yu     OS << "[" << S.getContext().toString() << "]:" << S.getTotalSamples();
47400ef28efSWenlei He   else
47500ef28efSWenlei He     OS << S.getName() << ":" << S.getTotalSamples();
47600ef28efSWenlei He 
477aae1ed8eSDiego Novillo   if (Indent == 0)
478aae1ed8eSDiego Novillo     OS << ":" << S.getHeadSamples();
479aae1ed8eSDiego Novillo   OS << "\n";
480c572e92cSDiego Novillo 
481ef548d29SDiego Novillo   SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples());
482ef548d29SDiego Novillo   for (const auto &I : SortedSamples.get()) {
483ef548d29SDiego Novillo     LineLocation Loc = I->first;
484ef548d29SDiego Novillo     const SampleRecord &Sample = I->second;
485aae1ed8eSDiego Novillo     OS.indent(Indent + 1);
486c572e92cSDiego Novillo     if (Loc.Discriminator == 0)
487c572e92cSDiego Novillo       OS << Loc.LineOffset << ": ";
488c572e92cSDiego Novillo     else
489c572e92cSDiego Novillo       OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
490c572e92cSDiego Novillo 
491c572e92cSDiego Novillo     OS << Sample.getSamples();
492c572e92cSDiego Novillo 
4935adace35SWenlei He     for (const auto &J : Sample.getSortedCallTargets())
4945adace35SWenlei He       OS << " " << J.first << ":" << J.second;
495c572e92cSDiego Novillo     OS << "\n";
496c572e92cSDiego Novillo   }
497c572e92cSDiego Novillo 
4982c7ca9b5SDehao Chen   SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples(
499ef548d29SDiego Novillo       S.getCallsiteSamples());
500aae1ed8eSDiego Novillo   Indent += 1;
5012c7ca9b5SDehao Chen   for (const auto &I : SortedCallsiteSamples.get())
5022c7ca9b5SDehao Chen     for (const auto &FS : I->second) {
50357d1dda5SDehao Chen       LineLocation Loc = I->first;
5042c7ca9b5SDehao Chen       const FunctionSamples &CalleeSamples = FS.second;
505aae1ed8eSDiego Novillo       OS.indent(Indent);
506aae1ed8eSDiego Novillo       if (Loc.Discriminator == 0)
507aae1ed8eSDiego Novillo         OS << Loc.LineOffset << ": ";
508aae1ed8eSDiego Novillo       else
509aae1ed8eSDiego Novillo         OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
510be907324SWei Mi       if (std::error_code EC = writeSample(CalleeSamples))
511760c5a8fSDiego Novillo         return EC;
512aae1ed8eSDiego Novillo     }
513aae1ed8eSDiego Novillo   Indent -= 1;
514aae1ed8eSDiego Novillo 
515ac068e01SHongtao Yu   if (FunctionSamples::ProfileIsProbeBased) {
516ac068e01SHongtao Yu     OS.indent(Indent + 1);
517ac068e01SHongtao Yu     OS << "!CFGChecksum: " << S.getFunctionHash() << "\n";
518ac068e01SHongtao Yu   }
5195740bb80SHongtao Yu 
5205740bb80SHongtao Yu   if (S.getContext().getAllAttributes()) {
5211410db70SWenlei He     OS.indent(Indent + 1);
5221410db70SWenlei He     OS << "!Attributes: " << S.getContext().getAllAttributes() << "\n";
5231410db70SWenlei He   }
524ac068e01SHongtao Yu 
525760c5a8fSDiego Novillo   return sampleprof_error::success;
526c572e92cSDiego Novillo }
527c572e92cSDiego Novillo 
528b9db7036SHongtao Yu std::error_code
writeContextIdx(const SampleContext & Context)529b9db7036SHongtao Yu SampleProfileWriterBinary::writeContextIdx(const SampleContext &Context) {
530b9db7036SHongtao Yu   assert(!Context.hasContext() && "cs profile is not supported");
531b9db7036SHongtao Yu   return writeNameIdx(Context.getName());
53200ef28efSWenlei He }
53300ef28efSWenlei He 
writeNameIdx(StringRef FName)534b9db7036SHongtao Yu std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) {
535b9db7036SHongtao Yu   auto &NTable = getNameTable();
536b9db7036SHongtao Yu   const auto &Ret = NTable.find(FName);
537b9db7036SHongtao Yu   if (Ret == NTable.end())
538760c5a8fSDiego Novillo     return sampleprof_error::truncated_name_table;
53900ef28efSWenlei He   encodeULEB128(Ret->second, *OutputStream);
540760c5a8fSDiego Novillo   return sampleprof_error::success;
541760c5a8fSDiego Novillo }
542c572e92cSDiego Novillo 
addName(StringRef FName)543b9db7036SHongtao Yu void SampleProfileWriterBinary::addName(StringRef FName) {
544b9db7036SHongtao Yu   auto &NTable = getNameTable();
545b9db7036SHongtao Yu   NTable.insert(std::make_pair(FName, 0));
54600ef28efSWenlei He }
547b9db7036SHongtao Yu 
addContext(const SampleContext & Context)548b9db7036SHongtao Yu void SampleProfileWriterBinary::addContext(const SampleContext &Context) {
549b9db7036SHongtao Yu   addName(Context.getName());
550760c5a8fSDiego Novillo }
551760c5a8fSDiego Novillo 
addNames(const FunctionSamples & S)552760c5a8fSDiego Novillo void SampleProfileWriterBinary::addNames(const FunctionSamples &S) {
553760c5a8fSDiego Novillo   // Add all the names in indirect call targets.
554760c5a8fSDiego Novillo   for (const auto &I : S.getBodySamples()) {
555760c5a8fSDiego Novillo     const SampleRecord &Sample = I.second;
556760c5a8fSDiego Novillo     for (const auto &J : Sample.getCallTargets())
557760c5a8fSDiego Novillo       addName(J.first());
558760c5a8fSDiego Novillo   }
559760c5a8fSDiego Novillo 
560760c5a8fSDiego Novillo   // Recursively add all the names for inlined callsites.
5612c7ca9b5SDehao Chen   for (const auto &J : S.getCallsiteSamples())
5622c7ca9b5SDehao Chen     for (const auto &FS : J.second) {
5632c7ca9b5SDehao Chen       const FunctionSamples &CalleeSamples = FS.second;
56457d1dda5SDehao Chen       addName(CalleeSamples.getName());
565760c5a8fSDiego Novillo       addNames(CalleeSamples);
566760c5a8fSDiego Novillo     }
567760c5a8fSDiego Novillo }
568760c5a8fSDiego Novillo 
addContext(const SampleContext & Context)569b9db7036SHongtao Yu void SampleProfileWriterExtBinaryBase::addContext(
570b9db7036SHongtao Yu     const SampleContext &Context) {
571b9db7036SHongtao Yu   if (Context.hasContext()) {
572b9db7036SHongtao Yu     for (auto &Callsite : Context.getContextFrames())
573fb29d812Swlei       SampleProfileWriterBinary::addName(Callsite.FuncName);
574b9db7036SHongtao Yu     CSNameTable.insert(std::make_pair(Context, 0));
575b9db7036SHongtao Yu   } else {
576b9db7036SHongtao Yu     SampleProfileWriterBinary::addName(Context.getName());
577b9db7036SHongtao Yu   }
578b9db7036SHongtao Yu }
579b9db7036SHongtao Yu 
stablizeNameTable(MapVector<StringRef,uint32_t> & NameTable,std::set<StringRef> & V)580b9db7036SHongtao Yu void SampleProfileWriterBinary::stablizeNameTable(
581b9db7036SHongtao Yu     MapVector<StringRef, uint32_t> &NameTable, std::set<StringRef> &V) {
582a0c0857eSWei Mi   // Sort the names to make NameTable deterministic.
583a0c0857eSWei Mi   for (const auto &I : NameTable)
584a0c0857eSWei Mi     V.insert(I.first);
585a0c0857eSWei Mi   int i = 0;
586a0c0857eSWei Mi   for (const StringRef &N : V)
587a0c0857eSWei Mi     NameTable[N] = i++;
588a0c0857eSWei Mi }
58951abea74SNathan Slingerland 
writeNameTable()590be907324SWei Mi std::error_code SampleProfileWriterBinary::writeNameTable() {
591a0c0857eSWei Mi   auto &OS = *OutputStream;
592a0c0857eSWei Mi   std::set<StringRef> V;
593b9db7036SHongtao Yu   stablizeNameTable(NameTable, V);
594a0c0857eSWei Mi 
595a0c0857eSWei Mi   // Write out the name table.
596a0c0857eSWei Mi   encodeULEB128(NameTable.size(), OS);
597a0c0857eSWei Mi   for (auto N : V) {
598a0c0857eSWei Mi     OS << N;
599a0c0857eSWei Mi     encodeULEB128(0, OS);
600a0c0857eSWei Mi   }
601a0c0857eSWei Mi   return sampleprof_error::success;
602a0c0857eSWei Mi }
603a0c0857eSWei Mi 
writeFuncOffsetTable()6046a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() {
6056a14325dSWei Mi   auto &OS = *OutputStream;
6066a14325dSWei Mi 
6076a14325dSWei Mi   // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable.
6086a14325dSWei Mi   auto &OFS = static_cast<raw_fd_ostream &>(OS);
6096a14325dSWei Mi   uint64_t FuncOffsetTableStart = OS.tell();
6106a14325dSWei Mi   if (OFS.seek(TableOffset) == (uint64_t)-1)
6116a14325dSWei Mi     return sampleprof_error::ostream_seek_unsupported;
6126a14325dSWei Mi   support::endian::Writer Writer(*OutputStream, support::little);
6136a14325dSWei Mi   Writer.write(FuncOffsetTableStart);
6146a14325dSWei Mi   if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1)
6156a14325dSWei Mi     return sampleprof_error::ostream_seek_unsupported;
6166a14325dSWei Mi 
6176a14325dSWei Mi   // Write out the table size.
6186a14325dSWei Mi   encodeULEB128(FuncOffsetTable.size(), OS);
6196a14325dSWei Mi 
6206a14325dSWei Mi   // Write out FuncOffsetTable.
62100ef28efSWenlei He   for (auto Entry : FuncOffsetTable) {
622b9db7036SHongtao Yu     if (std::error_code EC = writeNameIdx(Entry.first))
62300ef28efSWenlei He       return EC;
62400ef28efSWenlei He     encodeULEB128(Entry.second, OS);
6256a14325dSWei Mi   }
6266a14325dSWei Mi   return sampleprof_error::success;
6276a14325dSWei Mi }
6286a14325dSWei Mi 
writeNameTable()629a0c0857eSWei Mi std::error_code SampleProfileWriterCompactBinary::writeNameTable() {
630a0c0857eSWei Mi   auto &OS = *OutputStream;
631a0c0857eSWei Mi   std::set<StringRef> V;
632b9db7036SHongtao Yu   stablizeNameTable(NameTable, V);
633a0c0857eSWei Mi 
634a0c0857eSWei Mi   // Write out the name table.
635a0c0857eSWei Mi   encodeULEB128(NameTable.size(), OS);
636a0c0857eSWei Mi   for (auto N : V) {
637a0c0857eSWei Mi     encodeULEB128(MD5Hash(N), OS);
638a0c0857eSWei Mi   }
639a0c0857eSWei Mi   return sampleprof_error::success;
640a0c0857eSWei Mi }
641a0c0857eSWei Mi 
642be907324SWei Mi std::error_code
writeMagicIdent(SampleProfileFormat Format)643be907324SWei Mi SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) {
644a0c0857eSWei Mi   auto &OS = *OutputStream;
645760c5a8fSDiego Novillo   // Write file magic identifier.
646be907324SWei Mi   encodeULEB128(SPMagic(Format), OS);
647a0c0857eSWei Mi   encodeULEB128(SPVersion(), OS);
648a0c0857eSWei Mi   return sampleprof_error::success;
649a0c0857eSWei Mi }
650a0c0857eSWei Mi 
651b9db7036SHongtao Yu std::error_code
writeHeader(const SampleProfileMap & ProfileMap)652b9db7036SHongtao Yu SampleProfileWriterBinary::writeHeader(const SampleProfileMap &ProfileMap) {
653be907324SWei Mi   writeMagicIdent(Format);
654760c5a8fSDiego Novillo 
65540ee23dbSEaswaran Raman   computeSummary(ProfileMap);
65640ee23dbSEaswaran Raman   if (auto EC = writeSummary())
65740ee23dbSEaswaran Raman     return EC;
65840ee23dbSEaswaran Raman 
659760c5a8fSDiego Novillo   // Generate the name table for all the functions referenced in the profile.
660760c5a8fSDiego Novillo   for (const auto &I : ProfileMap) {
661b9db7036SHongtao Yu     assert(I.first == I.second.getContext() && "Inconsistent profile map");
662b9db7036SHongtao Yu     addContext(I.first);
663760c5a8fSDiego Novillo     addNames(I.second);
664760c5a8fSDiego Novillo   }
665760c5a8fSDiego Novillo 
666a0c0857eSWei Mi   writeNameTable();
667760c5a8fSDiego Novillo   return sampleprof_error::success;
668c572e92cSDiego Novillo }
669c572e92cSDiego Novillo 
setToCompressAllSections()670b523790aSWei Mi void SampleProfileWriterExtBinaryBase::setToCompressAllSections() {
67109dcfe68SWei Mi   for (auto &Entry : SectionHdrLayout)
672ebad6788SWei Mi     addSecFlag(Entry, SecCommonFlags::SecFlagCompress);
673b523790aSWei Mi }
674b523790aSWei Mi 
setToCompressSection(SecType Type)675b523790aSWei Mi void SampleProfileWriterExtBinaryBase::setToCompressSection(SecType Type) {
676ebad6788SWei Mi   addSectionFlag(Type, SecCommonFlags::SecFlagCompress);
677b523790aSWei Mi }
678b523790aSWei Mi 
allocSecHdrTable()679be907324SWei Mi void SampleProfileWriterExtBinaryBase::allocSecHdrTable() {
680be907324SWei Mi   support::endian::Writer Writer(*OutputStream, support::little);
681be907324SWei Mi 
68209dcfe68SWei Mi   Writer.write(static_cast<uint64_t>(SectionHdrLayout.size()));
683be907324SWei Mi   SecHdrTableOffset = OutputStream->tell();
68409dcfe68SWei Mi   for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) {
685be907324SWei Mi     Writer.write(static_cast<uint64_t>(-1));
686be907324SWei Mi     Writer.write(static_cast<uint64_t>(-1));
687be907324SWei Mi     Writer.write(static_cast<uint64_t>(-1));
688be907324SWei Mi     Writer.write(static_cast<uint64_t>(-1));
689be907324SWei Mi   }
690be907324SWei Mi }
691be907324SWei Mi 
writeSecHdrTable()692be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() {
693be907324SWei Mi   auto &OFS = static_cast<raw_fd_ostream &>(*OutputStream);
694be907324SWei Mi   uint64_t Saved = OutputStream->tell();
695be907324SWei Mi 
696be907324SWei Mi   // Set OutputStream to the location saved in SecHdrTableOffset.
697be907324SWei Mi   if (OFS.seek(SecHdrTableOffset) == (uint64_t)-1)
698be907324SWei Mi     return sampleprof_error::ostream_seek_unsupported;
699be907324SWei Mi   support::endian::Writer Writer(*OutputStream, support::little);
700be907324SWei Mi 
701a906e3ecSWei Mi   assert(SecHdrTable.size() == SectionHdrLayout.size() &&
702a906e3ecSWei Mi          "SecHdrTable entries doesn't match SectionHdrLayout");
703a906e3ecSWei Mi   SmallVector<uint32_t, 16> IndexMap(SecHdrTable.size(), -1);
704a906e3ecSWei Mi   for (uint32_t TableIdx = 0; TableIdx < SecHdrTable.size(); TableIdx++) {
705a906e3ecSWei Mi     IndexMap[SecHdrTable[TableIdx].LayoutIndex] = TableIdx;
706be907324SWei Mi   }
707be907324SWei Mi 
70809dcfe68SWei Mi   // Write the section header table in the order specified in
709a906e3ecSWei Mi   // SectionHdrLayout. SectionHdrLayout specifies the sections
710a906e3ecSWei Mi   // order in which profile reader expect to read, so the section
711a906e3ecSWei Mi   // header table should be written in the order in SectionHdrLayout.
712a906e3ecSWei Mi   // Note that the section order in SecHdrTable may be different
713a906e3ecSWei Mi   // from the order in SectionHdrLayout, for example, SecFuncOffsetTable
714a906e3ecSWei Mi   // needs to be computed after SecLBRProfile (the order in SecHdrTable),
715a906e3ecSWei Mi   // but it needs to be read before SecLBRProfile (the order in
716a906e3ecSWei Mi   // SectionHdrLayout). So we use IndexMap above to switch the order.
717a906e3ecSWei Mi   for (uint32_t LayoutIdx = 0; LayoutIdx < SectionHdrLayout.size();
718a906e3ecSWei Mi        LayoutIdx++) {
719a906e3ecSWei Mi     assert(IndexMap[LayoutIdx] < SecHdrTable.size() &&
720a906e3ecSWei Mi            "Incorrect LayoutIdx in SecHdrTable");
721a906e3ecSWei Mi     auto Entry = SecHdrTable[IndexMap[LayoutIdx]];
722a906e3ecSWei Mi     Writer.write(static_cast<uint64_t>(Entry.Type));
723a906e3ecSWei Mi     Writer.write(static_cast<uint64_t>(Entry.Flags));
724a906e3ecSWei Mi     Writer.write(static_cast<uint64_t>(Entry.Offset));
725a906e3ecSWei Mi     Writer.write(static_cast<uint64_t>(Entry.Size));
726be907324SWei Mi   }
727be907324SWei Mi 
728be907324SWei Mi   // Reset OutputStream.
729be907324SWei Mi   if (OFS.seek(Saved) == (uint64_t)-1)
730be907324SWei Mi     return sampleprof_error::ostream_seek_unsupported;
731be907324SWei Mi 
732be907324SWei Mi   return sampleprof_error::success;
733be907324SWei Mi }
734be907324SWei Mi 
writeHeader(const SampleProfileMap & ProfileMap)735be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeHeader(
736b9db7036SHongtao Yu     const SampleProfileMap &ProfileMap) {
737be907324SWei Mi   auto &OS = *OutputStream;
738be907324SWei Mi   FileStart = OS.tell();
739be907324SWei Mi   writeMagicIdent(Format);
740be907324SWei Mi 
741be907324SWei Mi   allocSecHdrTable();
742be907324SWei Mi   return sampleprof_error::success;
743be907324SWei Mi }
744be907324SWei Mi 
writeHeader(const SampleProfileMap & ProfileMap)7456a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::writeHeader(
746b9db7036SHongtao Yu     const SampleProfileMap &ProfileMap) {
7476a14325dSWei Mi   support::endian::Writer Writer(*OutputStream, support::little);
7486a14325dSWei Mi   if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap))
7496a14325dSWei Mi     return EC;
7506a14325dSWei Mi 
7516a14325dSWei Mi   // Reserve a slot for the offset of function offset table. The slot will
7526a14325dSWei Mi   // be populated with the offset of FuncOffsetTable later.
7536a14325dSWei Mi   TableOffset = OutputStream->tell();
7546a14325dSWei Mi   Writer.write(static_cast<uint64_t>(-2));
7556a14325dSWei Mi   return sampleprof_error::success;
7566a14325dSWei Mi }
7576a14325dSWei Mi 
writeSummary()75840ee23dbSEaswaran Raman std::error_code SampleProfileWriterBinary::writeSummary() {
75940ee23dbSEaswaran Raman   auto &OS = *OutputStream;
7607cefdb81SEaswaran Raman   encodeULEB128(Summary->getTotalCount(), OS);
7617cefdb81SEaswaran Raman   encodeULEB128(Summary->getMaxCount(), OS);
7626f4903d9SEaswaran Raman   encodeULEB128(Summary->getMaxFunctionCount(), OS);
7637cefdb81SEaswaran Raman   encodeULEB128(Summary->getNumCounts(), OS);
76440ee23dbSEaswaran Raman   encodeULEB128(Summary->getNumFunctions(), OS);
765d6790a0aSMircea Trofin   const std::vector<ProfileSummaryEntry> &Entries =
766d6790a0aSMircea Trofin       Summary->getDetailedSummary();
76740ee23dbSEaswaran Raman   encodeULEB128(Entries.size(), OS);
76840ee23dbSEaswaran Raman   for (auto Entry : Entries) {
76940ee23dbSEaswaran Raman     encodeULEB128(Entry.Cutoff, OS);
77040ee23dbSEaswaran Raman     encodeULEB128(Entry.MinCount, OS);
77140ee23dbSEaswaran Raman     encodeULEB128(Entry.NumCounts, OS);
77240ee23dbSEaswaran Raman   }
77340ee23dbSEaswaran Raman   return sampleprof_error::success;
77440ee23dbSEaswaran Raman }
writeBody(const FunctionSamples & S)77557d1dda5SDehao Chen std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
77651abea74SNathan Slingerland   auto &OS = *OutputStream;
777b9db7036SHongtao Yu   if (std::error_code EC = writeContextIdx(S.getContext()))
778760c5a8fSDiego Novillo     return EC;
779760c5a8fSDiego Novillo 
780c572e92cSDiego Novillo   encodeULEB128(S.getTotalSamples(), OS);
781a7f1e8efSDiego Novillo 
782a7f1e8efSDiego Novillo   // Emit all the body samples.
783b93483dbSDiego Novillo   encodeULEB128(S.getBodySamples().size(), OS);
784d5336ae2SDiego Novillo   for (const auto &I : S.getBodySamples()) {
785d5336ae2SDiego Novillo     LineLocation Loc = I.first;
786d5336ae2SDiego Novillo     const SampleRecord &Sample = I.second;
787c572e92cSDiego Novillo     encodeULEB128(Loc.LineOffset, OS);
788c572e92cSDiego Novillo     encodeULEB128(Loc.Discriminator, OS);
789c572e92cSDiego Novillo     encodeULEB128(Sample.getSamples(), OS);
790c572e92cSDiego Novillo     encodeULEB128(Sample.getCallTargets().size(), OS);
7915adace35SWenlei He     for (const auto &J : Sample.getSortedCallTargets()) {
7925adace35SWenlei He       StringRef Callee = J.first;
79338be3330SDiego Novillo       uint64_t CalleeSamples = J.second;
794760c5a8fSDiego Novillo       if (std::error_code EC = writeNameIdx(Callee))
795760c5a8fSDiego Novillo         return EC;
796c572e92cSDiego Novillo       encodeULEB128(CalleeSamples, OS);
797c572e92cSDiego Novillo     }
798c572e92cSDiego Novillo   }
799c572e92cSDiego Novillo 
800a7f1e8efSDiego Novillo   // Recursively emit all the callsite samples.
8012c27daf7SDehao Chen   uint64_t NumCallsites = 0;
8022c27daf7SDehao Chen   for (const auto &J : S.getCallsiteSamples())
8032c27daf7SDehao Chen     NumCallsites += J.second.size();
8042c27daf7SDehao Chen   encodeULEB128(NumCallsites, OS);
8052c7ca9b5SDehao Chen   for (const auto &J : S.getCallsiteSamples())
8062c7ca9b5SDehao Chen     for (const auto &FS : J.second) {
80757d1dda5SDehao Chen       LineLocation Loc = J.first;
8082c7ca9b5SDehao Chen       const FunctionSamples &CalleeSamples = FS.second;
809a7f1e8efSDiego Novillo       encodeULEB128(Loc.LineOffset, OS);
810a7f1e8efSDiego Novillo       encodeULEB128(Loc.Discriminator, OS);
81157d1dda5SDehao Chen       if (std::error_code EC = writeBody(CalleeSamples))
812760c5a8fSDiego Novillo         return EC;
813a7f1e8efSDiego Novillo     }
814a7f1e8efSDiego Novillo 
815760c5a8fSDiego Novillo   return sampleprof_error::success;
816c572e92cSDiego Novillo }
817d5336ae2SDiego Novillo 
8185f8f34e4SAdrian Prantl /// Write samples of a top-level function to a binary file.
819b93483dbSDiego Novillo ///
820b93483dbSDiego Novillo /// \returns true if the samples were written successfully, false otherwise.
821be907324SWei Mi std::error_code
writeSample(const FunctionSamples & S)822be907324SWei Mi SampleProfileWriterBinary::writeSample(const FunctionSamples &S) {
82351abea74SNathan Slingerland   encodeULEB128(S.getHeadSamples(), *OutputStream);
82457d1dda5SDehao Chen   return writeBody(S);
825b93483dbSDiego Novillo }
826b93483dbSDiego Novillo 
8276a14325dSWei Mi std::error_code
writeSample(const FunctionSamples & S)828be907324SWei Mi SampleProfileWriterCompactBinary::writeSample(const FunctionSamples &S) {
8296a14325dSWei Mi   uint64_t Offset = OutputStream->tell();
8306a14325dSWei Mi   StringRef Name = S.getName();
8316a14325dSWei Mi   FuncOffsetTable[Name] = Offset;
8326a14325dSWei Mi   encodeULEB128(S.getHeadSamples(), *OutputStream);
8336a14325dSWei Mi   return writeBody(S);
8346a14325dSWei Mi }
8356a14325dSWei Mi 
8365f8f34e4SAdrian Prantl /// Create a sample profile file writer based on the specified format.
837d5336ae2SDiego Novillo ///
838d5336ae2SDiego Novillo /// \param Filename The file to create.
839d5336ae2SDiego Novillo ///
840d5336ae2SDiego Novillo /// \param Format Encoding format for the profile file.
841d5336ae2SDiego Novillo ///
842d5336ae2SDiego Novillo /// \returns an error code indicating the status of the created writer.
843fcd55607SDiego Novillo ErrorOr<std::unique_ptr<SampleProfileWriter>>
create(StringRef Filename,SampleProfileFormat Format)844fcd55607SDiego Novillo SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
845d5336ae2SDiego Novillo   std::error_code EC;
84651abea74SNathan Slingerland   std::unique_ptr<raw_ostream> OS;
847be907324SWei Mi   if (Format == SPF_Binary || Format == SPF_Ext_Binary ||
848be907324SWei Mi       Format == SPF_Compact_Binary)
849d9b948b6SFangrui Song     OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None));
85051abea74SNathan Slingerland   else
85182b3e28eSAbhina Sreeskantharajan     OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_TextWithCRLF));
85251abea74SNathan Slingerland   if (EC)
85351abea74SNathan Slingerland     return EC;
85451abea74SNathan Slingerland 
85551abea74SNathan Slingerland   return create(OS, Format);
85651abea74SNathan Slingerland }
85751abea74SNathan Slingerland 
8585f8f34e4SAdrian Prantl /// Create a sample profile stream writer based on the specified format.
85951abea74SNathan Slingerland ///
86051abea74SNathan Slingerland /// \param OS The output stream to store the profile data to.
86151abea74SNathan Slingerland ///
86251abea74SNathan Slingerland /// \param Format Encoding format for the profile file.
86351abea74SNathan Slingerland ///
86451abea74SNathan Slingerland /// \returns an error code indicating the status of the created writer.
86551abea74SNathan Slingerland ErrorOr<std::unique_ptr<SampleProfileWriter>>
create(std::unique_ptr<raw_ostream> & OS,SampleProfileFormat Format)86651abea74SNathan Slingerland SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
86751abea74SNathan Slingerland                             SampleProfileFormat Format) {
86851abea74SNathan Slingerland   std::error_code EC;
869fcd55607SDiego Novillo   std::unique_ptr<SampleProfileWriter> Writer;
870d5336ae2SDiego Novillo 
871b2d07937SWenlei He   // Currently only Text and Extended Binary format are supported for CSSPGO.
872e36786d1SHongtao Yu   if ((FunctionSamples::ProfileIsCS || FunctionSamples::ProfileIsProbeBased) &&
873b2d07937SWenlei He       (Format == SPF_Binary || Format == SPF_Compact_Binary))
874b2d07937SWenlei He     return sampleprof_error::unsupported_writing_format;
875b2d07937SWenlei He 
876d9be2c7eSWei Mi   if (Format == SPF_Binary)
877a0c0857eSWei Mi     Writer.reset(new SampleProfileWriterRawBinary(OS));
878be907324SWei Mi   else if (Format == SPF_Ext_Binary)
879be907324SWei Mi     Writer.reset(new SampleProfileWriterExtBinary(OS));
880a0c0857eSWei Mi   else if (Format == SPF_Compact_Binary)
881a0c0857eSWei Mi     Writer.reset(new SampleProfileWriterCompactBinary(OS));
882d5336ae2SDiego Novillo   else if (Format == SPF_Text)
88351abea74SNathan Slingerland     Writer.reset(new SampleProfileWriterText(OS));
884760c5a8fSDiego Novillo   else if (Format == SPF_GCC)
885760c5a8fSDiego Novillo     EC = sampleprof_error::unsupported_writing_format;
886d5336ae2SDiego Novillo   else
887d5336ae2SDiego Novillo     EC = sampleprof_error::unrecognized_format;
888d5336ae2SDiego Novillo 
889fcd55607SDiego Novillo   if (EC)
890d5336ae2SDiego Novillo     return EC;
891fcd55607SDiego Novillo 
892be907324SWei Mi   Writer->Format = Format;
893c55cf4afSBill Wendling   return std::move(Writer);
894d5336ae2SDiego Novillo }
89540ee23dbSEaswaran Raman 
computeSummary(const SampleProfileMap & ProfileMap)896b9db7036SHongtao Yu void SampleProfileWriter::computeSummary(const SampleProfileMap &ProfileMap) {
897e5a17e3fSEaswaran Raman   SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
898801d9cc7SWenlei He   Summary = Builder.computeSummaryForProfiles(ProfileMap);
89940ee23dbSEaswaran Raman }
900