1c572e92cSDiego Novillo //===- SampleProfWriter.cpp - Write LLVM sample profile data --------------===//
2c572e92cSDiego Novillo //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c572e92cSDiego Novillo //
7c572e92cSDiego Novillo //===----------------------------------------------------------------------===//
8c572e92cSDiego Novillo //
9c572e92cSDiego Novillo // This file implements the class that writes LLVM sample profiles. It
10c572e92cSDiego Novillo // supports two file formats: text and binary. The textual representation
11c572e92cSDiego Novillo // is useful for debugging and testing purposes. The binary representation
12c572e92cSDiego Novillo // is more compact, resulting in smaller file sizes. However, they can
13c572e92cSDiego Novillo // both be used interchangeably.
14c572e92cSDiego Novillo //
15c572e92cSDiego Novillo // See lib/ProfileData/SampleProfReader.cpp for documentation on each of the
16c572e92cSDiego Novillo // supported formats.
17c572e92cSDiego Novillo //
18c572e92cSDiego Novillo //===----------------------------------------------------------------------===//
19c572e92cSDiego Novillo 
206bda14b3SChandler Carruth #include "llvm/ProfileData/SampleProfWriter.h"
21e78d131aSEugene Zelenko #include "llvm/ADT/StringRef.h"
22e78d131aSEugene Zelenko #include "llvm/ProfileData/ProfileCommon.h"
23e78d131aSEugene Zelenko #include "llvm/ProfileData/SampleProf.h"
246a14325dSWei Mi #include "llvm/Support/Endian.h"
256a14325dSWei Mi #include "llvm/Support/EndianStream.h"
26c572e92cSDiego Novillo #include "llvm/Support/ErrorOr.h"
27e78d131aSEugene Zelenko #include "llvm/Support/FileSystem.h"
28c572e92cSDiego Novillo #include "llvm/Support/LEB128.h"
29a0c0857eSWei Mi #include "llvm/Support/MD5.h"
30e78d131aSEugene Zelenko #include "llvm/Support/raw_ostream.h"
31e78d131aSEugene Zelenko #include <algorithm>
32e78d131aSEugene Zelenko #include <cstdint>
33e78d131aSEugene Zelenko #include <memory>
348d1c983fSDehao Chen #include <set>
35e78d131aSEugene Zelenko #include <system_error>
36e78d131aSEugene Zelenko #include <utility>
37e78d131aSEugene Zelenko #include <vector>
38c572e92cSDiego Novillo 
39c572e92cSDiego Novillo using namespace llvm;
40e78d131aSEugene Zelenko using namespace sampleprof;
41c572e92cSDiego Novillo 
428d1c983fSDehao Chen std::error_code
438d1c983fSDehao Chen SampleProfileWriter::write(const StringMap<FunctionSamples> &ProfileMap) {
448d1c983fSDehao Chen   if (std::error_code EC = writeHeader(ProfileMap))
458d1c983fSDehao Chen     return EC;
468d1c983fSDehao Chen 
478d1c983fSDehao Chen   // Sort the ProfileMap by total samples.
488d1c983fSDehao Chen   typedef std::pair<StringRef, const FunctionSamples *> NameFunctionSamples;
498d1c983fSDehao Chen   std::vector<NameFunctionSamples> V;
508d1c983fSDehao Chen   for (const auto &I : ProfileMap)
518d1c983fSDehao Chen     V.push_back(std::make_pair(I.getKey(), &I.second));
528d1c983fSDehao Chen 
53*efd94c56SFangrui Song   llvm::stable_sort(
54*efd94c56SFangrui Song       V, [](const NameFunctionSamples &A, const NameFunctionSamples &B) {
558d1c983fSDehao Chen         if (A.second->getTotalSamples() == B.second->getTotalSamples())
568d1c983fSDehao Chen           return A.first > B.first;
578d1c983fSDehao Chen         return A.second->getTotalSamples() > B.second->getTotalSamples();
588d1c983fSDehao Chen       });
598d1c983fSDehao Chen 
608d1c983fSDehao Chen   for (const auto &I : V) {
618d1c983fSDehao Chen     if (std::error_code EC = write(*I.second))
628d1c983fSDehao Chen       return EC;
638d1c983fSDehao Chen   }
648d1c983fSDehao Chen   return sampleprof_error::success;
658d1c983fSDehao Chen }
668d1c983fSDehao Chen 
676a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::write(
686a14325dSWei Mi     const StringMap<FunctionSamples> &ProfileMap) {
696a14325dSWei Mi   if (std::error_code EC = SampleProfileWriter::write(ProfileMap))
706a14325dSWei Mi     return EC;
716a14325dSWei Mi   if (std::error_code EC = writeFuncOffsetTable())
726a14325dSWei Mi     return EC;
736a14325dSWei Mi   return sampleprof_error::success;
746a14325dSWei Mi }
756a14325dSWei Mi 
765f8f34e4SAdrian Prantl /// Write samples to a text file.
778e415a82SDiego Novillo ///
788e415a82SDiego Novillo /// Note: it may be tempting to implement this in terms of
79ef548d29SDiego Novillo /// FunctionSamples::print().  Please don't.  The dump functionality is intended
808e415a82SDiego Novillo /// for debugging and has no specified form.
818e415a82SDiego Novillo ///
828e415a82SDiego Novillo /// The format used here is more structured and deliberate because
838e415a82SDiego Novillo /// it needs to be parsed by the SampleProfileReaderText class.
8457d1dda5SDehao Chen std::error_code SampleProfileWriterText::write(const FunctionSamples &S) {
8551abea74SNathan Slingerland   auto &OS = *OutputStream;
8657d1dda5SDehao Chen   OS << S.getName() << ":" << S.getTotalSamples();
87aae1ed8eSDiego Novillo   if (Indent == 0)
88aae1ed8eSDiego Novillo     OS << ":" << S.getHeadSamples();
89aae1ed8eSDiego Novillo   OS << "\n";
90c572e92cSDiego Novillo 
91ef548d29SDiego Novillo   SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples());
92ef548d29SDiego Novillo   for (const auto &I : SortedSamples.get()) {
93ef548d29SDiego Novillo     LineLocation Loc = I->first;
94ef548d29SDiego Novillo     const SampleRecord &Sample = I->second;
95aae1ed8eSDiego Novillo     OS.indent(Indent + 1);
96c572e92cSDiego Novillo     if (Loc.Discriminator == 0)
97c572e92cSDiego Novillo       OS << Loc.LineOffset << ": ";
98c572e92cSDiego Novillo     else
99c572e92cSDiego Novillo       OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
100c572e92cSDiego Novillo 
101c572e92cSDiego Novillo     OS << Sample.getSamples();
102c572e92cSDiego Novillo 
103d5336ae2SDiego Novillo     for (const auto &J : Sample.getCallTargets())
104d5336ae2SDiego Novillo       OS << " " << J.first() << ":" << J.second;
105c572e92cSDiego Novillo     OS << "\n";
106c572e92cSDiego Novillo   }
107c572e92cSDiego Novillo 
1082c7ca9b5SDehao Chen   SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples(
109ef548d29SDiego Novillo       S.getCallsiteSamples());
110aae1ed8eSDiego Novillo   Indent += 1;
1112c7ca9b5SDehao Chen   for (const auto &I : SortedCallsiteSamples.get())
1122c7ca9b5SDehao Chen     for (const auto &FS : I->second) {
11357d1dda5SDehao Chen       LineLocation Loc = I->first;
1142c7ca9b5SDehao Chen       const FunctionSamples &CalleeSamples = FS.second;
115aae1ed8eSDiego Novillo       OS.indent(Indent);
116aae1ed8eSDiego Novillo       if (Loc.Discriminator == 0)
117aae1ed8eSDiego Novillo         OS << Loc.LineOffset << ": ";
118aae1ed8eSDiego Novillo       else
119aae1ed8eSDiego Novillo         OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
12057d1dda5SDehao Chen       if (std::error_code EC = write(CalleeSamples))
121760c5a8fSDiego Novillo         return EC;
122aae1ed8eSDiego Novillo     }
123aae1ed8eSDiego Novillo   Indent -= 1;
124aae1ed8eSDiego Novillo 
125760c5a8fSDiego Novillo   return sampleprof_error::success;
126c572e92cSDiego Novillo }
127c572e92cSDiego Novillo 
128760c5a8fSDiego Novillo std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) {
129760c5a8fSDiego Novillo   const auto &ret = NameTable.find(FName);
130760c5a8fSDiego Novillo   if (ret == NameTable.end())
131760c5a8fSDiego Novillo     return sampleprof_error::truncated_name_table;
13251abea74SNathan Slingerland   encodeULEB128(ret->second, *OutputStream);
133760c5a8fSDiego Novillo   return sampleprof_error::success;
134760c5a8fSDiego Novillo }
135c572e92cSDiego Novillo 
136760c5a8fSDiego Novillo void SampleProfileWriterBinary::addName(StringRef FName) {
1378d1c983fSDehao Chen   NameTable.insert(std::make_pair(FName, 0));
138760c5a8fSDiego Novillo }
139760c5a8fSDiego Novillo 
140760c5a8fSDiego Novillo void SampleProfileWriterBinary::addNames(const FunctionSamples &S) {
141760c5a8fSDiego Novillo   // Add all the names in indirect call targets.
142760c5a8fSDiego Novillo   for (const auto &I : S.getBodySamples()) {
143760c5a8fSDiego Novillo     const SampleRecord &Sample = I.second;
144760c5a8fSDiego Novillo     for (const auto &J : Sample.getCallTargets())
145760c5a8fSDiego Novillo       addName(J.first());
146760c5a8fSDiego Novillo   }
147760c5a8fSDiego Novillo 
148760c5a8fSDiego Novillo   // Recursively add all the names for inlined callsites.
1492c7ca9b5SDehao Chen   for (const auto &J : S.getCallsiteSamples())
1502c7ca9b5SDehao Chen     for (const auto &FS : J.second) {
1512c7ca9b5SDehao Chen       const FunctionSamples &CalleeSamples = FS.second;
15257d1dda5SDehao Chen       addName(CalleeSamples.getName());
153760c5a8fSDiego Novillo       addNames(CalleeSamples);
154760c5a8fSDiego Novillo     }
155760c5a8fSDiego Novillo }
156760c5a8fSDiego Novillo 
157a0c0857eSWei Mi void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) {
158a0c0857eSWei Mi   // Sort the names to make NameTable deterministic.
159a0c0857eSWei Mi   for (const auto &I : NameTable)
160a0c0857eSWei Mi     V.insert(I.first);
161a0c0857eSWei Mi   int i = 0;
162a0c0857eSWei Mi   for (const StringRef &N : V)
163a0c0857eSWei Mi     NameTable[N] = i++;
164a0c0857eSWei Mi }
16551abea74SNathan Slingerland 
166a0c0857eSWei Mi std::error_code SampleProfileWriterRawBinary::writeNameTable() {
167a0c0857eSWei Mi   auto &OS = *OutputStream;
168a0c0857eSWei Mi   std::set<StringRef> V;
169a0c0857eSWei Mi   stablizeNameTable(V);
170a0c0857eSWei Mi 
171a0c0857eSWei Mi   // Write out the name table.
172a0c0857eSWei Mi   encodeULEB128(NameTable.size(), OS);
173a0c0857eSWei Mi   for (auto N : V) {
174a0c0857eSWei Mi     OS << N;
175a0c0857eSWei Mi     encodeULEB128(0, OS);
176a0c0857eSWei Mi   }
177a0c0857eSWei Mi   return sampleprof_error::success;
178a0c0857eSWei Mi }
179a0c0857eSWei Mi 
1806a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() {
1816a14325dSWei Mi   auto &OS = *OutputStream;
1826a14325dSWei Mi 
1836a14325dSWei Mi   // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable.
1846a14325dSWei Mi   auto &OFS = static_cast<raw_fd_ostream &>(OS);
1856a14325dSWei Mi   uint64_t FuncOffsetTableStart = OS.tell();
1866a14325dSWei Mi   if (OFS.seek(TableOffset) == (uint64_t)-1)
1876a14325dSWei Mi     return sampleprof_error::ostream_seek_unsupported;
1886a14325dSWei Mi   support::endian::Writer Writer(*OutputStream, support::little);
1896a14325dSWei Mi   Writer.write(FuncOffsetTableStart);
1906a14325dSWei Mi   if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1)
1916a14325dSWei Mi     return sampleprof_error::ostream_seek_unsupported;
1926a14325dSWei Mi 
1936a14325dSWei Mi   // Write out the table size.
1946a14325dSWei Mi   encodeULEB128(FuncOffsetTable.size(), OS);
1956a14325dSWei Mi 
1966a14325dSWei Mi   // Write out FuncOffsetTable.
1976a14325dSWei Mi   for (auto entry : FuncOffsetTable) {
1986a14325dSWei Mi     writeNameIdx(entry.first);
1996a14325dSWei Mi     encodeULEB128(entry.second, OS);
2006a14325dSWei Mi   }
2016a14325dSWei Mi   return sampleprof_error::success;
2026a14325dSWei Mi }
2036a14325dSWei Mi 
204a0c0857eSWei Mi std::error_code SampleProfileWriterCompactBinary::writeNameTable() {
205a0c0857eSWei Mi   auto &OS = *OutputStream;
206a0c0857eSWei Mi   std::set<StringRef> V;
207a0c0857eSWei Mi   stablizeNameTable(V);
208a0c0857eSWei Mi 
209a0c0857eSWei Mi   // Write out the name table.
210a0c0857eSWei Mi   encodeULEB128(NameTable.size(), OS);
211a0c0857eSWei Mi   for (auto N : V) {
212a0c0857eSWei Mi     encodeULEB128(MD5Hash(N), OS);
213a0c0857eSWei Mi   }
214a0c0857eSWei Mi   return sampleprof_error::success;
215a0c0857eSWei Mi }
216a0c0857eSWei Mi 
217a0c0857eSWei Mi std::error_code SampleProfileWriterRawBinary::writeMagicIdent() {
218a0c0857eSWei Mi   auto &OS = *OutputStream;
219760c5a8fSDiego Novillo   // Write file magic identifier.
220c572e92cSDiego Novillo   encodeULEB128(SPMagic(), OS);
221c572e92cSDiego Novillo   encodeULEB128(SPVersion(), OS);
222a0c0857eSWei Mi   return sampleprof_error::success;
223a0c0857eSWei Mi }
224a0c0857eSWei Mi 
225a0c0857eSWei Mi std::error_code SampleProfileWriterCompactBinary::writeMagicIdent() {
226a0c0857eSWei Mi   auto &OS = *OutputStream;
227a0c0857eSWei Mi   // Write file magic identifier.
228a0c0857eSWei Mi   encodeULEB128(SPMagic(SPF_Compact_Binary), OS);
229a0c0857eSWei Mi   encodeULEB128(SPVersion(), OS);
230a0c0857eSWei Mi   return sampleprof_error::success;
231a0c0857eSWei Mi }
232a0c0857eSWei Mi 
233a0c0857eSWei Mi std::error_code SampleProfileWriterBinary::writeHeader(
234a0c0857eSWei Mi     const StringMap<FunctionSamples> &ProfileMap) {
235a0c0857eSWei Mi   writeMagicIdent();
236760c5a8fSDiego Novillo 
23740ee23dbSEaswaran Raman   computeSummary(ProfileMap);
23840ee23dbSEaswaran Raman   if (auto EC = writeSummary())
23940ee23dbSEaswaran Raman     return EC;
24040ee23dbSEaswaran Raman 
241760c5a8fSDiego Novillo   // Generate the name table for all the functions referenced in the profile.
242760c5a8fSDiego Novillo   for (const auto &I : ProfileMap) {
243760c5a8fSDiego Novillo     addName(I.first());
244760c5a8fSDiego Novillo     addNames(I.second);
245760c5a8fSDiego Novillo   }
246760c5a8fSDiego Novillo 
247a0c0857eSWei Mi   writeNameTable();
248760c5a8fSDiego Novillo   return sampleprof_error::success;
249c572e92cSDiego Novillo }
250c572e92cSDiego Novillo 
2516a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::writeHeader(
2526a14325dSWei Mi     const StringMap<FunctionSamples> &ProfileMap) {
2536a14325dSWei Mi   support::endian::Writer Writer(*OutputStream, support::little);
2546a14325dSWei Mi   if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap))
2556a14325dSWei Mi     return EC;
2566a14325dSWei Mi 
2576a14325dSWei Mi   // Reserve a slot for the offset of function offset table. The slot will
2586a14325dSWei Mi   // be populated with the offset of FuncOffsetTable later.
2596a14325dSWei Mi   TableOffset = OutputStream->tell();
2606a14325dSWei Mi   Writer.write(static_cast<uint64_t>(-2));
2616a14325dSWei Mi   return sampleprof_error::success;
2626a14325dSWei Mi }
2636a14325dSWei Mi 
26440ee23dbSEaswaran Raman std::error_code SampleProfileWriterBinary::writeSummary() {
26540ee23dbSEaswaran Raman   auto &OS = *OutputStream;
2667cefdb81SEaswaran Raman   encodeULEB128(Summary->getTotalCount(), OS);
2677cefdb81SEaswaran Raman   encodeULEB128(Summary->getMaxCount(), OS);
2686f4903d9SEaswaran Raman   encodeULEB128(Summary->getMaxFunctionCount(), OS);
2697cefdb81SEaswaran Raman   encodeULEB128(Summary->getNumCounts(), OS);
27040ee23dbSEaswaran Raman   encodeULEB128(Summary->getNumFunctions(), OS);
27140ee23dbSEaswaran Raman   std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary();
27240ee23dbSEaswaran Raman   encodeULEB128(Entries.size(), OS);
27340ee23dbSEaswaran Raman   for (auto Entry : Entries) {
27440ee23dbSEaswaran Raman     encodeULEB128(Entry.Cutoff, OS);
27540ee23dbSEaswaran Raman     encodeULEB128(Entry.MinCount, OS);
27640ee23dbSEaswaran Raman     encodeULEB128(Entry.NumCounts, OS);
27740ee23dbSEaswaran Raman   }
27840ee23dbSEaswaran Raman   return sampleprof_error::success;
27940ee23dbSEaswaran Raman }
28057d1dda5SDehao Chen std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
28151abea74SNathan Slingerland   auto &OS = *OutputStream;
28251abea74SNathan Slingerland 
28357d1dda5SDehao Chen   if (std::error_code EC = writeNameIdx(S.getName()))
284760c5a8fSDiego Novillo     return EC;
285760c5a8fSDiego Novillo 
286c572e92cSDiego Novillo   encodeULEB128(S.getTotalSamples(), OS);
287a7f1e8efSDiego Novillo 
288a7f1e8efSDiego Novillo   // Emit all the body samples.
289b93483dbSDiego Novillo   encodeULEB128(S.getBodySamples().size(), OS);
290d5336ae2SDiego Novillo   for (const auto &I : S.getBodySamples()) {
291d5336ae2SDiego Novillo     LineLocation Loc = I.first;
292d5336ae2SDiego Novillo     const SampleRecord &Sample = I.second;
293c572e92cSDiego Novillo     encodeULEB128(Loc.LineOffset, OS);
294c572e92cSDiego Novillo     encodeULEB128(Loc.Discriminator, OS);
295c572e92cSDiego Novillo     encodeULEB128(Sample.getSamples(), OS);
296c572e92cSDiego Novillo     encodeULEB128(Sample.getCallTargets().size(), OS);
297d5336ae2SDiego Novillo     for (const auto &J : Sample.getCallTargets()) {
298760c5a8fSDiego Novillo       StringRef Callee = J.first();
29938be3330SDiego Novillo       uint64_t CalleeSamples = J.second;
300760c5a8fSDiego Novillo       if (std::error_code EC = writeNameIdx(Callee))
301760c5a8fSDiego Novillo         return EC;
302c572e92cSDiego Novillo       encodeULEB128(CalleeSamples, OS);
303c572e92cSDiego Novillo     }
304c572e92cSDiego Novillo   }
305c572e92cSDiego Novillo 
306a7f1e8efSDiego Novillo   // Recursively emit all the callsite samples.
3072c27daf7SDehao Chen   uint64_t NumCallsites = 0;
3082c27daf7SDehao Chen   for (const auto &J : S.getCallsiteSamples())
3092c27daf7SDehao Chen     NumCallsites += J.second.size();
3102c27daf7SDehao Chen   encodeULEB128(NumCallsites, OS);
3112c7ca9b5SDehao Chen   for (const auto &J : S.getCallsiteSamples())
3122c7ca9b5SDehao Chen     for (const auto &FS : J.second) {
31357d1dda5SDehao Chen       LineLocation Loc = J.first;
3142c7ca9b5SDehao Chen       const FunctionSamples &CalleeSamples = FS.second;
315a7f1e8efSDiego Novillo       encodeULEB128(Loc.LineOffset, OS);
316a7f1e8efSDiego Novillo       encodeULEB128(Loc.Discriminator, OS);
31757d1dda5SDehao Chen       if (std::error_code EC = writeBody(CalleeSamples))
318760c5a8fSDiego Novillo         return EC;
319a7f1e8efSDiego Novillo     }
320a7f1e8efSDiego Novillo 
321760c5a8fSDiego Novillo   return sampleprof_error::success;
322c572e92cSDiego Novillo }
323d5336ae2SDiego Novillo 
3245f8f34e4SAdrian Prantl /// Write samples of a top-level function to a binary file.
325b93483dbSDiego Novillo ///
326b93483dbSDiego Novillo /// \returns true if the samples were written successfully, false otherwise.
32757d1dda5SDehao Chen std::error_code SampleProfileWriterBinary::write(const FunctionSamples &S) {
32851abea74SNathan Slingerland   encodeULEB128(S.getHeadSamples(), *OutputStream);
32957d1dda5SDehao Chen   return writeBody(S);
330b93483dbSDiego Novillo }
331b93483dbSDiego Novillo 
3326a14325dSWei Mi std::error_code
3336a14325dSWei Mi SampleProfileWriterCompactBinary::write(const FunctionSamples &S) {
3346a14325dSWei Mi   uint64_t Offset = OutputStream->tell();
3356a14325dSWei Mi   StringRef Name = S.getName();
3366a14325dSWei Mi   FuncOffsetTable[Name] = Offset;
3376a14325dSWei Mi   encodeULEB128(S.getHeadSamples(), *OutputStream);
3386a14325dSWei Mi   return writeBody(S);
3396a14325dSWei Mi }
3406a14325dSWei Mi 
3415f8f34e4SAdrian Prantl /// Create a sample profile file writer based on the specified format.
342d5336ae2SDiego Novillo ///
343d5336ae2SDiego Novillo /// \param Filename The file to create.
344d5336ae2SDiego Novillo ///
345d5336ae2SDiego Novillo /// \param Format Encoding format for the profile file.
346d5336ae2SDiego Novillo ///
347d5336ae2SDiego Novillo /// \returns an error code indicating the status of the created writer.
348fcd55607SDiego Novillo ErrorOr<std::unique_ptr<SampleProfileWriter>>
349fcd55607SDiego Novillo SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
350d5336ae2SDiego Novillo   std::error_code EC;
35151abea74SNathan Slingerland   std::unique_ptr<raw_ostream> OS;
352d9be2c7eSWei Mi   if (Format == SPF_Binary || Format == SPF_Compact_Binary)
35351abea74SNathan Slingerland     OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::F_None));
35451abea74SNathan Slingerland   else
35551abea74SNathan Slingerland     OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::F_Text));
35651abea74SNathan Slingerland   if (EC)
35751abea74SNathan Slingerland     return EC;
35851abea74SNathan Slingerland 
35951abea74SNathan Slingerland   return create(OS, Format);
36051abea74SNathan Slingerland }
36151abea74SNathan Slingerland 
3625f8f34e4SAdrian Prantl /// Create a sample profile stream writer based on the specified format.
36351abea74SNathan Slingerland ///
36451abea74SNathan Slingerland /// \param OS The output stream to store the profile data to.
36551abea74SNathan Slingerland ///
36651abea74SNathan Slingerland /// \param Format Encoding format for the profile file.
36751abea74SNathan Slingerland ///
36851abea74SNathan Slingerland /// \returns an error code indicating the status of the created writer.
36951abea74SNathan Slingerland ErrorOr<std::unique_ptr<SampleProfileWriter>>
37051abea74SNathan Slingerland SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
37151abea74SNathan Slingerland                             SampleProfileFormat Format) {
37251abea74SNathan Slingerland   std::error_code EC;
373fcd55607SDiego Novillo   std::unique_ptr<SampleProfileWriter> Writer;
374d5336ae2SDiego Novillo 
375d9be2c7eSWei Mi   if (Format == SPF_Binary)
376a0c0857eSWei Mi     Writer.reset(new SampleProfileWriterRawBinary(OS));
377a0c0857eSWei Mi   else if (Format == SPF_Compact_Binary)
378a0c0857eSWei Mi     Writer.reset(new SampleProfileWriterCompactBinary(OS));
379d5336ae2SDiego Novillo   else if (Format == SPF_Text)
38051abea74SNathan Slingerland     Writer.reset(new SampleProfileWriterText(OS));
381760c5a8fSDiego Novillo   else if (Format == SPF_GCC)
382760c5a8fSDiego Novillo     EC = sampleprof_error::unsupported_writing_format;
383d5336ae2SDiego Novillo   else
384d5336ae2SDiego Novillo     EC = sampleprof_error::unrecognized_format;
385d5336ae2SDiego Novillo 
386fcd55607SDiego Novillo   if (EC)
387d5336ae2SDiego Novillo     return EC;
388fcd55607SDiego Novillo 
389fcd55607SDiego Novillo   return std::move(Writer);
390d5336ae2SDiego Novillo }
39140ee23dbSEaswaran Raman 
39240ee23dbSEaswaran Raman void SampleProfileWriter::computeSummary(
39340ee23dbSEaswaran Raman     const StringMap<FunctionSamples> &ProfileMap) {
394e5a17e3fSEaswaran Raman   SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
39540ee23dbSEaswaran Raman   for (const auto &I : ProfileMap) {
39640ee23dbSEaswaran Raman     const FunctionSamples &Profile = I.second;
397e5a17e3fSEaswaran Raman     Builder.addRecord(Profile);
39840ee23dbSEaswaran Raman   }
39938de59e4SBenjamin Kramer   Summary = Builder.getSummary();
40040ee23dbSEaswaran Raman }
401