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"
24*0b57cec5SDimitry Andric #include "llvm/Support/Endian.h"
25*0b57cec5SDimitry Andric #include "llvm/Support/EndianStream.h"
26*0b57cec5SDimitry Andric #include "llvm/Support/ErrorOr.h"
27*0b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
28*0b57cec5SDimitry Andric #include "llvm/Support/LEB128.h"
29*0b57cec5SDimitry Andric #include "llvm/Support/MD5.h"
30*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
31*0b57cec5SDimitry Andric #include <algorithm>
32*0b57cec5SDimitry Andric #include <cstdint>
33*0b57cec5SDimitry Andric #include <memory>
34*0b57cec5SDimitry Andric #include <set>
35*0b57cec5SDimitry Andric #include <system_error>
36*0b57cec5SDimitry Andric #include <utility>
37*0b57cec5SDimitry Andric #include <vector>
38*0b57cec5SDimitry Andric 
39*0b57cec5SDimitry Andric using namespace llvm;
40*0b57cec5SDimitry Andric using namespace sampleprof;
41*0b57cec5SDimitry Andric 
42*0b57cec5SDimitry Andric std::error_code
43*0b57cec5SDimitry Andric SampleProfileWriter::write(const StringMap<FunctionSamples> &ProfileMap) {
44*0b57cec5SDimitry Andric   if (std::error_code EC = writeHeader(ProfileMap))
45*0b57cec5SDimitry Andric     return EC;
46*0b57cec5SDimitry Andric 
47*0b57cec5SDimitry Andric   // Sort the ProfileMap by total samples.
48*0b57cec5SDimitry Andric   typedef std::pair<StringRef, const FunctionSamples *> NameFunctionSamples;
49*0b57cec5SDimitry Andric   std::vector<NameFunctionSamples> V;
50*0b57cec5SDimitry Andric   for (const auto &I : ProfileMap)
51*0b57cec5SDimitry Andric     V.push_back(std::make_pair(I.getKey(), &I.second));
52*0b57cec5SDimitry Andric 
53*0b57cec5SDimitry Andric   llvm::stable_sort(
54*0b57cec5SDimitry Andric       V, [](const NameFunctionSamples &A, const NameFunctionSamples &B) {
55*0b57cec5SDimitry Andric         if (A.second->getTotalSamples() == B.second->getTotalSamples())
56*0b57cec5SDimitry Andric           return A.first > B.first;
57*0b57cec5SDimitry Andric         return A.second->getTotalSamples() > B.second->getTotalSamples();
58*0b57cec5SDimitry Andric       });
59*0b57cec5SDimitry Andric 
60*0b57cec5SDimitry Andric   for (const auto &I : V) {
61*0b57cec5SDimitry Andric     if (std::error_code EC = write(*I.second))
62*0b57cec5SDimitry Andric       return EC;
63*0b57cec5SDimitry Andric   }
64*0b57cec5SDimitry Andric   return sampleprof_error::success;
65*0b57cec5SDimitry Andric }
66*0b57cec5SDimitry Andric 
67*0b57cec5SDimitry Andric std::error_code SampleProfileWriterCompactBinary::write(
68*0b57cec5SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
69*0b57cec5SDimitry Andric   if (std::error_code EC = SampleProfileWriter::write(ProfileMap))
70*0b57cec5SDimitry Andric     return EC;
71*0b57cec5SDimitry Andric   if (std::error_code EC = writeFuncOffsetTable())
72*0b57cec5SDimitry Andric     return EC;
73*0b57cec5SDimitry Andric   return sampleprof_error::success;
74*0b57cec5SDimitry Andric }
75*0b57cec5SDimitry Andric 
76*0b57cec5SDimitry Andric /// Write samples to a text file.
77*0b57cec5SDimitry Andric ///
78*0b57cec5SDimitry Andric /// Note: it may be tempting to implement this in terms of
79*0b57cec5SDimitry Andric /// FunctionSamples::print().  Please don't.  The dump functionality is intended
80*0b57cec5SDimitry Andric /// for debugging and has no specified form.
81*0b57cec5SDimitry Andric ///
82*0b57cec5SDimitry Andric /// The format used here is more structured and deliberate because
83*0b57cec5SDimitry Andric /// it needs to be parsed by the SampleProfileReaderText class.
84*0b57cec5SDimitry Andric std::error_code SampleProfileWriterText::write(const FunctionSamples &S) {
85*0b57cec5SDimitry Andric   auto &OS = *OutputStream;
86*0b57cec5SDimitry Andric   OS << S.getName() << ":" << S.getTotalSamples();
87*0b57cec5SDimitry Andric   if (Indent == 0)
88*0b57cec5SDimitry Andric     OS << ":" << S.getHeadSamples();
89*0b57cec5SDimitry Andric   OS << "\n";
90*0b57cec5SDimitry Andric 
91*0b57cec5SDimitry Andric   SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples());
92*0b57cec5SDimitry Andric   for (const auto &I : SortedSamples.get()) {
93*0b57cec5SDimitry Andric     LineLocation Loc = I->first;
94*0b57cec5SDimitry Andric     const SampleRecord &Sample = I->second;
95*0b57cec5SDimitry Andric     OS.indent(Indent + 1);
96*0b57cec5SDimitry Andric     if (Loc.Discriminator == 0)
97*0b57cec5SDimitry Andric       OS << Loc.LineOffset << ": ";
98*0b57cec5SDimitry Andric     else
99*0b57cec5SDimitry Andric       OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
100*0b57cec5SDimitry Andric 
101*0b57cec5SDimitry Andric     OS << Sample.getSamples();
102*0b57cec5SDimitry Andric 
103*0b57cec5SDimitry Andric     for (const auto &J : Sample.getCallTargets())
104*0b57cec5SDimitry Andric       OS << " " << J.first() << ":" << J.second;
105*0b57cec5SDimitry Andric     OS << "\n";
106*0b57cec5SDimitry Andric   }
107*0b57cec5SDimitry Andric 
108*0b57cec5SDimitry Andric   SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples(
109*0b57cec5SDimitry Andric       S.getCallsiteSamples());
110*0b57cec5SDimitry Andric   Indent += 1;
111*0b57cec5SDimitry Andric   for (const auto &I : SortedCallsiteSamples.get())
112*0b57cec5SDimitry Andric     for (const auto &FS : I->second) {
113*0b57cec5SDimitry Andric       LineLocation Loc = I->first;
114*0b57cec5SDimitry Andric       const FunctionSamples &CalleeSamples = FS.second;
115*0b57cec5SDimitry Andric       OS.indent(Indent);
116*0b57cec5SDimitry Andric       if (Loc.Discriminator == 0)
117*0b57cec5SDimitry Andric         OS << Loc.LineOffset << ": ";
118*0b57cec5SDimitry Andric       else
119*0b57cec5SDimitry Andric         OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
120*0b57cec5SDimitry Andric       if (std::error_code EC = write(CalleeSamples))
121*0b57cec5SDimitry Andric         return EC;
122*0b57cec5SDimitry Andric     }
123*0b57cec5SDimitry Andric   Indent -= 1;
124*0b57cec5SDimitry Andric 
125*0b57cec5SDimitry Andric   return sampleprof_error::success;
126*0b57cec5SDimitry Andric }
127*0b57cec5SDimitry Andric 
128*0b57cec5SDimitry Andric std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) {
129*0b57cec5SDimitry Andric   const auto &ret = NameTable.find(FName);
130*0b57cec5SDimitry Andric   if (ret == NameTable.end())
131*0b57cec5SDimitry Andric     return sampleprof_error::truncated_name_table;
132*0b57cec5SDimitry Andric   encodeULEB128(ret->second, *OutputStream);
133*0b57cec5SDimitry Andric   return sampleprof_error::success;
134*0b57cec5SDimitry Andric }
135*0b57cec5SDimitry Andric 
136*0b57cec5SDimitry Andric void SampleProfileWriterBinary::addName(StringRef FName) {
137*0b57cec5SDimitry Andric   NameTable.insert(std::make_pair(FName, 0));
138*0b57cec5SDimitry Andric }
139*0b57cec5SDimitry Andric 
140*0b57cec5SDimitry Andric void SampleProfileWriterBinary::addNames(const FunctionSamples &S) {
141*0b57cec5SDimitry Andric   // Add all the names in indirect call targets.
142*0b57cec5SDimitry Andric   for (const auto &I : S.getBodySamples()) {
143*0b57cec5SDimitry Andric     const SampleRecord &Sample = I.second;
144*0b57cec5SDimitry Andric     for (const auto &J : Sample.getCallTargets())
145*0b57cec5SDimitry Andric       addName(J.first());
146*0b57cec5SDimitry Andric   }
147*0b57cec5SDimitry Andric 
148*0b57cec5SDimitry Andric   // Recursively add all the names for inlined callsites.
149*0b57cec5SDimitry Andric   for (const auto &J : S.getCallsiteSamples())
150*0b57cec5SDimitry Andric     for (const auto &FS : J.second) {
151*0b57cec5SDimitry Andric       const FunctionSamples &CalleeSamples = FS.second;
152*0b57cec5SDimitry Andric       addName(CalleeSamples.getName());
153*0b57cec5SDimitry Andric       addNames(CalleeSamples);
154*0b57cec5SDimitry Andric     }
155*0b57cec5SDimitry Andric }
156*0b57cec5SDimitry Andric 
157*0b57cec5SDimitry Andric void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) {
158*0b57cec5SDimitry Andric   // Sort the names to make NameTable deterministic.
159*0b57cec5SDimitry Andric   for (const auto &I : NameTable)
160*0b57cec5SDimitry Andric     V.insert(I.first);
161*0b57cec5SDimitry Andric   int i = 0;
162*0b57cec5SDimitry Andric   for (const StringRef &N : V)
163*0b57cec5SDimitry Andric     NameTable[N] = i++;
164*0b57cec5SDimitry Andric }
165*0b57cec5SDimitry Andric 
166*0b57cec5SDimitry Andric std::error_code SampleProfileWriterRawBinary::writeNameTable() {
167*0b57cec5SDimitry Andric   auto &OS = *OutputStream;
168*0b57cec5SDimitry Andric   std::set<StringRef> V;
169*0b57cec5SDimitry Andric   stablizeNameTable(V);
170*0b57cec5SDimitry Andric 
171*0b57cec5SDimitry Andric   // Write out the name table.
172*0b57cec5SDimitry Andric   encodeULEB128(NameTable.size(), OS);
173*0b57cec5SDimitry Andric   for (auto N : V) {
174*0b57cec5SDimitry Andric     OS << N;
175*0b57cec5SDimitry Andric     encodeULEB128(0, OS);
176*0b57cec5SDimitry Andric   }
177*0b57cec5SDimitry Andric   return sampleprof_error::success;
178*0b57cec5SDimitry Andric }
179*0b57cec5SDimitry Andric 
180*0b57cec5SDimitry Andric std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() {
181*0b57cec5SDimitry Andric   auto &OS = *OutputStream;
182*0b57cec5SDimitry Andric 
183*0b57cec5SDimitry Andric   // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable.
184*0b57cec5SDimitry Andric   auto &OFS = static_cast<raw_fd_ostream &>(OS);
185*0b57cec5SDimitry Andric   uint64_t FuncOffsetTableStart = OS.tell();
186*0b57cec5SDimitry Andric   if (OFS.seek(TableOffset) == (uint64_t)-1)
187*0b57cec5SDimitry Andric     return sampleprof_error::ostream_seek_unsupported;
188*0b57cec5SDimitry Andric   support::endian::Writer Writer(*OutputStream, support::little);
189*0b57cec5SDimitry Andric   Writer.write(FuncOffsetTableStart);
190*0b57cec5SDimitry Andric   if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1)
191*0b57cec5SDimitry Andric     return sampleprof_error::ostream_seek_unsupported;
192*0b57cec5SDimitry Andric 
193*0b57cec5SDimitry Andric   // Write out the table size.
194*0b57cec5SDimitry Andric   encodeULEB128(FuncOffsetTable.size(), OS);
195*0b57cec5SDimitry Andric 
196*0b57cec5SDimitry Andric   // Write out FuncOffsetTable.
197*0b57cec5SDimitry Andric   for (auto entry : FuncOffsetTable) {
198*0b57cec5SDimitry Andric     writeNameIdx(entry.first);
199*0b57cec5SDimitry Andric     encodeULEB128(entry.second, OS);
200*0b57cec5SDimitry Andric   }
201*0b57cec5SDimitry Andric   return sampleprof_error::success;
202*0b57cec5SDimitry Andric }
203*0b57cec5SDimitry Andric 
204*0b57cec5SDimitry Andric std::error_code SampleProfileWriterCompactBinary::writeNameTable() {
205*0b57cec5SDimitry Andric   auto &OS = *OutputStream;
206*0b57cec5SDimitry Andric   std::set<StringRef> V;
207*0b57cec5SDimitry Andric   stablizeNameTable(V);
208*0b57cec5SDimitry Andric 
209*0b57cec5SDimitry Andric   // Write out the name table.
210*0b57cec5SDimitry Andric   encodeULEB128(NameTable.size(), OS);
211*0b57cec5SDimitry Andric   for (auto N : V) {
212*0b57cec5SDimitry Andric     encodeULEB128(MD5Hash(N), OS);
213*0b57cec5SDimitry Andric   }
214*0b57cec5SDimitry Andric   return sampleprof_error::success;
215*0b57cec5SDimitry Andric }
216*0b57cec5SDimitry Andric 
217*0b57cec5SDimitry Andric std::error_code SampleProfileWriterRawBinary::writeMagicIdent() {
218*0b57cec5SDimitry Andric   auto &OS = *OutputStream;
219*0b57cec5SDimitry Andric   // Write file magic identifier.
220*0b57cec5SDimitry Andric   encodeULEB128(SPMagic(), OS);
221*0b57cec5SDimitry Andric   encodeULEB128(SPVersion(), OS);
222*0b57cec5SDimitry Andric   return sampleprof_error::success;
223*0b57cec5SDimitry Andric }
224*0b57cec5SDimitry Andric 
225*0b57cec5SDimitry Andric std::error_code SampleProfileWriterCompactBinary::writeMagicIdent() {
226*0b57cec5SDimitry Andric   auto &OS = *OutputStream;
227*0b57cec5SDimitry Andric   // Write file magic identifier.
228*0b57cec5SDimitry Andric   encodeULEB128(SPMagic(SPF_Compact_Binary), OS);
229*0b57cec5SDimitry Andric   encodeULEB128(SPVersion(), OS);
230*0b57cec5SDimitry Andric   return sampleprof_error::success;
231*0b57cec5SDimitry Andric }
232*0b57cec5SDimitry Andric 
233*0b57cec5SDimitry Andric std::error_code SampleProfileWriterBinary::writeHeader(
234*0b57cec5SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
235*0b57cec5SDimitry Andric   writeMagicIdent();
236*0b57cec5SDimitry Andric 
237*0b57cec5SDimitry Andric   computeSummary(ProfileMap);
238*0b57cec5SDimitry Andric   if (auto EC = writeSummary())
239*0b57cec5SDimitry Andric     return EC;
240*0b57cec5SDimitry Andric 
241*0b57cec5SDimitry Andric   // Generate the name table for all the functions referenced in the profile.
242*0b57cec5SDimitry Andric   for (const auto &I : ProfileMap) {
243*0b57cec5SDimitry Andric     addName(I.first());
244*0b57cec5SDimitry Andric     addNames(I.second);
245*0b57cec5SDimitry Andric   }
246*0b57cec5SDimitry Andric 
247*0b57cec5SDimitry Andric   writeNameTable();
248*0b57cec5SDimitry Andric   return sampleprof_error::success;
249*0b57cec5SDimitry Andric }
250*0b57cec5SDimitry Andric 
251*0b57cec5SDimitry Andric std::error_code SampleProfileWriterCompactBinary::writeHeader(
252*0b57cec5SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
253*0b57cec5SDimitry Andric   support::endian::Writer Writer(*OutputStream, support::little);
254*0b57cec5SDimitry Andric   if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap))
255*0b57cec5SDimitry Andric     return EC;
256*0b57cec5SDimitry Andric 
257*0b57cec5SDimitry Andric   // Reserve a slot for the offset of function offset table. The slot will
258*0b57cec5SDimitry Andric   // be populated with the offset of FuncOffsetTable later.
259*0b57cec5SDimitry Andric   TableOffset = OutputStream->tell();
260*0b57cec5SDimitry Andric   Writer.write(static_cast<uint64_t>(-2));
261*0b57cec5SDimitry Andric   return sampleprof_error::success;
262*0b57cec5SDimitry Andric }
263*0b57cec5SDimitry Andric 
264*0b57cec5SDimitry Andric std::error_code SampleProfileWriterBinary::writeSummary() {
265*0b57cec5SDimitry Andric   auto &OS = *OutputStream;
266*0b57cec5SDimitry Andric   encodeULEB128(Summary->getTotalCount(), OS);
267*0b57cec5SDimitry Andric   encodeULEB128(Summary->getMaxCount(), OS);
268*0b57cec5SDimitry Andric   encodeULEB128(Summary->getMaxFunctionCount(), OS);
269*0b57cec5SDimitry Andric   encodeULEB128(Summary->getNumCounts(), OS);
270*0b57cec5SDimitry Andric   encodeULEB128(Summary->getNumFunctions(), OS);
271*0b57cec5SDimitry Andric   std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary();
272*0b57cec5SDimitry Andric   encodeULEB128(Entries.size(), OS);
273*0b57cec5SDimitry Andric   for (auto Entry : Entries) {
274*0b57cec5SDimitry Andric     encodeULEB128(Entry.Cutoff, OS);
275*0b57cec5SDimitry Andric     encodeULEB128(Entry.MinCount, OS);
276*0b57cec5SDimitry Andric     encodeULEB128(Entry.NumCounts, OS);
277*0b57cec5SDimitry Andric   }
278*0b57cec5SDimitry Andric   return sampleprof_error::success;
279*0b57cec5SDimitry Andric }
280*0b57cec5SDimitry Andric std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
281*0b57cec5SDimitry Andric   auto &OS = *OutputStream;
282*0b57cec5SDimitry Andric 
283*0b57cec5SDimitry Andric   if (std::error_code EC = writeNameIdx(S.getName()))
284*0b57cec5SDimitry Andric     return EC;
285*0b57cec5SDimitry Andric 
286*0b57cec5SDimitry Andric   encodeULEB128(S.getTotalSamples(), OS);
287*0b57cec5SDimitry Andric 
288*0b57cec5SDimitry Andric   // Emit all the body samples.
289*0b57cec5SDimitry Andric   encodeULEB128(S.getBodySamples().size(), OS);
290*0b57cec5SDimitry Andric   for (const auto &I : S.getBodySamples()) {
291*0b57cec5SDimitry Andric     LineLocation Loc = I.first;
292*0b57cec5SDimitry Andric     const SampleRecord &Sample = I.second;
293*0b57cec5SDimitry Andric     encodeULEB128(Loc.LineOffset, OS);
294*0b57cec5SDimitry Andric     encodeULEB128(Loc.Discriminator, OS);
295*0b57cec5SDimitry Andric     encodeULEB128(Sample.getSamples(), OS);
296*0b57cec5SDimitry Andric     encodeULEB128(Sample.getCallTargets().size(), OS);
297*0b57cec5SDimitry Andric     for (const auto &J : Sample.getCallTargets()) {
298*0b57cec5SDimitry Andric       StringRef Callee = J.first();
299*0b57cec5SDimitry Andric       uint64_t CalleeSamples = J.second;
300*0b57cec5SDimitry Andric       if (std::error_code EC = writeNameIdx(Callee))
301*0b57cec5SDimitry Andric         return EC;
302*0b57cec5SDimitry Andric       encodeULEB128(CalleeSamples, OS);
303*0b57cec5SDimitry Andric     }
304*0b57cec5SDimitry Andric   }
305*0b57cec5SDimitry Andric 
306*0b57cec5SDimitry Andric   // Recursively emit all the callsite samples.
307*0b57cec5SDimitry Andric   uint64_t NumCallsites = 0;
308*0b57cec5SDimitry Andric   for (const auto &J : S.getCallsiteSamples())
309*0b57cec5SDimitry Andric     NumCallsites += J.second.size();
310*0b57cec5SDimitry Andric   encodeULEB128(NumCallsites, OS);
311*0b57cec5SDimitry Andric   for (const auto &J : S.getCallsiteSamples())
312*0b57cec5SDimitry Andric     for (const auto &FS : J.second) {
313*0b57cec5SDimitry Andric       LineLocation Loc = J.first;
314*0b57cec5SDimitry Andric       const FunctionSamples &CalleeSamples = FS.second;
315*0b57cec5SDimitry Andric       encodeULEB128(Loc.LineOffset, OS);
316*0b57cec5SDimitry Andric       encodeULEB128(Loc.Discriminator, OS);
317*0b57cec5SDimitry Andric       if (std::error_code EC = writeBody(CalleeSamples))
318*0b57cec5SDimitry Andric         return EC;
319*0b57cec5SDimitry Andric     }
320*0b57cec5SDimitry Andric 
321*0b57cec5SDimitry Andric   return sampleprof_error::success;
322*0b57cec5SDimitry Andric }
323*0b57cec5SDimitry Andric 
324*0b57cec5SDimitry Andric /// Write samples of a top-level function to a binary file.
325*0b57cec5SDimitry Andric ///
326*0b57cec5SDimitry Andric /// \returns true if the samples were written successfully, false otherwise.
327*0b57cec5SDimitry Andric std::error_code SampleProfileWriterBinary::write(const FunctionSamples &S) {
328*0b57cec5SDimitry Andric   encodeULEB128(S.getHeadSamples(), *OutputStream);
329*0b57cec5SDimitry Andric   return writeBody(S);
330*0b57cec5SDimitry Andric }
331*0b57cec5SDimitry Andric 
332*0b57cec5SDimitry Andric std::error_code
333*0b57cec5SDimitry Andric SampleProfileWriterCompactBinary::write(const FunctionSamples &S) {
334*0b57cec5SDimitry Andric   uint64_t Offset = OutputStream->tell();
335*0b57cec5SDimitry Andric   StringRef Name = S.getName();
336*0b57cec5SDimitry Andric   FuncOffsetTable[Name] = Offset;
337*0b57cec5SDimitry Andric   encodeULEB128(S.getHeadSamples(), *OutputStream);
338*0b57cec5SDimitry Andric   return writeBody(S);
339*0b57cec5SDimitry Andric }
340*0b57cec5SDimitry Andric 
341*0b57cec5SDimitry Andric /// Create a sample profile file writer based on the specified format.
342*0b57cec5SDimitry Andric ///
343*0b57cec5SDimitry Andric /// \param Filename The file to create.
344*0b57cec5SDimitry Andric ///
345*0b57cec5SDimitry Andric /// \param Format Encoding format for the profile file.
346*0b57cec5SDimitry Andric ///
347*0b57cec5SDimitry Andric /// \returns an error code indicating the status of the created writer.
348*0b57cec5SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileWriter>>
349*0b57cec5SDimitry Andric SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
350*0b57cec5SDimitry Andric   std::error_code EC;
351*0b57cec5SDimitry Andric   std::unique_ptr<raw_ostream> OS;
352*0b57cec5SDimitry Andric   if (Format == SPF_Binary || Format == SPF_Compact_Binary)
353*0b57cec5SDimitry Andric     OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::F_None));
354*0b57cec5SDimitry Andric   else
355*0b57cec5SDimitry Andric     OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::F_Text));
356*0b57cec5SDimitry Andric   if (EC)
357*0b57cec5SDimitry Andric     return EC;
358*0b57cec5SDimitry Andric 
359*0b57cec5SDimitry Andric   return create(OS, Format);
360*0b57cec5SDimitry Andric }
361*0b57cec5SDimitry Andric 
362*0b57cec5SDimitry Andric /// Create a sample profile stream writer based on the specified format.
363*0b57cec5SDimitry Andric ///
364*0b57cec5SDimitry Andric /// \param OS The output stream to store the profile data to.
365*0b57cec5SDimitry Andric ///
366*0b57cec5SDimitry Andric /// \param Format Encoding format for the profile file.
367*0b57cec5SDimitry Andric ///
368*0b57cec5SDimitry Andric /// \returns an error code indicating the status of the created writer.
369*0b57cec5SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileWriter>>
370*0b57cec5SDimitry Andric SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
371*0b57cec5SDimitry Andric                             SampleProfileFormat Format) {
372*0b57cec5SDimitry Andric   std::error_code EC;
373*0b57cec5SDimitry Andric   std::unique_ptr<SampleProfileWriter> Writer;
374*0b57cec5SDimitry Andric 
375*0b57cec5SDimitry Andric   if (Format == SPF_Binary)
376*0b57cec5SDimitry Andric     Writer.reset(new SampleProfileWriterRawBinary(OS));
377*0b57cec5SDimitry Andric   else if (Format == SPF_Compact_Binary)
378*0b57cec5SDimitry Andric     Writer.reset(new SampleProfileWriterCompactBinary(OS));
379*0b57cec5SDimitry Andric   else if (Format == SPF_Text)
380*0b57cec5SDimitry Andric     Writer.reset(new SampleProfileWriterText(OS));
381*0b57cec5SDimitry Andric   else if (Format == SPF_GCC)
382*0b57cec5SDimitry Andric     EC = sampleprof_error::unsupported_writing_format;
383*0b57cec5SDimitry Andric   else
384*0b57cec5SDimitry Andric     EC = sampleprof_error::unrecognized_format;
385*0b57cec5SDimitry Andric 
386*0b57cec5SDimitry Andric   if (EC)
387*0b57cec5SDimitry Andric     return EC;
388*0b57cec5SDimitry Andric 
389*0b57cec5SDimitry Andric   return std::move(Writer);
390*0b57cec5SDimitry Andric }
391*0b57cec5SDimitry Andric 
392*0b57cec5SDimitry Andric void SampleProfileWriter::computeSummary(
393*0b57cec5SDimitry Andric     const StringMap<FunctionSamples> &ProfileMap) {
394*0b57cec5SDimitry Andric   SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
395*0b57cec5SDimitry Andric   for (const auto &I : ProfileMap) {
396*0b57cec5SDimitry Andric     const FunctionSamples &Profile = I.second;
397*0b57cec5SDimitry Andric     Builder.addRecord(Profile);
398*0b57cec5SDimitry Andric   }
399*0b57cec5SDimitry Andric   Summary = Builder.getSummary();
400*0b57cec5SDimitry Andric }
401