10b57cec5SDimitry Andric //===- SampleProfWriter.cpp - Write LLVM sample profile data --------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements the class that writes LLVM sample profiles. It
100b57cec5SDimitry Andric // supports two file formats: text and binary. The textual representation
110b57cec5SDimitry Andric // is useful for debugging and testing purposes. The binary representation
120b57cec5SDimitry Andric // is more compact, resulting in smaller file sizes. However, they can
130b57cec5SDimitry Andric // both be used interchangeably.
140b57cec5SDimitry Andric //
150b57cec5SDimitry Andric // See lib/ProfileData/SampleProfReader.cpp for documentation on each of the
160b57cec5SDimitry Andric // supported formats.
170b57cec5SDimitry Andric //
180b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric #include "llvm/ProfileData/SampleProfWriter.h"
210b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
22af732203SDimitry Andric #include "llvm/ADT/StringSet.h"
230b57cec5SDimitry Andric #include "llvm/ProfileData/ProfileCommon.h"
240b57cec5SDimitry Andric #include "llvm/ProfileData/SampleProf.h"
258bcb0991SDimitry Andric #include "llvm/Support/Compression.h"
260b57cec5SDimitry Andric #include "llvm/Support/Endian.h"
270b57cec5SDimitry Andric #include "llvm/Support/EndianStream.h"
280b57cec5SDimitry Andric #include "llvm/Support/ErrorOr.h"
290b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
300b57cec5SDimitry Andric #include "llvm/Support/LEB128.h"
310b57cec5SDimitry Andric #include "llvm/Support/MD5.h"
320b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
330b57cec5SDimitry Andric #include <algorithm>
340b57cec5SDimitry Andric #include <cstdint>
350b57cec5SDimitry Andric #include <memory>
360b57cec5SDimitry Andric #include <set>
370b57cec5SDimitry Andric #include <system_error>
380b57cec5SDimitry Andric #include <utility>
390b57cec5SDimitry Andric #include <vector>
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric using namespace llvm;
420b57cec5SDimitry Andric using namespace sampleprof;
430b57cec5SDimitry Andric 
writeFuncProfiles(const StringMap<FunctionSamples> & ProfileMap)448bcb0991SDimitry Andric std::error_code SampleProfileWriter::writeFuncProfiles(
458bcb0991SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
460b57cec5SDimitry Andric   // Sort the ProfileMap by total samples.
470b57cec5SDimitry Andric   typedef std::pair<StringRef, const FunctionSamples *> NameFunctionSamples;
480b57cec5SDimitry Andric   std::vector<NameFunctionSamples> V;
49*5f7ddb14SDimitry Andric   for (const auto &I : ProfileMap) {
50*5f7ddb14SDimitry Andric     assert(I.getKey() == I.second.getNameWithContext() &&
51*5f7ddb14SDimitry Andric            "Inconsistent profile map");
52*5f7ddb14SDimitry Andric     V.push_back(std::make_pair(I.second.getNameWithContext(), &I.second));
53*5f7ddb14SDimitry Andric   }
540b57cec5SDimitry Andric   llvm::stable_sort(
550b57cec5SDimitry Andric       V, [](const NameFunctionSamples &A, const NameFunctionSamples &B) {
560b57cec5SDimitry Andric         if (A.second->getTotalSamples() == B.second->getTotalSamples())
570b57cec5SDimitry Andric           return A.first > B.first;
580b57cec5SDimitry Andric         return A.second->getTotalSamples() > B.second->getTotalSamples();
590b57cec5SDimitry Andric       });
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   for (const auto &I : V) {
628bcb0991SDimitry Andric     if (std::error_code EC = writeSample(*I.second))
630b57cec5SDimitry Andric       return EC;
640b57cec5SDimitry Andric   }
650b57cec5SDimitry Andric   return sampleprof_error::success;
660b57cec5SDimitry Andric }
670b57cec5SDimitry Andric 
688bcb0991SDimitry Andric std::error_code
write(const StringMap<FunctionSamples> & ProfileMap)698bcb0991SDimitry Andric SampleProfileWriter::write(const StringMap<FunctionSamples> &ProfileMap) {
708bcb0991SDimitry Andric   if (std::error_code EC = writeHeader(ProfileMap))
718bcb0991SDimitry Andric     return EC;
728bcb0991SDimitry Andric 
738bcb0991SDimitry Andric   if (std::error_code EC = writeFuncProfiles(ProfileMap))
748bcb0991SDimitry Andric     return EC;
758bcb0991SDimitry Andric 
768bcb0991SDimitry Andric   return sampleprof_error::success;
778bcb0991SDimitry Andric }
788bcb0991SDimitry Andric 
798bcb0991SDimitry Andric /// Return the current position and prepare to use it as the start
80af732203SDimitry Andric /// position of a section given the section type \p Type and its position
81af732203SDimitry Andric /// \p LayoutIdx in SectionHdrLayout.
82af732203SDimitry Andric uint64_t
markSectionStart(SecType Type,uint32_t LayoutIdx)83af732203SDimitry Andric SampleProfileWriterExtBinaryBase::markSectionStart(SecType Type,
84af732203SDimitry Andric                                                    uint32_t LayoutIdx) {
858bcb0991SDimitry Andric   uint64_t SectionStart = OutputStream->tell();
86af732203SDimitry Andric   assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range");
87af732203SDimitry Andric   const auto &Entry = SectionHdrLayout[LayoutIdx];
88af732203SDimitry Andric   assert(Entry.Type == Type && "Unexpected section type");
898bcb0991SDimitry Andric   // Use LocalBuf as a temporary output for writting data.
905ffd83dbSDimitry Andric   if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress))
918bcb0991SDimitry Andric     LocalBufStream.swap(OutputStream);
928bcb0991SDimitry Andric   return SectionStart;
938bcb0991SDimitry Andric }
948bcb0991SDimitry Andric 
compressAndOutput()958bcb0991SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::compressAndOutput() {
968bcb0991SDimitry Andric   if (!llvm::zlib::isAvailable())
978bcb0991SDimitry Andric     return sampleprof_error::zlib_unavailable;
988bcb0991SDimitry Andric   std::string &UncompressedStrings =
998bcb0991SDimitry Andric       static_cast<raw_string_ostream *>(LocalBufStream.get())->str();
1008bcb0991SDimitry Andric   if (UncompressedStrings.size() == 0)
1018bcb0991SDimitry Andric     return sampleprof_error::success;
1028bcb0991SDimitry Andric   auto &OS = *OutputStream;
1038bcb0991SDimitry Andric   SmallString<128> CompressedStrings;
1048bcb0991SDimitry Andric   llvm::Error E = zlib::compress(UncompressedStrings, CompressedStrings,
1058bcb0991SDimitry Andric                                  zlib::BestSizeCompression);
1068bcb0991SDimitry Andric   if (E)
1078bcb0991SDimitry Andric     return sampleprof_error::compress_failed;
1088bcb0991SDimitry Andric   encodeULEB128(UncompressedStrings.size(), OS);
1098bcb0991SDimitry Andric   encodeULEB128(CompressedStrings.size(), OS);
1108bcb0991SDimitry Andric   OS << CompressedStrings.str();
1118bcb0991SDimitry Andric   UncompressedStrings.clear();
1128bcb0991SDimitry Andric   return sampleprof_error::success;
1138bcb0991SDimitry Andric }
1148bcb0991SDimitry Andric 
115af732203SDimitry Andric /// Add a new section into section header table given the section type
116af732203SDimitry Andric /// \p Type, its position \p LayoutIdx in SectionHdrLayout and the
117af732203SDimitry Andric /// location \p SectionStart where the section should be written to.
addNewSection(SecType Type,uint32_t LayoutIdx,uint64_t SectionStart)118af732203SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::addNewSection(
119af732203SDimitry Andric     SecType Type, uint32_t LayoutIdx, uint64_t SectionStart) {
120af732203SDimitry Andric   assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range");
121af732203SDimitry Andric   const auto &Entry = SectionHdrLayout[LayoutIdx];
122af732203SDimitry Andric   assert(Entry.Type == Type && "Unexpected section type");
1235ffd83dbSDimitry Andric   if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress)) {
1248bcb0991SDimitry Andric     LocalBufStream.swap(OutputStream);
1258bcb0991SDimitry Andric     if (std::error_code EC = compressAndOutput())
1268bcb0991SDimitry Andric       return EC;
1278bcb0991SDimitry Andric   }
1288bcb0991SDimitry Andric   SecHdrTable.push_back({Type, Entry.Flags, SectionStart - FileStart,
129af732203SDimitry Andric                          OutputStream->tell() - SectionStart, LayoutIdx});
1308bcb0991SDimitry Andric   return sampleprof_error::success;
1318bcb0991SDimitry Andric }
1328bcb0991SDimitry Andric 
write(const StringMap<FunctionSamples> & ProfileMap)1338bcb0991SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::write(
1348bcb0991SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
1358bcb0991SDimitry Andric   if (std::error_code EC = writeHeader(ProfileMap))
1368bcb0991SDimitry Andric     return EC;
1378bcb0991SDimitry Andric 
1388bcb0991SDimitry Andric   std::string LocalBuf;
1398bcb0991SDimitry Andric   LocalBufStream = std::make_unique<raw_string_ostream>(LocalBuf);
1408bcb0991SDimitry Andric   if (std::error_code EC = writeSections(ProfileMap))
1418bcb0991SDimitry Andric     return EC;
1428bcb0991SDimitry Andric 
1438bcb0991SDimitry Andric   if (std::error_code EC = writeSecHdrTable())
1448bcb0991SDimitry Andric     return EC;
1458bcb0991SDimitry Andric 
1468bcb0991SDimitry Andric   return sampleprof_error::success;
1478bcb0991SDimitry Andric }
1488bcb0991SDimitry Andric 
1498bcb0991SDimitry Andric std::error_code
writeSample(const FunctionSamples & S)150af732203SDimitry Andric SampleProfileWriterExtBinaryBase::writeSample(const FunctionSamples &S) {
1518bcb0991SDimitry Andric   uint64_t Offset = OutputStream->tell();
152*5f7ddb14SDimitry Andric   StringRef Name = S.getNameWithContext();
1538bcb0991SDimitry Andric   FuncOffsetTable[Name] = Offset - SecLBRProfileStart;
1548bcb0991SDimitry Andric   encodeULEB128(S.getHeadSamples(), *OutputStream);
1558bcb0991SDimitry Andric   return writeBody(S);
1568bcb0991SDimitry Andric }
1578bcb0991SDimitry Andric 
writeFuncOffsetTable()158af732203SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeFuncOffsetTable() {
1598bcb0991SDimitry Andric   auto &OS = *OutputStream;
1608bcb0991SDimitry Andric 
1618bcb0991SDimitry Andric   // Write out the table size.
1628bcb0991SDimitry Andric   encodeULEB128(FuncOffsetTable.size(), OS);
1638bcb0991SDimitry Andric 
1648bcb0991SDimitry Andric   // Write out FuncOffsetTable.
165*5f7ddb14SDimitry Andric   for (auto Entry : FuncOffsetTable) {
166*5f7ddb14SDimitry Andric     if (std::error_code EC =
167*5f7ddb14SDimitry Andric             writeNameIdx(Entry.first, FunctionSamples::ProfileIsCS))
168*5f7ddb14SDimitry Andric       return EC;
169*5f7ddb14SDimitry Andric     encodeULEB128(Entry.second, OS);
1708bcb0991SDimitry Andric   }
171af732203SDimitry Andric   FuncOffsetTable.clear();
1728bcb0991SDimitry Andric   return sampleprof_error::success;
1738bcb0991SDimitry Andric }
1748bcb0991SDimitry Andric 
writeFuncMetadata(const StringMap<FunctionSamples> & Profiles)175af732203SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeFuncMetadata(
176af732203SDimitry Andric     const StringMap<FunctionSamples> &Profiles) {
177*5f7ddb14SDimitry Andric   if (!FunctionSamples::ProfileIsProbeBased && !FunctionSamples::ProfileIsCS)
178af732203SDimitry Andric     return sampleprof_error::success;
179af732203SDimitry Andric   auto &OS = *OutputStream;
180af732203SDimitry Andric   for (const auto &Entry : Profiles) {
181*5f7ddb14SDimitry Andric     if (std::error_code EC = writeNameIdx(Entry.second.getNameWithContext(),
182*5f7ddb14SDimitry Andric                                           FunctionSamples::ProfileIsCS))
183*5f7ddb14SDimitry Andric       return EC;
184*5f7ddb14SDimitry Andric     if (FunctionSamples::ProfileIsProbeBased)
185af732203SDimitry Andric       encodeULEB128(Entry.second.getFunctionHash(), OS);
186*5f7ddb14SDimitry Andric     if (FunctionSamples::ProfileIsCS)
187*5f7ddb14SDimitry Andric       encodeULEB128(Entry.second.getContext().getAllAttributes(), OS);
188af732203SDimitry Andric   }
189af732203SDimitry Andric   return sampleprof_error::success;
190af732203SDimitry Andric }
191af732203SDimitry Andric 
writeNameTable()192af732203SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeNameTable() {
1935ffd83dbSDimitry Andric   if (!UseMD5)
1945ffd83dbSDimitry Andric     return SampleProfileWriterBinary::writeNameTable();
1955ffd83dbSDimitry Andric 
1965ffd83dbSDimitry Andric   auto &OS = *OutputStream;
1975ffd83dbSDimitry Andric   std::set<StringRef> V;
1985ffd83dbSDimitry Andric   stablizeNameTable(V);
1995ffd83dbSDimitry Andric 
200af732203SDimitry Andric   // Write out the MD5 name table. We wrote unencoded MD5 so reader can
201af732203SDimitry Andric   // retrieve the name using the name index without having to read the
202af732203SDimitry Andric   // whole name table.
2035ffd83dbSDimitry Andric   encodeULEB128(NameTable.size(), OS);
204af732203SDimitry Andric   support::endian::Writer Writer(OS, support::little);
205af732203SDimitry Andric   for (auto N : V)
206af732203SDimitry Andric     Writer.write(MD5Hash(N));
207af732203SDimitry Andric   return sampleprof_error::success;
2085ffd83dbSDimitry Andric }
209af732203SDimitry Andric 
writeNameTableSection(const StringMap<FunctionSamples> & ProfileMap)210af732203SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeNameTableSection(
211af732203SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
212af732203SDimitry Andric   for (const auto &I : ProfileMap) {
213*5f7ddb14SDimitry Andric     assert(I.first() == I.second.getNameWithContext() &&
214*5f7ddb14SDimitry Andric            "Inconsistent profile map");
215*5f7ddb14SDimitry Andric     addName(I.second.getNameWithContext(), FunctionSamples::ProfileIsCS);
216af732203SDimitry Andric     addNames(I.second);
217af732203SDimitry Andric   }
218*5f7ddb14SDimitry Andric 
219*5f7ddb14SDimitry Andric   // If NameTable contains ".__uniq." suffix, set SecFlagUniqSuffix flag
220*5f7ddb14SDimitry Andric   // so compiler won't strip the suffix during profile matching after
221*5f7ddb14SDimitry Andric   // seeing the flag in the profile.
222*5f7ddb14SDimitry Andric   for (const auto &I : NameTable) {
223*5f7ddb14SDimitry Andric     if (I.first.find(FunctionSamples::UniqSuffix) != StringRef::npos) {
224*5f7ddb14SDimitry Andric       addSectionFlag(SecNameTable, SecNameTableFlags::SecFlagUniqSuffix);
225*5f7ddb14SDimitry Andric       break;
226*5f7ddb14SDimitry Andric     }
227*5f7ddb14SDimitry Andric   }
228*5f7ddb14SDimitry Andric 
229af732203SDimitry Andric   if (auto EC = writeNameTable())
230af732203SDimitry Andric     return EC;
231af732203SDimitry Andric   return sampleprof_error::success;
232af732203SDimitry Andric }
233af732203SDimitry Andric 
234af732203SDimitry Andric std::error_code
writeProfileSymbolListSection()235af732203SDimitry Andric SampleProfileWriterExtBinaryBase::writeProfileSymbolListSection() {
236af732203SDimitry Andric   if (ProfSymList && ProfSymList->size() > 0)
237af732203SDimitry Andric     if (std::error_code EC = ProfSymList->write(*OutputStream))
238af732203SDimitry Andric       return EC;
239af732203SDimitry Andric 
240af732203SDimitry Andric   return sampleprof_error::success;
241af732203SDimitry Andric }
242af732203SDimitry Andric 
writeOneSection(SecType Type,uint32_t LayoutIdx,const StringMap<FunctionSamples> & ProfileMap)243af732203SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeOneSection(
244af732203SDimitry Andric     SecType Type, uint32_t LayoutIdx,
245af732203SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
246af732203SDimitry Andric   // The setting of SecFlagCompress should happen before markSectionStart.
247af732203SDimitry Andric   if (Type == SecProfileSymbolList && ProfSymList && ProfSymList->toCompress())
248af732203SDimitry Andric     setToCompressSection(SecProfileSymbolList);
249af732203SDimitry Andric   if (Type == SecFuncMetadata && FunctionSamples::ProfileIsProbeBased)
250af732203SDimitry Andric     addSectionFlag(SecFuncMetadata, SecFuncMetadataFlags::SecFlagIsProbeBased);
251*5f7ddb14SDimitry Andric   if (Type == SecProfSummary && FunctionSamples::ProfileIsCS)
252*5f7ddb14SDimitry Andric     addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagFullContext);
253*5f7ddb14SDimitry Andric   if (Type == SecFuncMetadata && FunctionSamples::ProfileIsCS)
254*5f7ddb14SDimitry Andric     addSectionFlag(SecFuncMetadata, SecFuncMetadataFlags::SecFlagHasAttribute);
255*5f7ddb14SDimitry Andric   if (Type == SecProfSummary && FunctionSamples::ProfileIsFS)
256*5f7ddb14SDimitry Andric     addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagFSDiscriminator);
257af732203SDimitry Andric 
258af732203SDimitry Andric   uint64_t SectionStart = markSectionStart(Type, LayoutIdx);
259af732203SDimitry Andric   switch (Type) {
260af732203SDimitry Andric   case SecProfSummary:
261af732203SDimitry Andric     computeSummary(ProfileMap);
262af732203SDimitry Andric     if (auto EC = writeSummary())
263af732203SDimitry Andric       return EC;
264af732203SDimitry Andric     break;
265af732203SDimitry Andric   case SecNameTable:
266af732203SDimitry Andric     if (auto EC = writeNameTableSection(ProfileMap))
267af732203SDimitry Andric       return EC;
268af732203SDimitry Andric     break;
269af732203SDimitry Andric   case SecLBRProfile:
270af732203SDimitry Andric     SecLBRProfileStart = OutputStream->tell();
271af732203SDimitry Andric     if (std::error_code EC = writeFuncProfiles(ProfileMap))
272af732203SDimitry Andric       return EC;
273af732203SDimitry Andric     break;
274af732203SDimitry Andric   case SecFuncOffsetTable:
275af732203SDimitry Andric     if (auto EC = writeFuncOffsetTable())
276af732203SDimitry Andric       return EC;
277af732203SDimitry Andric     break;
278af732203SDimitry Andric   case SecFuncMetadata:
279af732203SDimitry Andric     if (std::error_code EC = writeFuncMetadata(ProfileMap))
280af732203SDimitry Andric       return EC;
281af732203SDimitry Andric     break;
282af732203SDimitry Andric   case SecProfileSymbolList:
283af732203SDimitry Andric     if (auto EC = writeProfileSymbolListSection())
284af732203SDimitry Andric       return EC;
285af732203SDimitry Andric     break;
286af732203SDimitry Andric   default:
287af732203SDimitry Andric     if (auto EC = writeCustomSection(Type))
288af732203SDimitry Andric       return EC;
289af732203SDimitry Andric     break;
290af732203SDimitry Andric   }
291af732203SDimitry Andric   if (std::error_code EC = addNewSection(Type, LayoutIdx, SectionStart))
292af732203SDimitry Andric     return EC;
293af732203SDimitry Andric   return sampleprof_error::success;
294af732203SDimitry Andric }
295af732203SDimitry Andric 
writeDefaultLayout(const StringMap<FunctionSamples> & ProfileMap)296af732203SDimitry Andric std::error_code SampleProfileWriterExtBinary::writeDefaultLayout(
297af732203SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
298af732203SDimitry Andric   // The const indices passed to writeOneSection below are specifying the
299af732203SDimitry Andric   // positions of the sections in SectionHdrLayout. Look at
300af732203SDimitry Andric   // initSectionHdrLayout to find out where each section is located in
301af732203SDimitry Andric   // SectionHdrLayout.
302af732203SDimitry Andric   if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap))
303af732203SDimitry Andric     return EC;
304af732203SDimitry Andric   if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap))
305af732203SDimitry Andric     return EC;
306af732203SDimitry Andric   if (auto EC = writeOneSection(SecLBRProfile, 3, ProfileMap))
307af732203SDimitry Andric     return EC;
308af732203SDimitry Andric   if (auto EC = writeOneSection(SecProfileSymbolList, 4, ProfileMap))
309af732203SDimitry Andric     return EC;
310af732203SDimitry Andric   if (auto EC = writeOneSection(SecFuncOffsetTable, 2, ProfileMap))
311af732203SDimitry Andric     return EC;
312af732203SDimitry Andric   if (auto EC = writeOneSection(SecFuncMetadata, 5, ProfileMap))
313af732203SDimitry Andric     return EC;
314af732203SDimitry Andric   return sampleprof_error::success;
315af732203SDimitry Andric }
316af732203SDimitry Andric 
317af732203SDimitry Andric static void
splitProfileMapToTwo(const StringMap<FunctionSamples> & ProfileMap,StringMap<FunctionSamples> & ContextProfileMap,StringMap<FunctionSamples> & NoContextProfileMap)318af732203SDimitry Andric splitProfileMapToTwo(const StringMap<FunctionSamples> &ProfileMap,
319af732203SDimitry Andric                      StringMap<FunctionSamples> &ContextProfileMap,
320af732203SDimitry Andric                      StringMap<FunctionSamples> &NoContextProfileMap) {
321af732203SDimitry Andric   for (const auto &I : ProfileMap) {
322af732203SDimitry Andric     if (I.second.getCallsiteSamples().size())
323af732203SDimitry Andric       ContextProfileMap.insert({I.first(), I.second});
324af732203SDimitry Andric     else
325af732203SDimitry Andric       NoContextProfileMap.insert({I.first(), I.second});
326af732203SDimitry Andric   }
327af732203SDimitry Andric }
328af732203SDimitry Andric 
writeCtxSplitLayout(const StringMap<FunctionSamples> & ProfileMap)329af732203SDimitry Andric std::error_code SampleProfileWriterExtBinary::writeCtxSplitLayout(
330af732203SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
331af732203SDimitry Andric   StringMap<FunctionSamples> ContextProfileMap, NoContextProfileMap;
332af732203SDimitry Andric   splitProfileMapToTwo(ProfileMap, ContextProfileMap, NoContextProfileMap);
333af732203SDimitry Andric 
334af732203SDimitry Andric   if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap))
335af732203SDimitry Andric     return EC;
336af732203SDimitry Andric   if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap))
337af732203SDimitry Andric     return EC;
338af732203SDimitry Andric   if (auto EC = writeOneSection(SecLBRProfile, 3, ContextProfileMap))
339af732203SDimitry Andric     return EC;
340af732203SDimitry Andric   if (auto EC = writeOneSection(SecFuncOffsetTable, 2, ContextProfileMap))
341af732203SDimitry Andric     return EC;
342af732203SDimitry Andric   // Mark the section to have no context. Note section flag needs to be set
343af732203SDimitry Andric   // before writing the section.
344af732203SDimitry Andric   addSectionFlag(5, SecCommonFlags::SecFlagFlat);
345af732203SDimitry Andric   if (auto EC = writeOneSection(SecLBRProfile, 5, NoContextProfileMap))
346af732203SDimitry Andric     return EC;
347af732203SDimitry Andric   // Mark the section to have no context. Note section flag needs to be set
348af732203SDimitry Andric   // before writing the section.
349af732203SDimitry Andric   addSectionFlag(4, SecCommonFlags::SecFlagFlat);
350af732203SDimitry Andric   if (auto EC = writeOneSection(SecFuncOffsetTable, 4, NoContextProfileMap))
351af732203SDimitry Andric     return EC;
352af732203SDimitry Andric   if (auto EC = writeOneSection(SecProfileSymbolList, 6, ProfileMap))
353af732203SDimitry Andric     return EC;
354af732203SDimitry Andric   if (auto EC = writeOneSection(SecFuncMetadata, 7, ProfileMap))
355af732203SDimitry Andric     return EC;
356af732203SDimitry Andric 
3575ffd83dbSDimitry Andric   return sampleprof_error::success;
3585ffd83dbSDimitry Andric }
3595ffd83dbSDimitry Andric 
writeSections(const StringMap<FunctionSamples> & ProfileMap)3608bcb0991SDimitry Andric std::error_code SampleProfileWriterExtBinary::writeSections(
3618bcb0991SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
362af732203SDimitry Andric   std::error_code EC;
363af732203SDimitry Andric   if (SecLayout == DefaultLayout)
364af732203SDimitry Andric     EC = writeDefaultLayout(ProfileMap);
365af732203SDimitry Andric   else if (SecLayout == CtxSplitLayout)
366af732203SDimitry Andric     EC = writeCtxSplitLayout(ProfileMap);
367af732203SDimitry Andric   else
368af732203SDimitry Andric     llvm_unreachable("Unsupported layout");
3698bcb0991SDimitry Andric   return EC;
3708bcb0991SDimitry Andric }
3718bcb0991SDimitry Andric 
write(const StringMap<FunctionSamples> & ProfileMap)3720b57cec5SDimitry Andric std::error_code SampleProfileWriterCompactBinary::write(
3730b57cec5SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
3740b57cec5SDimitry Andric   if (std::error_code EC = SampleProfileWriter::write(ProfileMap))
3750b57cec5SDimitry Andric     return EC;
3760b57cec5SDimitry Andric   if (std::error_code EC = writeFuncOffsetTable())
3770b57cec5SDimitry Andric     return EC;
3780b57cec5SDimitry Andric   return sampleprof_error::success;
3790b57cec5SDimitry Andric }
3800b57cec5SDimitry Andric 
3810b57cec5SDimitry Andric /// Write samples to a text file.
3820b57cec5SDimitry Andric ///
3830b57cec5SDimitry Andric /// Note: it may be tempting to implement this in terms of
3840b57cec5SDimitry Andric /// FunctionSamples::print().  Please don't.  The dump functionality is intended
3850b57cec5SDimitry Andric /// for debugging and has no specified form.
3860b57cec5SDimitry Andric ///
3870b57cec5SDimitry Andric /// The format used here is more structured and deliberate because
3880b57cec5SDimitry Andric /// it needs to be parsed by the SampleProfileReaderText class.
writeSample(const FunctionSamples & S)3898bcb0991SDimitry Andric std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) {
3900b57cec5SDimitry Andric   auto &OS = *OutputStream;
391*5f7ddb14SDimitry Andric   if (FunctionSamples::ProfileIsCS)
392*5f7ddb14SDimitry Andric     OS << "[" << S.getNameWithContext() << "]:" << S.getTotalSamples();
393*5f7ddb14SDimitry Andric   else
394*5f7ddb14SDimitry Andric     OS << S.getName() << ":" << S.getTotalSamples();
395*5f7ddb14SDimitry Andric 
3960b57cec5SDimitry Andric   if (Indent == 0)
3970b57cec5SDimitry Andric     OS << ":" << S.getHeadSamples();
3980b57cec5SDimitry Andric   OS << "\n";
3990b57cec5SDimitry Andric 
4000b57cec5SDimitry Andric   SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples());
4010b57cec5SDimitry Andric   for (const auto &I : SortedSamples.get()) {
4020b57cec5SDimitry Andric     LineLocation Loc = I->first;
4030b57cec5SDimitry Andric     const SampleRecord &Sample = I->second;
4040b57cec5SDimitry Andric     OS.indent(Indent + 1);
4050b57cec5SDimitry Andric     if (Loc.Discriminator == 0)
4060b57cec5SDimitry Andric       OS << Loc.LineOffset << ": ";
4070b57cec5SDimitry Andric     else
4080b57cec5SDimitry Andric       OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
4090b57cec5SDimitry Andric 
4100b57cec5SDimitry Andric     OS << Sample.getSamples();
4110b57cec5SDimitry Andric 
4128bcb0991SDimitry Andric     for (const auto &J : Sample.getSortedCallTargets())
4138bcb0991SDimitry Andric       OS << " " << J.first << ":" << J.second;
4140b57cec5SDimitry Andric     OS << "\n";
4150b57cec5SDimitry Andric   }
4160b57cec5SDimitry Andric 
4170b57cec5SDimitry Andric   SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples(
4180b57cec5SDimitry Andric       S.getCallsiteSamples());
4190b57cec5SDimitry Andric   Indent += 1;
4200b57cec5SDimitry Andric   for (const auto &I : SortedCallsiteSamples.get())
4210b57cec5SDimitry Andric     for (const auto &FS : I->second) {
4220b57cec5SDimitry Andric       LineLocation Loc = I->first;
4230b57cec5SDimitry Andric       const FunctionSamples &CalleeSamples = FS.second;
4240b57cec5SDimitry Andric       OS.indent(Indent);
4250b57cec5SDimitry Andric       if (Loc.Discriminator == 0)
4260b57cec5SDimitry Andric         OS << Loc.LineOffset << ": ";
4270b57cec5SDimitry Andric       else
4280b57cec5SDimitry Andric         OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
4298bcb0991SDimitry Andric       if (std::error_code EC = writeSample(CalleeSamples))
4300b57cec5SDimitry Andric         return EC;
4310b57cec5SDimitry Andric     }
4320b57cec5SDimitry Andric   Indent -= 1;
4330b57cec5SDimitry Andric 
434af732203SDimitry Andric   if (Indent == 0) {
435af732203SDimitry Andric     if (FunctionSamples::ProfileIsProbeBased) {
436af732203SDimitry Andric       OS.indent(Indent + 1);
437af732203SDimitry Andric       OS << "!CFGChecksum: " << S.getFunctionHash() << "\n";
438af732203SDimitry Andric     }
439*5f7ddb14SDimitry Andric     if (FunctionSamples::ProfileIsCS) {
440*5f7ddb14SDimitry Andric       OS.indent(Indent + 1);
441*5f7ddb14SDimitry Andric       OS << "!Attributes: " << S.getContext().getAllAttributes() << "\n";
442*5f7ddb14SDimitry Andric     }
443af732203SDimitry Andric   }
444af732203SDimitry Andric 
4450b57cec5SDimitry Andric   return sampleprof_error::success;
4460b57cec5SDimitry Andric }
4470b57cec5SDimitry Andric 
writeNameIdx(StringRef FName,bool IsContextName)448*5f7ddb14SDimitry Andric std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName,
449*5f7ddb14SDimitry Andric                                                         bool IsContextName) {
450*5f7ddb14SDimitry Andric   std::string BracketedName;
451*5f7ddb14SDimitry Andric   if (IsContextName) {
452*5f7ddb14SDimitry Andric     BracketedName = "[" + FName.str() + "]";
453*5f7ddb14SDimitry Andric     FName = StringRef(BracketedName);
454*5f7ddb14SDimitry Andric   }
455*5f7ddb14SDimitry Andric 
456*5f7ddb14SDimitry Andric   const auto &Ret = NameTable.find(FName);
457*5f7ddb14SDimitry Andric   if (Ret == NameTable.end())
4580b57cec5SDimitry Andric     return sampleprof_error::truncated_name_table;
459*5f7ddb14SDimitry Andric   encodeULEB128(Ret->second, *OutputStream);
4600b57cec5SDimitry Andric   return sampleprof_error::success;
4610b57cec5SDimitry Andric }
4620b57cec5SDimitry Andric 
addName(StringRef FName,bool IsContextName)463*5f7ddb14SDimitry Andric void SampleProfileWriterBinary::addName(StringRef FName, bool IsContextName) {
464*5f7ddb14SDimitry Andric   if (IsContextName) {
465*5f7ddb14SDimitry Andric     auto It = BracketedContextStr.insert("[" + FName.str() + "]");
466*5f7ddb14SDimitry Andric     FName = StringRef(*It.first);
467*5f7ddb14SDimitry Andric   }
4680b57cec5SDimitry Andric   NameTable.insert(std::make_pair(FName, 0));
4690b57cec5SDimitry Andric }
4700b57cec5SDimitry Andric 
addNames(const FunctionSamples & S)4710b57cec5SDimitry Andric void SampleProfileWriterBinary::addNames(const FunctionSamples &S) {
4720b57cec5SDimitry Andric   // Add all the names in indirect call targets.
4730b57cec5SDimitry Andric   for (const auto &I : S.getBodySamples()) {
4740b57cec5SDimitry Andric     const SampleRecord &Sample = I.second;
4750b57cec5SDimitry Andric     for (const auto &J : Sample.getCallTargets())
4760b57cec5SDimitry Andric       addName(J.first());
4770b57cec5SDimitry Andric   }
4780b57cec5SDimitry Andric 
4790b57cec5SDimitry Andric   // Recursively add all the names for inlined callsites.
4800b57cec5SDimitry Andric   for (const auto &J : S.getCallsiteSamples())
4810b57cec5SDimitry Andric     for (const auto &FS : J.second) {
4820b57cec5SDimitry Andric       const FunctionSamples &CalleeSamples = FS.second;
4830b57cec5SDimitry Andric       addName(CalleeSamples.getName());
4840b57cec5SDimitry Andric       addNames(CalleeSamples);
4850b57cec5SDimitry Andric     }
4860b57cec5SDimitry Andric }
4870b57cec5SDimitry Andric 
stablizeNameTable(std::set<StringRef> & V)4880b57cec5SDimitry Andric void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) {
4890b57cec5SDimitry Andric   // Sort the names to make NameTable deterministic.
4900b57cec5SDimitry Andric   for (const auto &I : NameTable)
4910b57cec5SDimitry Andric     V.insert(I.first);
4920b57cec5SDimitry Andric   int i = 0;
4930b57cec5SDimitry Andric   for (const StringRef &N : V)
4940b57cec5SDimitry Andric     NameTable[N] = i++;
4950b57cec5SDimitry Andric }
4960b57cec5SDimitry Andric 
writeNameTable()4978bcb0991SDimitry Andric std::error_code SampleProfileWriterBinary::writeNameTable() {
4980b57cec5SDimitry Andric   auto &OS = *OutputStream;
4990b57cec5SDimitry Andric   std::set<StringRef> V;
5000b57cec5SDimitry Andric   stablizeNameTable(V);
5010b57cec5SDimitry Andric 
5020b57cec5SDimitry Andric   // Write out the name table.
5030b57cec5SDimitry Andric   encodeULEB128(NameTable.size(), OS);
5040b57cec5SDimitry Andric   for (auto N : V) {
5050b57cec5SDimitry Andric     OS << N;
5060b57cec5SDimitry Andric     encodeULEB128(0, OS);
5070b57cec5SDimitry Andric   }
5080b57cec5SDimitry Andric   return sampleprof_error::success;
5090b57cec5SDimitry Andric }
5100b57cec5SDimitry Andric 
writeFuncOffsetTable()5110b57cec5SDimitry Andric std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() {
5120b57cec5SDimitry Andric   auto &OS = *OutputStream;
5130b57cec5SDimitry Andric 
5140b57cec5SDimitry Andric   // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable.
5150b57cec5SDimitry Andric   auto &OFS = static_cast<raw_fd_ostream &>(OS);
5160b57cec5SDimitry Andric   uint64_t FuncOffsetTableStart = OS.tell();
5170b57cec5SDimitry Andric   if (OFS.seek(TableOffset) == (uint64_t)-1)
5180b57cec5SDimitry Andric     return sampleprof_error::ostream_seek_unsupported;
5190b57cec5SDimitry Andric   support::endian::Writer Writer(*OutputStream, support::little);
5200b57cec5SDimitry Andric   Writer.write(FuncOffsetTableStart);
5210b57cec5SDimitry Andric   if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1)
5220b57cec5SDimitry Andric     return sampleprof_error::ostream_seek_unsupported;
5230b57cec5SDimitry Andric 
5240b57cec5SDimitry Andric   // Write out the table size.
5250b57cec5SDimitry Andric   encodeULEB128(FuncOffsetTable.size(), OS);
5260b57cec5SDimitry Andric 
5270b57cec5SDimitry Andric   // Write out FuncOffsetTable.
528*5f7ddb14SDimitry Andric   for (auto Entry : FuncOffsetTable) {
529*5f7ddb14SDimitry Andric     if (std::error_code EC =
530*5f7ddb14SDimitry Andric             writeNameIdx(Entry.first, FunctionSamples::ProfileIsCS))
531*5f7ddb14SDimitry Andric       return EC;
532*5f7ddb14SDimitry Andric     encodeULEB128(Entry.second, OS);
5330b57cec5SDimitry Andric   }
5340b57cec5SDimitry Andric   return sampleprof_error::success;
5350b57cec5SDimitry Andric }
5360b57cec5SDimitry Andric 
writeNameTable()5370b57cec5SDimitry Andric std::error_code SampleProfileWriterCompactBinary::writeNameTable() {
5380b57cec5SDimitry Andric   auto &OS = *OutputStream;
5390b57cec5SDimitry Andric   std::set<StringRef> V;
5400b57cec5SDimitry Andric   stablizeNameTable(V);
5410b57cec5SDimitry Andric 
5420b57cec5SDimitry Andric   // Write out the name table.
5430b57cec5SDimitry Andric   encodeULEB128(NameTable.size(), OS);
5440b57cec5SDimitry Andric   for (auto N : V) {
5450b57cec5SDimitry Andric     encodeULEB128(MD5Hash(N), OS);
5460b57cec5SDimitry Andric   }
5470b57cec5SDimitry Andric   return sampleprof_error::success;
5480b57cec5SDimitry Andric }
5490b57cec5SDimitry Andric 
5508bcb0991SDimitry Andric std::error_code
writeMagicIdent(SampleProfileFormat Format)5518bcb0991SDimitry Andric SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) {
5520b57cec5SDimitry Andric   auto &OS = *OutputStream;
5530b57cec5SDimitry Andric   // Write file magic identifier.
5548bcb0991SDimitry Andric   encodeULEB128(SPMagic(Format), OS);
5550b57cec5SDimitry Andric   encodeULEB128(SPVersion(), OS);
5560b57cec5SDimitry Andric   return sampleprof_error::success;
5570b57cec5SDimitry Andric }
5580b57cec5SDimitry Andric 
writeHeader(const StringMap<FunctionSamples> & ProfileMap)5590b57cec5SDimitry Andric std::error_code SampleProfileWriterBinary::writeHeader(
5600b57cec5SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
5618bcb0991SDimitry Andric   writeMagicIdent(Format);
5620b57cec5SDimitry Andric 
5630b57cec5SDimitry Andric   computeSummary(ProfileMap);
5640b57cec5SDimitry Andric   if (auto EC = writeSummary())
5650b57cec5SDimitry Andric     return EC;
5660b57cec5SDimitry Andric 
5670b57cec5SDimitry Andric   // Generate the name table for all the functions referenced in the profile.
5680b57cec5SDimitry Andric   for (const auto &I : ProfileMap) {
569*5f7ddb14SDimitry Andric     assert(I.first() == I.second.getNameWithContext() &&
570*5f7ddb14SDimitry Andric            "Inconsistent profile map");
571*5f7ddb14SDimitry Andric     addName(I.first(), FunctionSamples::ProfileIsCS);
5720b57cec5SDimitry Andric     addNames(I.second);
5730b57cec5SDimitry Andric   }
5740b57cec5SDimitry Andric 
5750b57cec5SDimitry Andric   writeNameTable();
5760b57cec5SDimitry Andric   return sampleprof_error::success;
5770b57cec5SDimitry Andric }
5780b57cec5SDimitry Andric 
setToCompressAllSections()5798bcb0991SDimitry Andric void SampleProfileWriterExtBinaryBase::setToCompressAllSections() {
5808bcb0991SDimitry Andric   for (auto &Entry : SectionHdrLayout)
5815ffd83dbSDimitry Andric     addSecFlag(Entry, SecCommonFlags::SecFlagCompress);
5828bcb0991SDimitry Andric }
5838bcb0991SDimitry Andric 
setToCompressSection(SecType Type)5848bcb0991SDimitry Andric void SampleProfileWriterExtBinaryBase::setToCompressSection(SecType Type) {
5855ffd83dbSDimitry Andric   addSectionFlag(Type, SecCommonFlags::SecFlagCompress);
5868bcb0991SDimitry Andric }
5878bcb0991SDimitry Andric 
allocSecHdrTable()5888bcb0991SDimitry Andric void SampleProfileWriterExtBinaryBase::allocSecHdrTable() {
5898bcb0991SDimitry Andric   support::endian::Writer Writer(*OutputStream, support::little);
5908bcb0991SDimitry Andric 
5918bcb0991SDimitry Andric   Writer.write(static_cast<uint64_t>(SectionHdrLayout.size()));
5928bcb0991SDimitry Andric   SecHdrTableOffset = OutputStream->tell();
5938bcb0991SDimitry Andric   for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) {
5948bcb0991SDimitry Andric     Writer.write(static_cast<uint64_t>(-1));
5958bcb0991SDimitry Andric     Writer.write(static_cast<uint64_t>(-1));
5968bcb0991SDimitry Andric     Writer.write(static_cast<uint64_t>(-1));
5978bcb0991SDimitry Andric     Writer.write(static_cast<uint64_t>(-1));
5988bcb0991SDimitry Andric   }
5998bcb0991SDimitry Andric }
6008bcb0991SDimitry Andric 
writeSecHdrTable()6018bcb0991SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() {
6028bcb0991SDimitry Andric   auto &OFS = static_cast<raw_fd_ostream &>(*OutputStream);
6038bcb0991SDimitry Andric   uint64_t Saved = OutputStream->tell();
6048bcb0991SDimitry Andric 
6058bcb0991SDimitry Andric   // Set OutputStream to the location saved in SecHdrTableOffset.
6068bcb0991SDimitry Andric   if (OFS.seek(SecHdrTableOffset) == (uint64_t)-1)
6078bcb0991SDimitry Andric     return sampleprof_error::ostream_seek_unsupported;
6088bcb0991SDimitry Andric   support::endian::Writer Writer(*OutputStream, support::little);
6098bcb0991SDimitry Andric 
610af732203SDimitry Andric   assert(SecHdrTable.size() == SectionHdrLayout.size() &&
611af732203SDimitry Andric          "SecHdrTable entries doesn't match SectionHdrLayout");
612af732203SDimitry Andric   SmallVector<uint32_t, 16> IndexMap(SecHdrTable.size(), -1);
613af732203SDimitry Andric   for (uint32_t TableIdx = 0; TableIdx < SecHdrTable.size(); TableIdx++) {
614af732203SDimitry Andric     IndexMap[SecHdrTable[TableIdx].LayoutIndex] = TableIdx;
6158bcb0991SDimitry Andric   }
6168bcb0991SDimitry Andric 
6178bcb0991SDimitry Andric   // Write the section header table in the order specified in
618af732203SDimitry Andric   // SectionHdrLayout. SectionHdrLayout specifies the sections
619af732203SDimitry Andric   // order in which profile reader expect to read, so the section
620af732203SDimitry Andric   // header table should be written in the order in SectionHdrLayout.
621af732203SDimitry Andric   // Note that the section order in SecHdrTable may be different
622af732203SDimitry Andric   // from the order in SectionHdrLayout, for example, SecFuncOffsetTable
623af732203SDimitry Andric   // needs to be computed after SecLBRProfile (the order in SecHdrTable),
624af732203SDimitry Andric   // but it needs to be read before SecLBRProfile (the order in
625af732203SDimitry Andric   // SectionHdrLayout). So we use IndexMap above to switch the order.
626af732203SDimitry Andric   for (uint32_t LayoutIdx = 0; LayoutIdx < SectionHdrLayout.size();
627af732203SDimitry Andric        LayoutIdx++) {
628af732203SDimitry Andric     assert(IndexMap[LayoutIdx] < SecHdrTable.size() &&
629af732203SDimitry Andric            "Incorrect LayoutIdx in SecHdrTable");
630af732203SDimitry Andric     auto Entry = SecHdrTable[IndexMap[LayoutIdx]];
631af732203SDimitry Andric     Writer.write(static_cast<uint64_t>(Entry.Type));
632af732203SDimitry Andric     Writer.write(static_cast<uint64_t>(Entry.Flags));
633af732203SDimitry Andric     Writer.write(static_cast<uint64_t>(Entry.Offset));
634af732203SDimitry Andric     Writer.write(static_cast<uint64_t>(Entry.Size));
6358bcb0991SDimitry Andric   }
6368bcb0991SDimitry Andric 
6378bcb0991SDimitry Andric   // Reset OutputStream.
6388bcb0991SDimitry Andric   if (OFS.seek(Saved) == (uint64_t)-1)
6398bcb0991SDimitry Andric     return sampleprof_error::ostream_seek_unsupported;
6408bcb0991SDimitry Andric 
6418bcb0991SDimitry Andric   return sampleprof_error::success;
6428bcb0991SDimitry Andric }
6438bcb0991SDimitry Andric 
writeHeader(const StringMap<FunctionSamples> & ProfileMap)6448bcb0991SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeHeader(
6458bcb0991SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
6468bcb0991SDimitry Andric   auto &OS = *OutputStream;
6478bcb0991SDimitry Andric   FileStart = OS.tell();
6488bcb0991SDimitry Andric   writeMagicIdent(Format);
6498bcb0991SDimitry Andric 
6508bcb0991SDimitry Andric   allocSecHdrTable();
6518bcb0991SDimitry Andric   return sampleprof_error::success;
6528bcb0991SDimitry Andric }
6538bcb0991SDimitry Andric 
writeHeader(const StringMap<FunctionSamples> & ProfileMap)6540b57cec5SDimitry Andric std::error_code SampleProfileWriterCompactBinary::writeHeader(
6550b57cec5SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
6560b57cec5SDimitry Andric   support::endian::Writer Writer(*OutputStream, support::little);
6570b57cec5SDimitry Andric   if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap))
6580b57cec5SDimitry Andric     return EC;
6590b57cec5SDimitry Andric 
6600b57cec5SDimitry Andric   // Reserve a slot for the offset of function offset table. The slot will
6610b57cec5SDimitry Andric   // be populated with the offset of FuncOffsetTable later.
6620b57cec5SDimitry Andric   TableOffset = OutputStream->tell();
6630b57cec5SDimitry Andric   Writer.write(static_cast<uint64_t>(-2));
6640b57cec5SDimitry Andric   return sampleprof_error::success;
6650b57cec5SDimitry Andric }
6660b57cec5SDimitry Andric 
writeSummary()6670b57cec5SDimitry Andric std::error_code SampleProfileWriterBinary::writeSummary() {
6680b57cec5SDimitry Andric   auto &OS = *OutputStream;
6690b57cec5SDimitry Andric   encodeULEB128(Summary->getTotalCount(), OS);
6700b57cec5SDimitry Andric   encodeULEB128(Summary->getMaxCount(), OS);
6710b57cec5SDimitry Andric   encodeULEB128(Summary->getMaxFunctionCount(), OS);
6720b57cec5SDimitry Andric   encodeULEB128(Summary->getNumCounts(), OS);
6730b57cec5SDimitry Andric   encodeULEB128(Summary->getNumFunctions(), OS);
6740b57cec5SDimitry Andric   std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary();
6750b57cec5SDimitry Andric   encodeULEB128(Entries.size(), OS);
6760b57cec5SDimitry Andric   for (auto Entry : Entries) {
6770b57cec5SDimitry Andric     encodeULEB128(Entry.Cutoff, OS);
6780b57cec5SDimitry Andric     encodeULEB128(Entry.MinCount, OS);
6790b57cec5SDimitry Andric     encodeULEB128(Entry.NumCounts, OS);
6800b57cec5SDimitry Andric   }
6810b57cec5SDimitry Andric   return sampleprof_error::success;
6820b57cec5SDimitry Andric }
writeBody(const FunctionSamples & S)6830b57cec5SDimitry Andric std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
6840b57cec5SDimitry Andric   auto &OS = *OutputStream;
6850b57cec5SDimitry Andric 
686*5f7ddb14SDimitry Andric   if (std::error_code EC =
687*5f7ddb14SDimitry Andric           writeNameIdx(S.getNameWithContext(), FunctionSamples::ProfileIsCS))
6880b57cec5SDimitry Andric     return EC;
6890b57cec5SDimitry Andric 
6900b57cec5SDimitry Andric   encodeULEB128(S.getTotalSamples(), OS);
6910b57cec5SDimitry Andric 
6920b57cec5SDimitry Andric   // Emit all the body samples.
6930b57cec5SDimitry Andric   encodeULEB128(S.getBodySamples().size(), OS);
6940b57cec5SDimitry Andric   for (const auto &I : S.getBodySamples()) {
6950b57cec5SDimitry Andric     LineLocation Loc = I.first;
6960b57cec5SDimitry Andric     const SampleRecord &Sample = I.second;
6970b57cec5SDimitry Andric     encodeULEB128(Loc.LineOffset, OS);
6980b57cec5SDimitry Andric     encodeULEB128(Loc.Discriminator, OS);
6990b57cec5SDimitry Andric     encodeULEB128(Sample.getSamples(), OS);
7000b57cec5SDimitry Andric     encodeULEB128(Sample.getCallTargets().size(), OS);
7018bcb0991SDimitry Andric     for (const auto &J : Sample.getSortedCallTargets()) {
7028bcb0991SDimitry Andric       StringRef Callee = J.first;
7030b57cec5SDimitry Andric       uint64_t CalleeSamples = J.second;
7040b57cec5SDimitry Andric       if (std::error_code EC = writeNameIdx(Callee))
7050b57cec5SDimitry Andric         return EC;
7060b57cec5SDimitry Andric       encodeULEB128(CalleeSamples, OS);
7070b57cec5SDimitry Andric     }
7080b57cec5SDimitry Andric   }
7090b57cec5SDimitry Andric 
7100b57cec5SDimitry Andric   // Recursively emit all the callsite samples.
7110b57cec5SDimitry Andric   uint64_t NumCallsites = 0;
7120b57cec5SDimitry Andric   for (const auto &J : S.getCallsiteSamples())
7130b57cec5SDimitry Andric     NumCallsites += J.second.size();
7140b57cec5SDimitry Andric   encodeULEB128(NumCallsites, OS);
7150b57cec5SDimitry Andric   for (const auto &J : S.getCallsiteSamples())
7160b57cec5SDimitry Andric     for (const auto &FS : J.second) {
7170b57cec5SDimitry Andric       LineLocation Loc = J.first;
7180b57cec5SDimitry Andric       const FunctionSamples &CalleeSamples = FS.second;
7190b57cec5SDimitry Andric       encodeULEB128(Loc.LineOffset, OS);
7200b57cec5SDimitry Andric       encodeULEB128(Loc.Discriminator, OS);
7210b57cec5SDimitry Andric       if (std::error_code EC = writeBody(CalleeSamples))
7220b57cec5SDimitry Andric         return EC;
7230b57cec5SDimitry Andric     }
7240b57cec5SDimitry Andric 
7250b57cec5SDimitry Andric   return sampleprof_error::success;
7260b57cec5SDimitry Andric }
7270b57cec5SDimitry Andric 
7280b57cec5SDimitry Andric /// Write samples of a top-level function to a binary file.
7290b57cec5SDimitry Andric ///
7300b57cec5SDimitry Andric /// \returns true if the samples were written successfully, false otherwise.
7318bcb0991SDimitry Andric std::error_code
writeSample(const FunctionSamples & S)7328bcb0991SDimitry Andric SampleProfileWriterBinary::writeSample(const FunctionSamples &S) {
7330b57cec5SDimitry Andric   encodeULEB128(S.getHeadSamples(), *OutputStream);
7340b57cec5SDimitry Andric   return writeBody(S);
7350b57cec5SDimitry Andric }
7360b57cec5SDimitry Andric 
7370b57cec5SDimitry Andric std::error_code
writeSample(const FunctionSamples & S)7388bcb0991SDimitry Andric SampleProfileWriterCompactBinary::writeSample(const FunctionSamples &S) {
7390b57cec5SDimitry Andric   uint64_t Offset = OutputStream->tell();
7400b57cec5SDimitry Andric   StringRef Name = S.getName();
7410b57cec5SDimitry Andric   FuncOffsetTable[Name] = Offset;
7420b57cec5SDimitry Andric   encodeULEB128(S.getHeadSamples(), *OutputStream);
7430b57cec5SDimitry Andric   return writeBody(S);
7440b57cec5SDimitry Andric }
7450b57cec5SDimitry Andric 
7460b57cec5SDimitry Andric /// Create a sample profile file writer based on the specified format.
7470b57cec5SDimitry Andric ///
7480b57cec5SDimitry Andric /// \param Filename The file to create.
7490b57cec5SDimitry Andric ///
7500b57cec5SDimitry Andric /// \param Format Encoding format for the profile file.
7510b57cec5SDimitry Andric ///
7520b57cec5SDimitry Andric /// \returns an error code indicating the status of the created writer.
7530b57cec5SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileWriter>>
create(StringRef Filename,SampleProfileFormat Format)7540b57cec5SDimitry Andric SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
7550b57cec5SDimitry Andric   std::error_code EC;
7560b57cec5SDimitry Andric   std::unique_ptr<raw_ostream> OS;
7578bcb0991SDimitry Andric   if (Format == SPF_Binary || Format == SPF_Ext_Binary ||
7588bcb0991SDimitry Andric       Format == SPF_Compact_Binary)
7598bcb0991SDimitry Andric     OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None));
7600b57cec5SDimitry Andric   else
761*5f7ddb14SDimitry Andric     OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_TextWithCRLF));
7620b57cec5SDimitry Andric   if (EC)
7630b57cec5SDimitry Andric     return EC;
7640b57cec5SDimitry Andric 
7650b57cec5SDimitry Andric   return create(OS, Format);
7660b57cec5SDimitry Andric }
7670b57cec5SDimitry Andric 
7680b57cec5SDimitry Andric /// Create a sample profile stream writer based on the specified format.
7690b57cec5SDimitry Andric ///
7700b57cec5SDimitry Andric /// \param OS The output stream to store the profile data to.
7710b57cec5SDimitry Andric ///
7720b57cec5SDimitry Andric /// \param Format Encoding format for the profile file.
7730b57cec5SDimitry Andric ///
7740b57cec5SDimitry Andric /// \returns an error code indicating the status of the created writer.
7750b57cec5SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileWriter>>
create(std::unique_ptr<raw_ostream> & OS,SampleProfileFormat Format)7760b57cec5SDimitry Andric SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
7770b57cec5SDimitry Andric                             SampleProfileFormat Format) {
7780b57cec5SDimitry Andric   std::error_code EC;
7790b57cec5SDimitry Andric   std::unique_ptr<SampleProfileWriter> Writer;
7800b57cec5SDimitry Andric 
781*5f7ddb14SDimitry Andric   // Currently only Text and Extended Binary format are supported for CSSPGO.
782*5f7ddb14SDimitry Andric   if ((FunctionSamples::ProfileIsCS || FunctionSamples::ProfileIsProbeBased) &&
783*5f7ddb14SDimitry Andric       (Format == SPF_Binary || Format == SPF_Compact_Binary))
784*5f7ddb14SDimitry Andric     return sampleprof_error::unsupported_writing_format;
785*5f7ddb14SDimitry Andric 
7860b57cec5SDimitry Andric   if (Format == SPF_Binary)
7870b57cec5SDimitry Andric     Writer.reset(new SampleProfileWriterRawBinary(OS));
7888bcb0991SDimitry Andric   else if (Format == SPF_Ext_Binary)
7898bcb0991SDimitry Andric     Writer.reset(new SampleProfileWriterExtBinary(OS));
7900b57cec5SDimitry Andric   else if (Format == SPF_Compact_Binary)
7910b57cec5SDimitry Andric     Writer.reset(new SampleProfileWriterCompactBinary(OS));
7920b57cec5SDimitry Andric   else if (Format == SPF_Text)
7930b57cec5SDimitry Andric     Writer.reset(new SampleProfileWriterText(OS));
7940b57cec5SDimitry Andric   else if (Format == SPF_GCC)
7950b57cec5SDimitry Andric     EC = sampleprof_error::unsupported_writing_format;
7960b57cec5SDimitry Andric   else
7970b57cec5SDimitry Andric     EC = sampleprof_error::unrecognized_format;
7980b57cec5SDimitry Andric 
7990b57cec5SDimitry Andric   if (EC)
8000b57cec5SDimitry Andric     return EC;
8010b57cec5SDimitry Andric 
8028bcb0991SDimitry Andric   Writer->Format = Format;
8030b57cec5SDimitry Andric   return std::move(Writer);
8040b57cec5SDimitry Andric }
8050b57cec5SDimitry Andric 
computeSummary(const StringMap<FunctionSamples> & ProfileMap)8060b57cec5SDimitry Andric void SampleProfileWriter::computeSummary(
8070b57cec5SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
8080b57cec5SDimitry Andric   SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
809af732203SDimitry Andric   Summary = Builder.computeSummaryForProfiles(ProfileMap);
8100b57cec5SDimitry Andric }
811