139d628a0SDimitry Andric //===- SampleProfWriter.cpp - Write LLVM sample profile data --------------===//
239d628a0SDimitry Andric //
339d628a0SDimitry Andric //                      The LLVM Compiler Infrastructure
439d628a0SDimitry Andric //
539d628a0SDimitry Andric // This file is distributed under the University of Illinois Open Source
639d628a0SDimitry Andric // License. See LICENSE.TXT for details.
739d628a0SDimitry Andric //
839d628a0SDimitry Andric //===----------------------------------------------------------------------===//
939d628a0SDimitry Andric //
1039d628a0SDimitry Andric // This file implements the class that writes LLVM sample profiles. It
1139d628a0SDimitry Andric // supports two file formats: text and binary. The textual representation
1239d628a0SDimitry Andric // is useful for debugging and testing purposes. The binary representation
1339d628a0SDimitry Andric // is more compact, resulting in smaller file sizes. However, they can
1439d628a0SDimitry Andric // both be used interchangeably.
1539d628a0SDimitry Andric //
1639d628a0SDimitry Andric // See lib/ProfileData/SampleProfReader.cpp for documentation on each of the
1739d628a0SDimitry Andric // supported formats.
1839d628a0SDimitry Andric //
1939d628a0SDimitry Andric //===----------------------------------------------------------------------===//
2039d628a0SDimitry Andric 
21db17bf38SDimitry Andric #include "llvm/ProfileData/SampleProfWriter.h"
227a7e6055SDimitry Andric #include "llvm/ADT/StringRef.h"
237a7e6055SDimitry Andric #include "llvm/ProfileData/ProfileCommon.h"
247a7e6055SDimitry Andric #include "llvm/ProfileData/SampleProf.h"
25*b5893f02SDimitry Andric #include "llvm/Support/Endian.h"
26*b5893f02SDimitry Andric #include "llvm/Support/EndianStream.h"
2739d628a0SDimitry Andric #include "llvm/Support/ErrorOr.h"
287a7e6055SDimitry Andric #include "llvm/Support/FileSystem.h"
2939d628a0SDimitry Andric #include "llvm/Support/LEB128.h"
304ba319b5SDimitry Andric #include "llvm/Support/MD5.h"
317a7e6055SDimitry Andric #include "llvm/Support/raw_ostream.h"
327a7e6055SDimitry Andric #include <algorithm>
337a7e6055SDimitry Andric #include <cstdint>
347a7e6055SDimitry Andric #include <memory>
355517e702SDimitry Andric #include <set>
367a7e6055SDimitry Andric #include <system_error>
377a7e6055SDimitry Andric #include <utility>
387a7e6055SDimitry Andric #include <vector>
3939d628a0SDimitry Andric 
4039d628a0SDimitry Andric using namespace llvm;
417a7e6055SDimitry Andric using namespace sampleprof;
4239d628a0SDimitry Andric 
435517e702SDimitry Andric std::error_code
write(const StringMap<FunctionSamples> & ProfileMap)445517e702SDimitry Andric SampleProfileWriter::write(const StringMap<FunctionSamples> &ProfileMap) {
455517e702SDimitry Andric   if (std::error_code EC = writeHeader(ProfileMap))
465517e702SDimitry Andric     return EC;
475517e702SDimitry Andric 
485517e702SDimitry Andric   // Sort the ProfileMap by total samples.
495517e702SDimitry Andric   typedef std::pair<StringRef, const FunctionSamples *> NameFunctionSamples;
505517e702SDimitry Andric   std::vector<NameFunctionSamples> V;
515517e702SDimitry Andric   for (const auto &I : ProfileMap)
525517e702SDimitry Andric     V.push_back(std::make_pair(I.getKey(), &I.second));
535517e702SDimitry Andric 
545517e702SDimitry Andric   std::stable_sort(
555517e702SDimitry Andric       V.begin(), V.end(),
565517e702SDimitry Andric       [](const NameFunctionSamples &A, const NameFunctionSamples &B) {
575517e702SDimitry Andric         if (A.second->getTotalSamples() == B.second->getTotalSamples())
585517e702SDimitry Andric           return A.first > B.first;
595517e702SDimitry Andric         return A.second->getTotalSamples() > B.second->getTotalSamples();
605517e702SDimitry Andric       });
615517e702SDimitry Andric 
625517e702SDimitry Andric   for (const auto &I : V) {
635517e702SDimitry Andric     if (std::error_code EC = write(*I.second))
645517e702SDimitry Andric       return EC;
655517e702SDimitry Andric   }
665517e702SDimitry Andric   return sampleprof_error::success;
675517e702SDimitry Andric }
685517e702SDimitry Andric 
write(const StringMap<FunctionSamples> & ProfileMap)69*b5893f02SDimitry Andric std::error_code SampleProfileWriterCompactBinary::write(
70*b5893f02SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
71*b5893f02SDimitry Andric   if (std::error_code EC = SampleProfileWriter::write(ProfileMap))
72*b5893f02SDimitry Andric     return EC;
73*b5893f02SDimitry Andric   if (std::error_code EC = writeFuncOffsetTable())
74*b5893f02SDimitry Andric     return EC;
75*b5893f02SDimitry Andric   return sampleprof_error::success;
76*b5893f02SDimitry Andric }
77*b5893f02SDimitry Andric 
784ba319b5SDimitry Andric /// Write samples to a text file.
797d523365SDimitry Andric ///
807d523365SDimitry Andric /// Note: it may be tempting to implement this in terms of
817d523365SDimitry Andric /// FunctionSamples::print().  Please don't.  The dump functionality is intended
827d523365SDimitry Andric /// for debugging and has no specified form.
837d523365SDimitry Andric ///
847d523365SDimitry Andric /// The format used here is more structured and deliberate because
857d523365SDimitry Andric /// it needs to be parsed by the SampleProfileReaderText class.
write(const FunctionSamples & S)863ca95b02SDimitry Andric std::error_code SampleProfileWriterText::write(const FunctionSamples &S) {
877d523365SDimitry Andric   auto &OS = *OutputStream;
883ca95b02SDimitry Andric   OS << S.getName() << ":" << S.getTotalSamples();
897d523365SDimitry Andric   if (Indent == 0)
907d523365SDimitry Andric     OS << ":" << S.getHeadSamples();
917d523365SDimitry Andric   OS << "\n";
9239d628a0SDimitry Andric 
937d523365SDimitry Andric   SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples());
947d523365SDimitry Andric   for (const auto &I : SortedSamples.get()) {
957d523365SDimitry Andric     LineLocation Loc = I->first;
967d523365SDimitry Andric     const SampleRecord &Sample = I->second;
977d523365SDimitry Andric     OS.indent(Indent + 1);
9839d628a0SDimitry Andric     if (Loc.Discriminator == 0)
9939d628a0SDimitry Andric       OS << Loc.LineOffset << ": ";
10039d628a0SDimitry Andric     else
10139d628a0SDimitry Andric       OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
10239d628a0SDimitry Andric 
10339d628a0SDimitry Andric     OS << Sample.getSamples();
10439d628a0SDimitry Andric 
10539d628a0SDimitry Andric     for (const auto &J : Sample.getCallTargets())
10639d628a0SDimitry Andric       OS << " " << J.first() << ":" << J.second;
10739d628a0SDimitry Andric     OS << "\n";
10839d628a0SDimitry Andric   }
10939d628a0SDimitry Andric 
1107a7e6055SDimitry Andric   SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples(
1117d523365SDimitry Andric       S.getCallsiteSamples());
1127d523365SDimitry Andric   Indent += 1;
1137a7e6055SDimitry Andric   for (const auto &I : SortedCallsiteSamples.get())
1147a7e6055SDimitry Andric     for (const auto &FS : I->second) {
1153ca95b02SDimitry Andric       LineLocation Loc = I->first;
1167a7e6055SDimitry Andric       const FunctionSamples &CalleeSamples = FS.second;
1177d523365SDimitry Andric       OS.indent(Indent);
1187d523365SDimitry Andric       if (Loc.Discriminator == 0)
1197d523365SDimitry Andric         OS << Loc.LineOffset << ": ";
1207d523365SDimitry Andric       else
1217d523365SDimitry Andric         OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
1223ca95b02SDimitry Andric       if (std::error_code EC = write(CalleeSamples))
1237d523365SDimitry Andric         return EC;
1247d523365SDimitry Andric     }
1257d523365SDimitry Andric   Indent -= 1;
1267d523365SDimitry Andric 
1277d523365SDimitry Andric   return sampleprof_error::success;
12839d628a0SDimitry Andric }
12939d628a0SDimitry Andric 
writeNameIdx(StringRef FName)1307d523365SDimitry Andric std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) {
1317d523365SDimitry Andric   const auto &ret = NameTable.find(FName);
1327d523365SDimitry Andric   if (ret == NameTable.end())
1337d523365SDimitry Andric     return sampleprof_error::truncated_name_table;
1347d523365SDimitry Andric   encodeULEB128(ret->second, *OutputStream);
1357d523365SDimitry Andric   return sampleprof_error::success;
1367d523365SDimitry Andric }
13739d628a0SDimitry Andric 
addName(StringRef FName)1387d523365SDimitry Andric void SampleProfileWriterBinary::addName(StringRef FName) {
1395517e702SDimitry Andric   NameTable.insert(std::make_pair(FName, 0));
1407d523365SDimitry Andric }
1417d523365SDimitry Andric 
addNames(const FunctionSamples & S)1427d523365SDimitry Andric void SampleProfileWriterBinary::addNames(const FunctionSamples &S) {
1437d523365SDimitry Andric   // Add all the names in indirect call targets.
1447d523365SDimitry Andric   for (const auto &I : S.getBodySamples()) {
1457d523365SDimitry Andric     const SampleRecord &Sample = I.second;
1467d523365SDimitry Andric     for (const auto &J : Sample.getCallTargets())
1477d523365SDimitry Andric       addName(J.first());
1487d523365SDimitry Andric   }
1497d523365SDimitry Andric 
1507d523365SDimitry Andric   // Recursively add all the names for inlined callsites.
1517a7e6055SDimitry Andric   for (const auto &J : S.getCallsiteSamples())
1527a7e6055SDimitry Andric     for (const auto &FS : J.second) {
1537a7e6055SDimitry Andric       const FunctionSamples &CalleeSamples = FS.second;
1543ca95b02SDimitry Andric       addName(CalleeSamples.getName());
1557d523365SDimitry Andric       addNames(CalleeSamples);
1567d523365SDimitry Andric     }
1577d523365SDimitry Andric }
1587d523365SDimitry Andric 
stablizeNameTable(std::set<StringRef> & V)1594ba319b5SDimitry Andric void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) {
1604ba319b5SDimitry Andric   // Sort the names to make NameTable deterministic.
1614ba319b5SDimitry Andric   for (const auto &I : NameTable)
1624ba319b5SDimitry Andric     V.insert(I.first);
1634ba319b5SDimitry Andric   int i = 0;
1644ba319b5SDimitry Andric   for (const StringRef &N : V)
1654ba319b5SDimitry Andric     NameTable[N] = i++;
1664ba319b5SDimitry Andric }
1677d523365SDimitry Andric 
writeNameTable()1684ba319b5SDimitry Andric std::error_code SampleProfileWriterRawBinary::writeNameTable() {
1694ba319b5SDimitry Andric   auto &OS = *OutputStream;
1704ba319b5SDimitry Andric   std::set<StringRef> V;
1714ba319b5SDimitry Andric   stablizeNameTable(V);
1724ba319b5SDimitry Andric 
1734ba319b5SDimitry Andric   // Write out the name table.
1744ba319b5SDimitry Andric   encodeULEB128(NameTable.size(), OS);
1754ba319b5SDimitry Andric   for (auto N : V) {
1764ba319b5SDimitry Andric     OS << N;
1774ba319b5SDimitry Andric     encodeULEB128(0, OS);
1784ba319b5SDimitry Andric   }
1794ba319b5SDimitry Andric   return sampleprof_error::success;
1804ba319b5SDimitry Andric }
1814ba319b5SDimitry Andric 
writeFuncOffsetTable()182*b5893f02SDimitry Andric std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() {
183*b5893f02SDimitry Andric   auto &OS = *OutputStream;
184*b5893f02SDimitry Andric 
185*b5893f02SDimitry Andric   // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable.
186*b5893f02SDimitry Andric   auto &OFS = static_cast<raw_fd_ostream &>(OS);
187*b5893f02SDimitry Andric   uint64_t FuncOffsetTableStart = OS.tell();
188*b5893f02SDimitry Andric   if (OFS.seek(TableOffset) == (uint64_t)-1)
189*b5893f02SDimitry Andric     return sampleprof_error::ostream_seek_unsupported;
190*b5893f02SDimitry Andric   support::endian::Writer Writer(*OutputStream, support::little);
191*b5893f02SDimitry Andric   Writer.write(FuncOffsetTableStart);
192*b5893f02SDimitry Andric   if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1)
193*b5893f02SDimitry Andric     return sampleprof_error::ostream_seek_unsupported;
194*b5893f02SDimitry Andric 
195*b5893f02SDimitry Andric   // Write out the table size.
196*b5893f02SDimitry Andric   encodeULEB128(FuncOffsetTable.size(), OS);
197*b5893f02SDimitry Andric 
198*b5893f02SDimitry Andric   // Write out FuncOffsetTable.
199*b5893f02SDimitry Andric   for (auto entry : FuncOffsetTable) {
200*b5893f02SDimitry Andric     writeNameIdx(entry.first);
201*b5893f02SDimitry Andric     encodeULEB128(entry.second, OS);
202*b5893f02SDimitry Andric   }
203*b5893f02SDimitry Andric   return sampleprof_error::success;
204*b5893f02SDimitry Andric }
205*b5893f02SDimitry Andric 
writeNameTable()2064ba319b5SDimitry Andric std::error_code SampleProfileWriterCompactBinary::writeNameTable() {
2074ba319b5SDimitry Andric   auto &OS = *OutputStream;
2084ba319b5SDimitry Andric   std::set<StringRef> V;
2094ba319b5SDimitry Andric   stablizeNameTable(V);
2104ba319b5SDimitry Andric 
2114ba319b5SDimitry Andric   // Write out the name table.
2124ba319b5SDimitry Andric   encodeULEB128(NameTable.size(), OS);
2134ba319b5SDimitry Andric   for (auto N : V) {
2144ba319b5SDimitry Andric     encodeULEB128(MD5Hash(N), OS);
2154ba319b5SDimitry Andric   }
2164ba319b5SDimitry Andric   return sampleprof_error::success;
2174ba319b5SDimitry Andric }
2184ba319b5SDimitry Andric 
writeMagicIdent()2194ba319b5SDimitry Andric std::error_code SampleProfileWriterRawBinary::writeMagicIdent() {
2204ba319b5SDimitry Andric   auto &OS = *OutputStream;
2217d523365SDimitry Andric   // Write file magic identifier.
22239d628a0SDimitry Andric   encodeULEB128(SPMagic(), OS);
22339d628a0SDimitry Andric   encodeULEB128(SPVersion(), OS);
2244ba319b5SDimitry Andric   return sampleprof_error::success;
2254ba319b5SDimitry Andric }
2264ba319b5SDimitry Andric 
writeMagicIdent()2274ba319b5SDimitry Andric std::error_code SampleProfileWriterCompactBinary::writeMagicIdent() {
2284ba319b5SDimitry Andric   auto &OS = *OutputStream;
2294ba319b5SDimitry Andric   // Write file magic identifier.
2304ba319b5SDimitry Andric   encodeULEB128(SPMagic(SPF_Compact_Binary), OS);
2314ba319b5SDimitry Andric   encodeULEB128(SPVersion(), OS);
2324ba319b5SDimitry Andric   return sampleprof_error::success;
2334ba319b5SDimitry Andric }
2344ba319b5SDimitry Andric 
writeHeader(const StringMap<FunctionSamples> & ProfileMap)2354ba319b5SDimitry Andric std::error_code SampleProfileWriterBinary::writeHeader(
2364ba319b5SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
2374ba319b5SDimitry Andric   writeMagicIdent();
2387d523365SDimitry Andric 
2393ca95b02SDimitry Andric   computeSummary(ProfileMap);
2403ca95b02SDimitry Andric   if (auto EC = writeSummary())
2413ca95b02SDimitry Andric     return EC;
2423ca95b02SDimitry Andric 
2437d523365SDimitry Andric   // Generate the name table for all the functions referenced in the profile.
2447d523365SDimitry Andric   for (const auto &I : ProfileMap) {
2457d523365SDimitry Andric     addName(I.first());
2467d523365SDimitry Andric     addNames(I.second);
24739d628a0SDimitry Andric   }
24839d628a0SDimitry Andric 
2494ba319b5SDimitry Andric   writeNameTable();
2507d523365SDimitry Andric   return sampleprof_error::success;
2517d523365SDimitry Andric }
2527d523365SDimitry Andric 
writeHeader(const StringMap<FunctionSamples> & ProfileMap)253*b5893f02SDimitry Andric std::error_code SampleProfileWriterCompactBinary::writeHeader(
254*b5893f02SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
255*b5893f02SDimitry Andric   support::endian::Writer Writer(*OutputStream, support::little);
256*b5893f02SDimitry Andric   if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap))
257*b5893f02SDimitry Andric     return EC;
258*b5893f02SDimitry Andric 
259*b5893f02SDimitry Andric   // Reserve a slot for the offset of function offset table. The slot will
260*b5893f02SDimitry Andric   // be populated with the offset of FuncOffsetTable later.
261*b5893f02SDimitry Andric   TableOffset = OutputStream->tell();
262*b5893f02SDimitry Andric   Writer.write(static_cast<uint64_t>(-2));
263*b5893f02SDimitry Andric   return sampleprof_error::success;
264*b5893f02SDimitry Andric }
265*b5893f02SDimitry Andric 
writeSummary()2663ca95b02SDimitry Andric std::error_code SampleProfileWriterBinary::writeSummary() {
2673ca95b02SDimitry Andric   auto &OS = *OutputStream;
2683ca95b02SDimitry Andric   encodeULEB128(Summary->getTotalCount(), OS);
2693ca95b02SDimitry Andric   encodeULEB128(Summary->getMaxCount(), OS);
2703ca95b02SDimitry Andric   encodeULEB128(Summary->getMaxFunctionCount(), OS);
2713ca95b02SDimitry Andric   encodeULEB128(Summary->getNumCounts(), OS);
2723ca95b02SDimitry Andric   encodeULEB128(Summary->getNumFunctions(), OS);
2733ca95b02SDimitry Andric   std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary();
2743ca95b02SDimitry Andric   encodeULEB128(Entries.size(), OS);
2753ca95b02SDimitry Andric   for (auto Entry : Entries) {
2763ca95b02SDimitry Andric     encodeULEB128(Entry.Cutoff, OS);
2773ca95b02SDimitry Andric     encodeULEB128(Entry.MinCount, OS);
2783ca95b02SDimitry Andric     encodeULEB128(Entry.NumCounts, OS);
2793ca95b02SDimitry Andric   }
2803ca95b02SDimitry Andric   return sampleprof_error::success;
2813ca95b02SDimitry Andric }
writeBody(const FunctionSamples & S)2823ca95b02SDimitry Andric std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
2837d523365SDimitry Andric   auto &OS = *OutputStream;
2847d523365SDimitry Andric 
2853ca95b02SDimitry Andric   if (std::error_code EC = writeNameIdx(S.getName()))
2867d523365SDimitry Andric     return EC;
2877d523365SDimitry Andric 
28839d628a0SDimitry Andric   encodeULEB128(S.getTotalSamples(), OS);
2897d523365SDimitry Andric 
2907d523365SDimitry Andric   // Emit all the body samples.
29139d628a0SDimitry Andric   encodeULEB128(S.getBodySamples().size(), OS);
29239d628a0SDimitry Andric   for (const auto &I : S.getBodySamples()) {
29339d628a0SDimitry Andric     LineLocation Loc = I.first;
29439d628a0SDimitry Andric     const SampleRecord &Sample = I.second;
29539d628a0SDimitry Andric     encodeULEB128(Loc.LineOffset, OS);
29639d628a0SDimitry Andric     encodeULEB128(Loc.Discriminator, OS);
29739d628a0SDimitry Andric     encodeULEB128(Sample.getSamples(), OS);
29839d628a0SDimitry Andric     encodeULEB128(Sample.getCallTargets().size(), OS);
29939d628a0SDimitry Andric     for (const auto &J : Sample.getCallTargets()) {
3007d523365SDimitry Andric       StringRef Callee = J.first();
3017d523365SDimitry Andric       uint64_t CalleeSamples = J.second;
3027d523365SDimitry Andric       if (std::error_code EC = writeNameIdx(Callee))
3037d523365SDimitry Andric         return EC;
30439d628a0SDimitry Andric       encodeULEB128(CalleeSamples, OS);
30539d628a0SDimitry Andric     }
30639d628a0SDimitry Andric   }
30739d628a0SDimitry Andric 
3087d523365SDimitry Andric   // Recursively emit all the callsite samples.
3092cab237bSDimitry Andric   uint64_t NumCallsites = 0;
3102cab237bSDimitry Andric   for (const auto &J : S.getCallsiteSamples())
3112cab237bSDimitry Andric     NumCallsites += J.second.size();
3122cab237bSDimitry Andric   encodeULEB128(NumCallsites, OS);
3137a7e6055SDimitry Andric   for (const auto &J : S.getCallsiteSamples())
3147a7e6055SDimitry Andric     for (const auto &FS : J.second) {
3153ca95b02SDimitry Andric       LineLocation Loc = J.first;
3167a7e6055SDimitry Andric       const FunctionSamples &CalleeSamples = FS.second;
3177d523365SDimitry Andric       encodeULEB128(Loc.LineOffset, OS);
3187d523365SDimitry Andric       encodeULEB128(Loc.Discriminator, OS);
3193ca95b02SDimitry Andric       if (std::error_code EC = writeBody(CalleeSamples))
3207d523365SDimitry Andric         return EC;
32139d628a0SDimitry Andric     }
32239d628a0SDimitry Andric 
3237d523365SDimitry Andric   return sampleprof_error::success;
3247d523365SDimitry Andric }
3257d523365SDimitry Andric 
3264ba319b5SDimitry Andric /// Write samples of a top-level function to a binary file.
3277d523365SDimitry Andric ///
3287d523365SDimitry Andric /// \returns true if the samples were written successfully, false otherwise.
write(const FunctionSamples & S)3293ca95b02SDimitry Andric std::error_code SampleProfileWriterBinary::write(const FunctionSamples &S) {
3307d523365SDimitry Andric   encodeULEB128(S.getHeadSamples(), *OutputStream);
3313ca95b02SDimitry Andric   return writeBody(S);
3327d523365SDimitry Andric }
3337d523365SDimitry Andric 
334*b5893f02SDimitry Andric std::error_code
write(const FunctionSamples & S)335*b5893f02SDimitry Andric SampleProfileWriterCompactBinary::write(const FunctionSamples &S) {
336*b5893f02SDimitry Andric   uint64_t Offset = OutputStream->tell();
337*b5893f02SDimitry Andric   StringRef Name = S.getName();
338*b5893f02SDimitry Andric   FuncOffsetTable[Name] = Offset;
339*b5893f02SDimitry Andric   encodeULEB128(S.getHeadSamples(), *OutputStream);
340*b5893f02SDimitry Andric   return writeBody(S);
341*b5893f02SDimitry Andric }
342*b5893f02SDimitry Andric 
3434ba319b5SDimitry Andric /// Create a sample profile file writer based on the specified format.
34439d628a0SDimitry Andric ///
34539d628a0SDimitry Andric /// \param Filename The file to create.
34639d628a0SDimitry Andric ///
34739d628a0SDimitry Andric /// \param Format Encoding format for the profile file.
34839d628a0SDimitry Andric ///
34939d628a0SDimitry Andric /// \returns an error code indicating the status of the created writer.
35039d628a0SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileWriter>>
create(StringRef Filename,SampleProfileFormat Format)35139d628a0SDimitry Andric SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
35239d628a0SDimitry Andric   std::error_code EC;
3537d523365SDimitry Andric   std::unique_ptr<raw_ostream> OS;
3544ba319b5SDimitry Andric   if (Format == SPF_Binary || Format == SPF_Compact_Binary)
3557d523365SDimitry Andric     OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::F_None));
3567d523365SDimitry Andric   else
3577d523365SDimitry Andric     OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::F_Text));
3587d523365SDimitry Andric   if (EC)
3597d523365SDimitry Andric     return EC;
3607d523365SDimitry Andric 
3617d523365SDimitry Andric   return create(OS, Format);
3627d523365SDimitry Andric }
3637d523365SDimitry Andric 
3644ba319b5SDimitry Andric /// Create a sample profile stream writer based on the specified format.
3657d523365SDimitry Andric ///
3667d523365SDimitry Andric /// \param OS The output stream to store the profile data to.
3677d523365SDimitry Andric ///
3687d523365SDimitry Andric /// \param Format Encoding format for the profile file.
3697d523365SDimitry Andric ///
3707d523365SDimitry Andric /// \returns an error code indicating the status of the created writer.
3717d523365SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileWriter>>
create(std::unique_ptr<raw_ostream> & OS,SampleProfileFormat Format)3727d523365SDimitry Andric SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
3737d523365SDimitry Andric                             SampleProfileFormat Format) {
3747d523365SDimitry Andric   std::error_code EC;
37539d628a0SDimitry Andric   std::unique_ptr<SampleProfileWriter> Writer;
37639d628a0SDimitry Andric 
37739d628a0SDimitry Andric   if (Format == SPF_Binary)
3784ba319b5SDimitry Andric     Writer.reset(new SampleProfileWriterRawBinary(OS));
3794ba319b5SDimitry Andric   else if (Format == SPF_Compact_Binary)
3804ba319b5SDimitry Andric     Writer.reset(new SampleProfileWriterCompactBinary(OS));
38139d628a0SDimitry Andric   else if (Format == SPF_Text)
3827d523365SDimitry Andric     Writer.reset(new SampleProfileWriterText(OS));
3837d523365SDimitry Andric   else if (Format == SPF_GCC)
3847d523365SDimitry Andric     EC = sampleprof_error::unsupported_writing_format;
38539d628a0SDimitry Andric   else
38639d628a0SDimitry Andric     EC = sampleprof_error::unrecognized_format;
38739d628a0SDimitry Andric 
38839d628a0SDimitry Andric   if (EC)
38939d628a0SDimitry Andric     return EC;
39039d628a0SDimitry Andric 
39139d628a0SDimitry Andric   return std::move(Writer);
39239d628a0SDimitry Andric }
3933ca95b02SDimitry Andric 
computeSummary(const StringMap<FunctionSamples> & ProfileMap)3943ca95b02SDimitry Andric void SampleProfileWriter::computeSummary(
3953ca95b02SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
3963ca95b02SDimitry Andric   SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
3973ca95b02SDimitry Andric   for (const auto &I : ProfileMap) {
3983ca95b02SDimitry Andric     const FunctionSamples &Profile = I.second;
3993ca95b02SDimitry Andric     Builder.addRecord(Profile);
4003ca95b02SDimitry Andric   }
4013ca95b02SDimitry Andric   Summary = Builder.getSummary();
4023ca95b02SDimitry Andric }
403