1*0b57cec5SDimitry Andric //===- SampleProfWriter.cpp - Write LLVM sample profile data --------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // This file implements the class that writes LLVM sample profiles. It
10*0b57cec5SDimitry Andric // supports two file formats: text and binary. The textual representation
11*0b57cec5SDimitry Andric // is useful for debugging and testing purposes. The binary representation
12*0b57cec5SDimitry Andric // is more compact, resulting in smaller file sizes. However, they can
13*0b57cec5SDimitry Andric // both be used interchangeably.
14*0b57cec5SDimitry Andric //
15*0b57cec5SDimitry Andric // See lib/ProfileData/SampleProfReader.cpp for documentation on each of the
16*0b57cec5SDimitry Andric // supported formats.
17*0b57cec5SDimitry Andric //
18*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
19*0b57cec5SDimitry Andric 
20*0b57cec5SDimitry Andric #include "llvm/ProfileData/SampleProfWriter.h"
21*0b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
22*0b57cec5SDimitry Andric #include "llvm/ProfileData/ProfileCommon.h"
23*0b57cec5SDimitry Andric #include "llvm/ProfileData/SampleProf.h"
248bcb0991SDimitry Andric #include "llvm/Support/Compression.h"
25*0b57cec5SDimitry Andric #include "llvm/Support/Endian.h"
26*0b57cec5SDimitry Andric #include "llvm/Support/EndianStream.h"
27*0b57cec5SDimitry Andric #include "llvm/Support/ErrorOr.h"
28*0b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
29*0b57cec5SDimitry Andric #include "llvm/Support/LEB128.h"
30*0b57cec5SDimitry Andric #include "llvm/Support/MD5.h"
31*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
32*0b57cec5SDimitry Andric #include <algorithm>
33*0b57cec5SDimitry Andric #include <cstdint>
34*0b57cec5SDimitry Andric #include <memory>
35*0b57cec5SDimitry Andric #include <set>
36*0b57cec5SDimitry Andric #include <system_error>
37*0b57cec5SDimitry Andric #include <utility>
38*0b57cec5SDimitry Andric #include <vector>
39*0b57cec5SDimitry Andric 
40*0b57cec5SDimitry Andric using namespace llvm;
41*0b57cec5SDimitry Andric using namespace sampleprof;
42*0b57cec5SDimitry Andric 
438bcb0991SDimitry Andric std::error_code SampleProfileWriter::writeFuncProfiles(
448bcb0991SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
45*0b57cec5SDimitry Andric   // Sort the ProfileMap by total samples.
46*0b57cec5SDimitry Andric   typedef std::pair<StringRef, const FunctionSamples *> NameFunctionSamples;
47*0b57cec5SDimitry Andric   std::vector<NameFunctionSamples> V;
48*0b57cec5SDimitry Andric   for (const auto &I : ProfileMap)
49*0b57cec5SDimitry Andric     V.push_back(std::make_pair(I.getKey(), &I.second));
50*0b57cec5SDimitry Andric 
51*0b57cec5SDimitry Andric   llvm::stable_sort(
52*0b57cec5SDimitry Andric       V, [](const NameFunctionSamples &A, const NameFunctionSamples &B) {
53*0b57cec5SDimitry Andric         if (A.second->getTotalSamples() == B.second->getTotalSamples())
54*0b57cec5SDimitry Andric           return A.first > B.first;
55*0b57cec5SDimitry Andric         return A.second->getTotalSamples() > B.second->getTotalSamples();
56*0b57cec5SDimitry Andric       });
57*0b57cec5SDimitry Andric 
58*0b57cec5SDimitry Andric   for (const auto &I : V) {
598bcb0991SDimitry Andric     if (std::error_code EC = writeSample(*I.second))
60*0b57cec5SDimitry Andric       return EC;
61*0b57cec5SDimitry Andric   }
62*0b57cec5SDimitry Andric   return sampleprof_error::success;
63*0b57cec5SDimitry Andric }
64*0b57cec5SDimitry Andric 
658bcb0991SDimitry Andric std::error_code
668bcb0991SDimitry Andric SampleProfileWriter::write(const StringMap<FunctionSamples> &ProfileMap) {
678bcb0991SDimitry Andric   if (std::error_code EC = writeHeader(ProfileMap))
688bcb0991SDimitry Andric     return EC;
698bcb0991SDimitry Andric 
708bcb0991SDimitry Andric   if (std::error_code EC = writeFuncProfiles(ProfileMap))
718bcb0991SDimitry Andric     return EC;
728bcb0991SDimitry Andric 
738bcb0991SDimitry Andric   return sampleprof_error::success;
748bcb0991SDimitry Andric }
758bcb0991SDimitry Andric 
768bcb0991SDimitry Andric SecHdrTableEntry &
778bcb0991SDimitry Andric SampleProfileWriterExtBinaryBase::getEntryInLayout(SecType Type) {
788bcb0991SDimitry Andric   auto SecIt = std::find_if(
798bcb0991SDimitry Andric       SectionHdrLayout.begin(), SectionHdrLayout.end(),
808bcb0991SDimitry Andric       [=](const auto &Entry) -> bool { return Entry.Type == Type; });
818bcb0991SDimitry Andric   return *SecIt;
828bcb0991SDimitry Andric }
838bcb0991SDimitry Andric 
848bcb0991SDimitry Andric /// Return the current position and prepare to use it as the start
858bcb0991SDimitry Andric /// position of a section.
868bcb0991SDimitry Andric uint64_t SampleProfileWriterExtBinaryBase::markSectionStart(SecType Type) {
878bcb0991SDimitry Andric   uint64_t SectionStart = OutputStream->tell();
888bcb0991SDimitry Andric   auto &Entry = getEntryInLayout(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 
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 
1158bcb0991SDimitry Andric /// Add a new section into section header table.
1168bcb0991SDimitry Andric std::error_code
1178bcb0991SDimitry Andric SampleProfileWriterExtBinaryBase::addNewSection(SecType Type,
1188bcb0991SDimitry Andric                                                 uint64_t SectionStart) {
1198bcb0991SDimitry Andric   auto Entry = getEntryInLayout(Type);
1205ffd83dbSDimitry Andric   if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress)) {
1218bcb0991SDimitry Andric     LocalBufStream.swap(OutputStream);
1228bcb0991SDimitry Andric     if (std::error_code EC = compressAndOutput())
1238bcb0991SDimitry Andric       return EC;
1248bcb0991SDimitry Andric   }
1258bcb0991SDimitry Andric   SecHdrTable.push_back({Type, Entry.Flags, SectionStart - FileStart,
1268bcb0991SDimitry Andric                          OutputStream->tell() - SectionStart});
1278bcb0991SDimitry Andric   return sampleprof_error::success;
1288bcb0991SDimitry Andric }
1298bcb0991SDimitry Andric 
1308bcb0991SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::write(
1318bcb0991SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
1328bcb0991SDimitry Andric   if (std::error_code EC = writeHeader(ProfileMap))
1338bcb0991SDimitry Andric     return EC;
1348bcb0991SDimitry Andric 
1358bcb0991SDimitry Andric   std::string LocalBuf;
1368bcb0991SDimitry Andric   LocalBufStream = std::make_unique<raw_string_ostream>(LocalBuf);
1378bcb0991SDimitry Andric   if (std::error_code EC = writeSections(ProfileMap))
1388bcb0991SDimitry Andric     return EC;
1398bcb0991SDimitry Andric 
1408bcb0991SDimitry Andric   if (std::error_code EC = writeSecHdrTable())
1418bcb0991SDimitry Andric     return EC;
1428bcb0991SDimitry Andric 
1438bcb0991SDimitry Andric   return sampleprof_error::success;
1448bcb0991SDimitry Andric }
1458bcb0991SDimitry Andric 
1468bcb0991SDimitry Andric std::error_code
1478bcb0991SDimitry Andric SampleProfileWriterExtBinary::writeSample(const FunctionSamples &S) {
1488bcb0991SDimitry Andric   uint64_t Offset = OutputStream->tell();
1498bcb0991SDimitry Andric   StringRef Name = S.getName();
1508bcb0991SDimitry Andric   FuncOffsetTable[Name] = Offset - SecLBRProfileStart;
1518bcb0991SDimitry Andric   encodeULEB128(S.getHeadSamples(), *OutputStream);
1528bcb0991SDimitry Andric   return writeBody(S);
1538bcb0991SDimitry Andric }
1548bcb0991SDimitry Andric 
1558bcb0991SDimitry Andric std::error_code SampleProfileWriterExtBinary::writeFuncOffsetTable() {
1568bcb0991SDimitry Andric   auto &OS = *OutputStream;
1578bcb0991SDimitry Andric 
1588bcb0991SDimitry Andric   // Write out the table size.
1598bcb0991SDimitry Andric   encodeULEB128(FuncOffsetTable.size(), OS);
1608bcb0991SDimitry Andric 
1618bcb0991SDimitry Andric   // Write out FuncOffsetTable.
1628bcb0991SDimitry Andric   for (auto entry : FuncOffsetTable) {
1638bcb0991SDimitry Andric     writeNameIdx(entry.first);
1648bcb0991SDimitry Andric     encodeULEB128(entry.second, OS);
1658bcb0991SDimitry Andric   }
1668bcb0991SDimitry Andric   return sampleprof_error::success;
1678bcb0991SDimitry Andric }
1688bcb0991SDimitry Andric 
1695ffd83dbSDimitry Andric std::error_code SampleProfileWriterExtBinary::writeNameTable() {
1705ffd83dbSDimitry Andric   if (!UseMD5)
1715ffd83dbSDimitry Andric     return SampleProfileWriterBinary::writeNameTable();
1725ffd83dbSDimitry Andric 
1735ffd83dbSDimitry Andric   auto &OS = *OutputStream;
1745ffd83dbSDimitry Andric   std::set<StringRef> V;
1755ffd83dbSDimitry Andric   stablizeNameTable(V);
1765ffd83dbSDimitry Andric 
1775ffd83dbSDimitry Andric   // Write out the name table.
1785ffd83dbSDimitry Andric   encodeULEB128(NameTable.size(), OS);
1795ffd83dbSDimitry Andric   for (auto N : V) {
1805ffd83dbSDimitry Andric     encodeULEB128(MD5Hash(N), OS);
1815ffd83dbSDimitry Andric   }
1825ffd83dbSDimitry Andric   return sampleprof_error::success;
1835ffd83dbSDimitry Andric }
1845ffd83dbSDimitry Andric 
1858bcb0991SDimitry Andric std::error_code SampleProfileWriterExtBinary::writeSections(
1868bcb0991SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
1878bcb0991SDimitry Andric   uint64_t SectionStart = markSectionStart(SecProfSummary);
1888bcb0991SDimitry Andric   computeSummary(ProfileMap);
1898bcb0991SDimitry Andric   if (auto EC = writeSummary())
1908bcb0991SDimitry Andric     return EC;
1918bcb0991SDimitry Andric   if (std::error_code EC = addNewSection(SecProfSummary, SectionStart))
1928bcb0991SDimitry Andric     return EC;
1938bcb0991SDimitry Andric 
1948bcb0991SDimitry Andric   // Generate the name table for all the functions referenced in the profile.
1958bcb0991SDimitry Andric   SectionStart = markSectionStart(SecNameTable);
1968bcb0991SDimitry Andric   for (const auto &I : ProfileMap) {
1978bcb0991SDimitry Andric     addName(I.first());
1988bcb0991SDimitry Andric     addNames(I.second);
1998bcb0991SDimitry Andric   }
2008bcb0991SDimitry Andric   writeNameTable();
2018bcb0991SDimitry Andric   if (std::error_code EC = addNewSection(SecNameTable, SectionStart))
2028bcb0991SDimitry Andric     return EC;
2038bcb0991SDimitry Andric 
2048bcb0991SDimitry Andric   SectionStart = markSectionStart(SecLBRProfile);
2058bcb0991SDimitry Andric   SecLBRProfileStart = OutputStream->tell();
2068bcb0991SDimitry Andric   if (std::error_code EC = writeFuncProfiles(ProfileMap))
2078bcb0991SDimitry Andric     return EC;
2088bcb0991SDimitry Andric   if (std::error_code EC = addNewSection(SecLBRProfile, SectionStart))
2098bcb0991SDimitry Andric     return EC;
2108bcb0991SDimitry Andric 
2118bcb0991SDimitry Andric   if (ProfSymList && ProfSymList->toCompress())
2128bcb0991SDimitry Andric     setToCompressSection(SecProfileSymbolList);
2138bcb0991SDimitry Andric 
2148bcb0991SDimitry Andric   SectionStart = markSectionStart(SecProfileSymbolList);
2158bcb0991SDimitry Andric   if (ProfSymList && ProfSymList->size() > 0)
2168bcb0991SDimitry Andric     if (std::error_code EC = ProfSymList->write(*OutputStream))
2178bcb0991SDimitry Andric       return EC;
2188bcb0991SDimitry Andric   if (std::error_code EC = addNewSection(SecProfileSymbolList, SectionStart))
2198bcb0991SDimitry Andric     return EC;
2208bcb0991SDimitry Andric 
2218bcb0991SDimitry Andric   SectionStart = markSectionStart(SecFuncOffsetTable);
2228bcb0991SDimitry Andric   if (std::error_code EC = writeFuncOffsetTable())
2238bcb0991SDimitry Andric     return EC;
2248bcb0991SDimitry Andric   if (std::error_code EC = addNewSection(SecFuncOffsetTable, SectionStart))
2258bcb0991SDimitry Andric     return EC;
2268bcb0991SDimitry Andric 
2278bcb0991SDimitry Andric   return sampleprof_error::success;
2288bcb0991SDimitry Andric }
2298bcb0991SDimitry Andric 
230*0b57cec5SDimitry Andric std::error_code SampleProfileWriterCompactBinary::write(
231*0b57cec5SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
232*0b57cec5SDimitry Andric   if (std::error_code EC = SampleProfileWriter::write(ProfileMap))
233*0b57cec5SDimitry Andric     return EC;
234*0b57cec5SDimitry Andric   if (std::error_code EC = writeFuncOffsetTable())
235*0b57cec5SDimitry Andric     return EC;
236*0b57cec5SDimitry Andric   return sampleprof_error::success;
237*0b57cec5SDimitry Andric }
238*0b57cec5SDimitry Andric 
239*0b57cec5SDimitry Andric /// Write samples to a text file.
240*0b57cec5SDimitry Andric ///
241*0b57cec5SDimitry Andric /// Note: it may be tempting to implement this in terms of
242*0b57cec5SDimitry Andric /// FunctionSamples::print().  Please don't.  The dump functionality is intended
243*0b57cec5SDimitry Andric /// for debugging and has no specified form.
244*0b57cec5SDimitry Andric ///
245*0b57cec5SDimitry Andric /// The format used here is more structured and deliberate because
246*0b57cec5SDimitry Andric /// it needs to be parsed by the SampleProfileReaderText class.
2478bcb0991SDimitry Andric std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) {
248*0b57cec5SDimitry Andric   auto &OS = *OutputStream;
249*0b57cec5SDimitry Andric   OS << S.getName() << ":" << S.getTotalSamples();
250*0b57cec5SDimitry Andric   if (Indent == 0)
251*0b57cec5SDimitry Andric     OS << ":" << S.getHeadSamples();
252*0b57cec5SDimitry Andric   OS << "\n";
253*0b57cec5SDimitry Andric 
254*0b57cec5SDimitry Andric   SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples());
255*0b57cec5SDimitry Andric   for (const auto &I : SortedSamples.get()) {
256*0b57cec5SDimitry Andric     LineLocation Loc = I->first;
257*0b57cec5SDimitry Andric     const SampleRecord &Sample = I->second;
258*0b57cec5SDimitry Andric     OS.indent(Indent + 1);
259*0b57cec5SDimitry Andric     if (Loc.Discriminator == 0)
260*0b57cec5SDimitry Andric       OS << Loc.LineOffset << ": ";
261*0b57cec5SDimitry Andric     else
262*0b57cec5SDimitry Andric       OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
263*0b57cec5SDimitry Andric 
264*0b57cec5SDimitry Andric     OS << Sample.getSamples();
265*0b57cec5SDimitry Andric 
2668bcb0991SDimitry Andric     for (const auto &J : Sample.getSortedCallTargets())
2678bcb0991SDimitry Andric       OS << " " << J.first << ":" << J.second;
268*0b57cec5SDimitry Andric     OS << "\n";
269*0b57cec5SDimitry Andric   }
270*0b57cec5SDimitry Andric 
271*0b57cec5SDimitry Andric   SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples(
272*0b57cec5SDimitry Andric       S.getCallsiteSamples());
273*0b57cec5SDimitry Andric   Indent += 1;
274*0b57cec5SDimitry Andric   for (const auto &I : SortedCallsiteSamples.get())
275*0b57cec5SDimitry Andric     for (const auto &FS : I->second) {
276*0b57cec5SDimitry Andric       LineLocation Loc = I->first;
277*0b57cec5SDimitry Andric       const FunctionSamples &CalleeSamples = FS.second;
278*0b57cec5SDimitry Andric       OS.indent(Indent);
279*0b57cec5SDimitry Andric       if (Loc.Discriminator == 0)
280*0b57cec5SDimitry Andric         OS << Loc.LineOffset << ": ";
281*0b57cec5SDimitry Andric       else
282*0b57cec5SDimitry Andric         OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
2838bcb0991SDimitry Andric       if (std::error_code EC = writeSample(CalleeSamples))
284*0b57cec5SDimitry Andric         return EC;
285*0b57cec5SDimitry Andric     }
286*0b57cec5SDimitry Andric   Indent -= 1;
287*0b57cec5SDimitry Andric 
288*0b57cec5SDimitry Andric   return sampleprof_error::success;
289*0b57cec5SDimitry Andric }
290*0b57cec5SDimitry Andric 
291*0b57cec5SDimitry Andric std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) {
292*0b57cec5SDimitry Andric   const auto &ret = NameTable.find(FName);
293*0b57cec5SDimitry Andric   if (ret == NameTable.end())
294*0b57cec5SDimitry Andric     return sampleprof_error::truncated_name_table;
295*0b57cec5SDimitry Andric   encodeULEB128(ret->second, *OutputStream);
296*0b57cec5SDimitry Andric   return sampleprof_error::success;
297*0b57cec5SDimitry Andric }
298*0b57cec5SDimitry Andric 
299*0b57cec5SDimitry Andric void SampleProfileWriterBinary::addName(StringRef FName) {
300*0b57cec5SDimitry Andric   NameTable.insert(std::make_pair(FName, 0));
301*0b57cec5SDimitry Andric }
302*0b57cec5SDimitry Andric 
303*0b57cec5SDimitry Andric void SampleProfileWriterBinary::addNames(const FunctionSamples &S) {
304*0b57cec5SDimitry Andric   // Add all the names in indirect call targets.
305*0b57cec5SDimitry Andric   for (const auto &I : S.getBodySamples()) {
306*0b57cec5SDimitry Andric     const SampleRecord &Sample = I.second;
307*0b57cec5SDimitry Andric     for (const auto &J : Sample.getCallTargets())
308*0b57cec5SDimitry Andric       addName(J.first());
309*0b57cec5SDimitry Andric   }
310*0b57cec5SDimitry Andric 
311*0b57cec5SDimitry Andric   // Recursively add all the names for inlined callsites.
312*0b57cec5SDimitry Andric   for (const auto &J : S.getCallsiteSamples())
313*0b57cec5SDimitry Andric     for (const auto &FS : J.second) {
314*0b57cec5SDimitry Andric       const FunctionSamples &CalleeSamples = FS.second;
315*0b57cec5SDimitry Andric       addName(CalleeSamples.getName());
316*0b57cec5SDimitry Andric       addNames(CalleeSamples);
317*0b57cec5SDimitry Andric     }
318*0b57cec5SDimitry Andric }
319*0b57cec5SDimitry Andric 
320*0b57cec5SDimitry Andric void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) {
321*0b57cec5SDimitry Andric   // Sort the names to make NameTable deterministic.
322*0b57cec5SDimitry Andric   for (const auto &I : NameTable)
323*0b57cec5SDimitry Andric     V.insert(I.first);
324*0b57cec5SDimitry Andric   int i = 0;
325*0b57cec5SDimitry Andric   for (const StringRef &N : V)
326*0b57cec5SDimitry Andric     NameTable[N] = i++;
327*0b57cec5SDimitry Andric }
328*0b57cec5SDimitry Andric 
3298bcb0991SDimitry Andric std::error_code SampleProfileWriterBinary::writeNameTable() {
330*0b57cec5SDimitry Andric   auto &OS = *OutputStream;
331*0b57cec5SDimitry Andric   std::set<StringRef> V;
332*0b57cec5SDimitry Andric   stablizeNameTable(V);
333*0b57cec5SDimitry Andric 
334*0b57cec5SDimitry Andric   // Write out the name table.
335*0b57cec5SDimitry Andric   encodeULEB128(NameTable.size(), OS);
336*0b57cec5SDimitry Andric   for (auto N : V) {
337*0b57cec5SDimitry Andric     OS << N;
338*0b57cec5SDimitry Andric     encodeULEB128(0, OS);
339*0b57cec5SDimitry Andric   }
340*0b57cec5SDimitry Andric   return sampleprof_error::success;
341*0b57cec5SDimitry Andric }
342*0b57cec5SDimitry Andric 
343*0b57cec5SDimitry Andric std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() {
344*0b57cec5SDimitry Andric   auto &OS = *OutputStream;
345*0b57cec5SDimitry Andric 
346*0b57cec5SDimitry Andric   // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable.
347*0b57cec5SDimitry Andric   auto &OFS = static_cast<raw_fd_ostream &>(OS);
348*0b57cec5SDimitry Andric   uint64_t FuncOffsetTableStart = OS.tell();
349*0b57cec5SDimitry Andric   if (OFS.seek(TableOffset) == (uint64_t)-1)
350*0b57cec5SDimitry Andric     return sampleprof_error::ostream_seek_unsupported;
351*0b57cec5SDimitry Andric   support::endian::Writer Writer(*OutputStream, support::little);
352*0b57cec5SDimitry Andric   Writer.write(FuncOffsetTableStart);
353*0b57cec5SDimitry Andric   if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1)
354*0b57cec5SDimitry Andric     return sampleprof_error::ostream_seek_unsupported;
355*0b57cec5SDimitry Andric 
356*0b57cec5SDimitry Andric   // Write out the table size.
357*0b57cec5SDimitry Andric   encodeULEB128(FuncOffsetTable.size(), OS);
358*0b57cec5SDimitry Andric 
359*0b57cec5SDimitry Andric   // Write out FuncOffsetTable.
360*0b57cec5SDimitry Andric   for (auto entry : FuncOffsetTable) {
361*0b57cec5SDimitry Andric     writeNameIdx(entry.first);
362*0b57cec5SDimitry Andric     encodeULEB128(entry.second, OS);
363*0b57cec5SDimitry Andric   }
364*0b57cec5SDimitry Andric   return sampleprof_error::success;
365*0b57cec5SDimitry Andric }
366*0b57cec5SDimitry Andric 
367*0b57cec5SDimitry Andric std::error_code SampleProfileWriterCompactBinary::writeNameTable() {
368*0b57cec5SDimitry Andric   auto &OS = *OutputStream;
369*0b57cec5SDimitry Andric   std::set<StringRef> V;
370*0b57cec5SDimitry Andric   stablizeNameTable(V);
371*0b57cec5SDimitry Andric 
372*0b57cec5SDimitry Andric   // Write out the name table.
373*0b57cec5SDimitry Andric   encodeULEB128(NameTable.size(), OS);
374*0b57cec5SDimitry Andric   for (auto N : V) {
375*0b57cec5SDimitry Andric     encodeULEB128(MD5Hash(N), OS);
376*0b57cec5SDimitry Andric   }
377*0b57cec5SDimitry Andric   return sampleprof_error::success;
378*0b57cec5SDimitry Andric }
379*0b57cec5SDimitry Andric 
3808bcb0991SDimitry Andric std::error_code
3818bcb0991SDimitry Andric SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) {
382*0b57cec5SDimitry Andric   auto &OS = *OutputStream;
383*0b57cec5SDimitry Andric   // Write file magic identifier.
3848bcb0991SDimitry Andric   encodeULEB128(SPMagic(Format), OS);
385*0b57cec5SDimitry Andric   encodeULEB128(SPVersion(), OS);
386*0b57cec5SDimitry Andric   return sampleprof_error::success;
387*0b57cec5SDimitry Andric }
388*0b57cec5SDimitry Andric 
389*0b57cec5SDimitry Andric std::error_code SampleProfileWriterBinary::writeHeader(
390*0b57cec5SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
3918bcb0991SDimitry Andric   writeMagicIdent(Format);
392*0b57cec5SDimitry Andric 
393*0b57cec5SDimitry Andric   computeSummary(ProfileMap);
394*0b57cec5SDimitry Andric   if (auto EC = writeSummary())
395*0b57cec5SDimitry Andric     return EC;
396*0b57cec5SDimitry Andric 
397*0b57cec5SDimitry Andric   // Generate the name table for all the functions referenced in the profile.
398*0b57cec5SDimitry Andric   for (const auto &I : ProfileMap) {
399*0b57cec5SDimitry Andric     addName(I.first());
400*0b57cec5SDimitry Andric     addNames(I.second);
401*0b57cec5SDimitry Andric   }
402*0b57cec5SDimitry Andric 
403*0b57cec5SDimitry Andric   writeNameTable();
404*0b57cec5SDimitry Andric   return sampleprof_error::success;
405*0b57cec5SDimitry Andric }
406*0b57cec5SDimitry Andric 
4078bcb0991SDimitry Andric void SampleProfileWriterExtBinaryBase::setToCompressAllSections() {
4088bcb0991SDimitry Andric   for (auto &Entry : SectionHdrLayout)
4095ffd83dbSDimitry Andric     addSecFlag(Entry, SecCommonFlags::SecFlagCompress);
4108bcb0991SDimitry Andric }
4118bcb0991SDimitry Andric 
4128bcb0991SDimitry Andric void SampleProfileWriterExtBinaryBase::setToCompressSection(SecType Type) {
4135ffd83dbSDimitry Andric   addSectionFlag(Type, SecCommonFlags::SecFlagCompress);
4148bcb0991SDimitry Andric }
4158bcb0991SDimitry Andric 
4168bcb0991SDimitry Andric void SampleProfileWriterExtBinaryBase::allocSecHdrTable() {
4178bcb0991SDimitry Andric   support::endian::Writer Writer(*OutputStream, support::little);
4188bcb0991SDimitry Andric 
4198bcb0991SDimitry Andric   Writer.write(static_cast<uint64_t>(SectionHdrLayout.size()));
4208bcb0991SDimitry Andric   SecHdrTableOffset = OutputStream->tell();
4218bcb0991SDimitry Andric   for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) {
4228bcb0991SDimitry Andric     Writer.write(static_cast<uint64_t>(-1));
4238bcb0991SDimitry Andric     Writer.write(static_cast<uint64_t>(-1));
4248bcb0991SDimitry Andric     Writer.write(static_cast<uint64_t>(-1));
4258bcb0991SDimitry Andric     Writer.write(static_cast<uint64_t>(-1));
4268bcb0991SDimitry Andric   }
4278bcb0991SDimitry Andric }
4288bcb0991SDimitry Andric 
4298bcb0991SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() {
4308bcb0991SDimitry Andric   auto &OFS = static_cast<raw_fd_ostream &>(*OutputStream);
4318bcb0991SDimitry Andric   uint64_t Saved = OutputStream->tell();
4328bcb0991SDimitry Andric 
4338bcb0991SDimitry Andric   // Set OutputStream to the location saved in SecHdrTableOffset.
4348bcb0991SDimitry Andric   if (OFS.seek(SecHdrTableOffset) == (uint64_t)-1)
4358bcb0991SDimitry Andric     return sampleprof_error::ostream_seek_unsupported;
4368bcb0991SDimitry Andric   support::endian::Writer Writer(*OutputStream, support::little);
4378bcb0991SDimitry Andric 
4388bcb0991SDimitry Andric   DenseMap<uint32_t, uint32_t> IndexMap;
4398bcb0991SDimitry Andric   for (uint32_t i = 0; i < SecHdrTable.size(); i++) {
4408bcb0991SDimitry Andric     IndexMap.insert({static_cast<uint32_t>(SecHdrTable[i].Type), i});
4418bcb0991SDimitry Andric   }
4428bcb0991SDimitry Andric 
4438bcb0991SDimitry Andric   // Write the section header table in the order specified in
4448bcb0991SDimitry Andric   // SectionHdrLayout. That is the sections order Reader will see.
4458bcb0991SDimitry Andric   // Note that the sections order in which Reader expects to read
4468bcb0991SDimitry Andric   // may be different from the order in which Writer is able to
4478bcb0991SDimitry Andric   // write, so we need to adjust the order in SecHdrTable to be
4488bcb0991SDimitry Andric   // consistent with SectionHdrLayout when we write SecHdrTable
4498bcb0991SDimitry Andric   // to the memory.
4508bcb0991SDimitry Andric   for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) {
4518bcb0991SDimitry Andric     uint32_t idx = IndexMap[static_cast<uint32_t>(SectionHdrLayout[i].Type)];
4528bcb0991SDimitry Andric     Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Type));
4538bcb0991SDimitry Andric     Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Flags));
4548bcb0991SDimitry Andric     Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Offset));
4558bcb0991SDimitry Andric     Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Size));
4568bcb0991SDimitry Andric   }
4578bcb0991SDimitry Andric 
4588bcb0991SDimitry Andric   // Reset OutputStream.
4598bcb0991SDimitry Andric   if (OFS.seek(Saved) == (uint64_t)-1)
4608bcb0991SDimitry Andric     return sampleprof_error::ostream_seek_unsupported;
4618bcb0991SDimitry Andric 
4628bcb0991SDimitry Andric   return sampleprof_error::success;
4638bcb0991SDimitry Andric }
4648bcb0991SDimitry Andric 
4658bcb0991SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeHeader(
4668bcb0991SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
4678bcb0991SDimitry Andric   auto &OS = *OutputStream;
4688bcb0991SDimitry Andric   FileStart = OS.tell();
4698bcb0991SDimitry Andric   writeMagicIdent(Format);
4708bcb0991SDimitry Andric 
4718bcb0991SDimitry Andric   allocSecHdrTable();
4728bcb0991SDimitry Andric   return sampleprof_error::success;
4738bcb0991SDimitry Andric }
4748bcb0991SDimitry Andric 
475*0b57cec5SDimitry Andric std::error_code SampleProfileWriterCompactBinary::writeHeader(
476*0b57cec5SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
477*0b57cec5SDimitry Andric   support::endian::Writer Writer(*OutputStream, support::little);
478*0b57cec5SDimitry Andric   if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap))
479*0b57cec5SDimitry Andric     return EC;
480*0b57cec5SDimitry Andric 
481*0b57cec5SDimitry Andric   // Reserve a slot for the offset of function offset table. The slot will
482*0b57cec5SDimitry Andric   // be populated with the offset of FuncOffsetTable later.
483*0b57cec5SDimitry Andric   TableOffset = OutputStream->tell();
484*0b57cec5SDimitry Andric   Writer.write(static_cast<uint64_t>(-2));
485*0b57cec5SDimitry Andric   return sampleprof_error::success;
486*0b57cec5SDimitry Andric }
487*0b57cec5SDimitry Andric 
488*0b57cec5SDimitry Andric std::error_code SampleProfileWriterBinary::writeSummary() {
489*0b57cec5SDimitry Andric   auto &OS = *OutputStream;
490*0b57cec5SDimitry Andric   encodeULEB128(Summary->getTotalCount(), OS);
491*0b57cec5SDimitry Andric   encodeULEB128(Summary->getMaxCount(), OS);
492*0b57cec5SDimitry Andric   encodeULEB128(Summary->getMaxFunctionCount(), OS);
493*0b57cec5SDimitry Andric   encodeULEB128(Summary->getNumCounts(), OS);
494*0b57cec5SDimitry Andric   encodeULEB128(Summary->getNumFunctions(), OS);
495*0b57cec5SDimitry Andric   std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary();
496*0b57cec5SDimitry Andric   encodeULEB128(Entries.size(), OS);
497*0b57cec5SDimitry Andric   for (auto Entry : Entries) {
498*0b57cec5SDimitry Andric     encodeULEB128(Entry.Cutoff, OS);
499*0b57cec5SDimitry Andric     encodeULEB128(Entry.MinCount, OS);
500*0b57cec5SDimitry Andric     encodeULEB128(Entry.NumCounts, OS);
501*0b57cec5SDimitry Andric   }
502*0b57cec5SDimitry Andric   return sampleprof_error::success;
503*0b57cec5SDimitry Andric }
504*0b57cec5SDimitry Andric std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
505*0b57cec5SDimitry Andric   auto &OS = *OutputStream;
506*0b57cec5SDimitry Andric 
507*0b57cec5SDimitry Andric   if (std::error_code EC = writeNameIdx(S.getName()))
508*0b57cec5SDimitry Andric     return EC;
509*0b57cec5SDimitry Andric 
510*0b57cec5SDimitry Andric   encodeULEB128(S.getTotalSamples(), OS);
511*0b57cec5SDimitry Andric 
512*0b57cec5SDimitry Andric   // Emit all the body samples.
513*0b57cec5SDimitry Andric   encodeULEB128(S.getBodySamples().size(), OS);
514*0b57cec5SDimitry Andric   for (const auto &I : S.getBodySamples()) {
515*0b57cec5SDimitry Andric     LineLocation Loc = I.first;
516*0b57cec5SDimitry Andric     const SampleRecord &Sample = I.second;
517*0b57cec5SDimitry Andric     encodeULEB128(Loc.LineOffset, OS);
518*0b57cec5SDimitry Andric     encodeULEB128(Loc.Discriminator, OS);
519*0b57cec5SDimitry Andric     encodeULEB128(Sample.getSamples(), OS);
520*0b57cec5SDimitry Andric     encodeULEB128(Sample.getCallTargets().size(), OS);
5218bcb0991SDimitry Andric     for (const auto &J : Sample.getSortedCallTargets()) {
5228bcb0991SDimitry Andric       StringRef Callee = J.first;
523*0b57cec5SDimitry Andric       uint64_t CalleeSamples = J.second;
524*0b57cec5SDimitry Andric       if (std::error_code EC = writeNameIdx(Callee))
525*0b57cec5SDimitry Andric         return EC;
526*0b57cec5SDimitry Andric       encodeULEB128(CalleeSamples, OS);
527*0b57cec5SDimitry Andric     }
528*0b57cec5SDimitry Andric   }
529*0b57cec5SDimitry Andric 
530*0b57cec5SDimitry Andric   // Recursively emit all the callsite samples.
531*0b57cec5SDimitry Andric   uint64_t NumCallsites = 0;
532*0b57cec5SDimitry Andric   for (const auto &J : S.getCallsiteSamples())
533*0b57cec5SDimitry Andric     NumCallsites += J.second.size();
534*0b57cec5SDimitry Andric   encodeULEB128(NumCallsites, OS);
535*0b57cec5SDimitry Andric   for (const auto &J : S.getCallsiteSamples())
536*0b57cec5SDimitry Andric     for (const auto &FS : J.second) {
537*0b57cec5SDimitry Andric       LineLocation Loc = J.first;
538*0b57cec5SDimitry Andric       const FunctionSamples &CalleeSamples = FS.second;
539*0b57cec5SDimitry Andric       encodeULEB128(Loc.LineOffset, OS);
540*0b57cec5SDimitry Andric       encodeULEB128(Loc.Discriminator, OS);
541*0b57cec5SDimitry Andric       if (std::error_code EC = writeBody(CalleeSamples))
542*0b57cec5SDimitry Andric         return EC;
543*0b57cec5SDimitry Andric     }
544*0b57cec5SDimitry Andric 
545*0b57cec5SDimitry Andric   return sampleprof_error::success;
546*0b57cec5SDimitry Andric }
547*0b57cec5SDimitry Andric 
548*0b57cec5SDimitry Andric /// Write samples of a top-level function to a binary file.
549*0b57cec5SDimitry Andric ///
550*0b57cec5SDimitry Andric /// \returns true if the samples were written successfully, false otherwise.
5518bcb0991SDimitry Andric std::error_code
5528bcb0991SDimitry Andric SampleProfileWriterBinary::writeSample(const FunctionSamples &S) {
553*0b57cec5SDimitry Andric   encodeULEB128(S.getHeadSamples(), *OutputStream);
554*0b57cec5SDimitry Andric   return writeBody(S);
555*0b57cec5SDimitry Andric }
556*0b57cec5SDimitry Andric 
557*0b57cec5SDimitry Andric std::error_code
5588bcb0991SDimitry Andric SampleProfileWriterCompactBinary::writeSample(const FunctionSamples &S) {
559*0b57cec5SDimitry Andric   uint64_t Offset = OutputStream->tell();
560*0b57cec5SDimitry Andric   StringRef Name = S.getName();
561*0b57cec5SDimitry Andric   FuncOffsetTable[Name] = Offset;
562*0b57cec5SDimitry Andric   encodeULEB128(S.getHeadSamples(), *OutputStream);
563*0b57cec5SDimitry Andric   return writeBody(S);
564*0b57cec5SDimitry Andric }
565*0b57cec5SDimitry Andric 
566*0b57cec5SDimitry Andric /// Create a sample profile file writer based on the specified format.
567*0b57cec5SDimitry Andric ///
568*0b57cec5SDimitry Andric /// \param Filename The file to create.
569*0b57cec5SDimitry Andric ///
570*0b57cec5SDimitry Andric /// \param Format Encoding format for the profile file.
571*0b57cec5SDimitry Andric ///
572*0b57cec5SDimitry Andric /// \returns an error code indicating the status of the created writer.
573*0b57cec5SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileWriter>>
574*0b57cec5SDimitry Andric SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
575*0b57cec5SDimitry Andric   std::error_code EC;
576*0b57cec5SDimitry Andric   std::unique_ptr<raw_ostream> OS;
5778bcb0991SDimitry Andric   if (Format == SPF_Binary || Format == SPF_Ext_Binary ||
5788bcb0991SDimitry Andric       Format == SPF_Compact_Binary)
5798bcb0991SDimitry Andric     OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None));
580*0b57cec5SDimitry Andric   else
5818bcb0991SDimitry Andric     OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_Text));
582*0b57cec5SDimitry Andric   if (EC)
583*0b57cec5SDimitry Andric     return EC;
584*0b57cec5SDimitry Andric 
585*0b57cec5SDimitry Andric   return create(OS, Format);
586*0b57cec5SDimitry Andric }
587*0b57cec5SDimitry Andric 
588*0b57cec5SDimitry Andric /// Create a sample profile stream writer based on the specified format.
589*0b57cec5SDimitry Andric ///
590*0b57cec5SDimitry Andric /// \param OS The output stream to store the profile data to.
591*0b57cec5SDimitry Andric ///
592*0b57cec5SDimitry Andric /// \param Format Encoding format for the profile file.
593*0b57cec5SDimitry Andric ///
594*0b57cec5SDimitry Andric /// \returns an error code indicating the status of the created writer.
595*0b57cec5SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileWriter>>
596*0b57cec5SDimitry Andric SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
597*0b57cec5SDimitry Andric                             SampleProfileFormat Format) {
598*0b57cec5SDimitry Andric   std::error_code EC;
599*0b57cec5SDimitry Andric   std::unique_ptr<SampleProfileWriter> Writer;
600*0b57cec5SDimitry Andric 
601*0b57cec5SDimitry Andric   if (Format == SPF_Binary)
602*0b57cec5SDimitry Andric     Writer.reset(new SampleProfileWriterRawBinary(OS));
6038bcb0991SDimitry Andric   else if (Format == SPF_Ext_Binary)
6048bcb0991SDimitry Andric     Writer.reset(new SampleProfileWriterExtBinary(OS));
605*0b57cec5SDimitry Andric   else if (Format == SPF_Compact_Binary)
606*0b57cec5SDimitry Andric     Writer.reset(new SampleProfileWriterCompactBinary(OS));
607*0b57cec5SDimitry Andric   else if (Format == SPF_Text)
608*0b57cec5SDimitry Andric     Writer.reset(new SampleProfileWriterText(OS));
609*0b57cec5SDimitry Andric   else if (Format == SPF_GCC)
610*0b57cec5SDimitry Andric     EC = sampleprof_error::unsupported_writing_format;
611*0b57cec5SDimitry Andric   else
612*0b57cec5SDimitry Andric     EC = sampleprof_error::unrecognized_format;
613*0b57cec5SDimitry Andric 
614*0b57cec5SDimitry Andric   if (EC)
615*0b57cec5SDimitry Andric     return EC;
616*0b57cec5SDimitry Andric 
6178bcb0991SDimitry Andric   Writer->Format = Format;
618*0b57cec5SDimitry Andric   return std::move(Writer);
619*0b57cec5SDimitry Andric }
620*0b57cec5SDimitry Andric 
621*0b57cec5SDimitry Andric void SampleProfileWriter::computeSummary(
622*0b57cec5SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
623*0b57cec5SDimitry Andric   SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
624*0b57cec5SDimitry Andric   for (const auto &I : ProfileMap) {
625*0b57cec5SDimitry Andric     const FunctionSamples &Profile = I.second;
626*0b57cec5SDimitry Andric     Builder.addRecord(Profile);
627*0b57cec5SDimitry Andric   }
628*0b57cec5SDimitry Andric   Summary = Builder.getSummary();
629*0b57cec5SDimitry Andric }
630