blob: 47f97de2a3b053569f8a5750c4e8057bcea5f6d5 [file] [log] [blame]
Diego Novilloc572e922014-10-30 18:00:06 +00001//===- SampleProfWriter.cpp - Write LLVM sample profile data --------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Diego Novilloc572e922014-10-30 18:00:06 +00006//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the class that writes LLVM sample profiles. It
10// supports two file formats: text and binary. The textual representation
11// is useful for debugging and testing purposes. The binary representation
12// is more compact, resulting in smaller file sizes. However, they can
13// both be used interchangeably.
14//
15// See lib/ProfileData/SampleProfReader.cpp for documentation on each of the
16// supported formats.
17//
18//===----------------------------------------------------------------------===//
19
Chandler Carruth6bda14b2017-06-06 11:49:48 +000020#include "llvm/ProfileData/SampleProfWriter.h"
Eugene Zelenkoe78d1312017-03-03 01:07:34 +000021#include "llvm/ADT/StringRef.h"
22#include "llvm/ProfileData/ProfileCommon.h"
23#include "llvm/ProfileData/SampleProf.h"
Wei Mi6a143252018-09-14 20:52:59 +000024#include "llvm/Support/Endian.h"
25#include "llvm/Support/EndianStream.h"
Diego Novilloc572e922014-10-30 18:00:06 +000026#include "llvm/Support/ErrorOr.h"
Eugene Zelenkoe78d1312017-03-03 01:07:34 +000027#include "llvm/Support/FileSystem.h"
Diego Novilloc572e922014-10-30 18:00:06 +000028#include "llvm/Support/LEB128.h"
Wei Mia0c08572018-06-11 22:40:43 +000029#include "llvm/Support/MD5.h"
Eugene Zelenkoe78d1312017-03-03 01:07:34 +000030#include "llvm/Support/raw_ostream.h"
31#include <algorithm>
32#include <cstdint>
33#include <memory>
Dehao Chen8d1c9832017-05-11 23:43:44 +000034#include <set>
Eugene Zelenkoe78d1312017-03-03 01:07:34 +000035#include <system_error>
36#include <utility>
37#include <vector>
Diego Novilloc572e922014-10-30 18:00:06 +000038
Diego Novilloc572e922014-10-30 18:00:06 +000039using namespace llvm;
Eugene Zelenkoe78d1312017-03-03 01:07:34 +000040using namespace sampleprof;
Diego Novilloc572e922014-10-30 18:00:06 +000041
Wei Mibe907322019-08-23 19:05:30 +000042std::error_code SampleProfileWriter::writeFuncProfiles(
43 const StringMap<FunctionSamples> &ProfileMap) {
Dehao Chen8d1c9832017-05-11 23:43:44 +000044 // Sort the ProfileMap by total samples.
45 typedef std::pair<StringRef, const FunctionSamples *> NameFunctionSamples;
46 std::vector<NameFunctionSamples> V;
47 for (const auto &I : ProfileMap)
48 V.push_back(std::make_pair(I.getKey(), &I.second));
49
Fangrui Songefd94c52019-04-23 14:51:27 +000050 llvm::stable_sort(
51 V, [](const NameFunctionSamples &A, const NameFunctionSamples &B) {
Dehao Chen8d1c9832017-05-11 23:43:44 +000052 if (A.second->getTotalSamples() == B.second->getTotalSamples())
53 return A.first > B.first;
54 return A.second->getTotalSamples() > B.second->getTotalSamples();
55 });
56
57 for (const auto &I : V) {
Wei Mibe907322019-08-23 19:05:30 +000058 if (std::error_code EC = writeSample(*I.second))
Dehao Chen8d1c9832017-05-11 23:43:44 +000059 return EC;
60 }
61 return sampleprof_error::success;
62}
63
Wei Mibe907322019-08-23 19:05:30 +000064std::error_code
65SampleProfileWriter::write(const StringMap<FunctionSamples> &ProfileMap) {
66 if (std::error_code EC = writeHeader(ProfileMap))
67 return EC;
68
69 if (std::error_code EC = writeFuncProfiles(ProfileMap))
70 return EC;
71
72 return sampleprof_error::success;
73}
74
75/// Return the current position and prepare to use it as the start
76/// position of a section.
77uint64_t SampleProfileWriterExtBinaryBase::markSectionStart() {
78 return OutputStream->tell();
79}
80
81/// Add a new section into section header table. Return the position
82/// of SectionEnd.
83uint64_t
84SampleProfileWriterExtBinaryBase::addNewSection(SecType Sec,
85 uint64_t SectionStart) {
86 uint64_t SectionEnd = OutputStream->tell();
87 SecHdrTable.push_back(
88 {Sec, 0, SectionStart - FileStart, SectionEnd - SectionStart});
89 return SectionEnd;
90}
91
92std::error_code SampleProfileWriterExtBinaryBase::write(
93 const StringMap<FunctionSamples> &ProfileMap) {
94 if (std::error_code EC = writeHeader(ProfileMap))
95 return EC;
96
97 if (std::error_code EC = writeSections(ProfileMap))
98 return EC;
99
100 if (std::error_code EC = writeSecHdrTable())
101 return EC;
102
103 return sampleprof_error::success;
104}
105
106std::error_code SampleProfileWriterExtBinary::writeSections(
107 const StringMap<FunctionSamples> &ProfileMap) {
108 uint64_t SectionStart = markSectionStart();
109 computeSummary(ProfileMap);
110 if (auto EC = writeSummary())
111 return EC;
112 SectionStart = addNewSection(SecProfSummary, SectionStart);
113
114 // Generate the name table for all the functions referenced in the profile.
115 for (const auto &I : ProfileMap) {
116 addName(I.first());
117 addNames(I.second);
118 }
119 writeNameTable();
120 SectionStart = addNewSection(SecNameTable, SectionStart);
121
122 if (std::error_code EC = writeFuncProfiles(ProfileMap))
123 return EC;
124 addNewSection(SecLBRProfile, SectionStart);
125
126 return sampleprof_error::success;
127}
128
Wei Mi6a143252018-09-14 20:52:59 +0000129std::error_code SampleProfileWriterCompactBinary::write(
130 const StringMap<FunctionSamples> &ProfileMap) {
131 if (std::error_code EC = SampleProfileWriter::write(ProfileMap))
132 return EC;
133 if (std::error_code EC = writeFuncOffsetTable())
134 return EC;
135 return sampleprof_error::success;
136}
137
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000138/// Write samples to a text file.
Diego Novillo8e415a82015-11-13 20:24:28 +0000139///
140/// Note: it may be tempting to implement this in terms of
Diego Novilloef548d22015-11-19 15:33:08 +0000141/// FunctionSamples::print(). Please don't. The dump functionality is intended
Diego Novillo8e415a82015-11-13 20:24:28 +0000142/// for debugging and has no specified form.
143///
144/// The format used here is more structured and deliberate because
145/// it needs to be parsed by the SampleProfileReaderText class.
Wei Mibe907322019-08-23 19:05:30 +0000146std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) {
Nathan Slingerland51abea72015-12-10 17:21:42 +0000147 auto &OS = *OutputStream;
Dehao Chen57d1dda2016-03-03 18:09:32 +0000148 OS << S.getName() << ":" << S.getTotalSamples();
Diego Novilloaae1ed82015-10-08 19:40:37 +0000149 if (Indent == 0)
150 OS << ":" << S.getHeadSamples();
151 OS << "\n";
Diego Novilloc572e922014-10-30 18:00:06 +0000152
Diego Novilloef548d22015-11-19 15:33:08 +0000153 SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples());
154 for (const auto &I : SortedSamples.get()) {
155 LineLocation Loc = I->first;
156 const SampleRecord &Sample = I->second;
Diego Novilloaae1ed82015-10-08 19:40:37 +0000157 OS.indent(Indent + 1);
Diego Novilloc572e922014-10-30 18:00:06 +0000158 if (Loc.Discriminator == 0)
159 OS << Loc.LineOffset << ": ";
160 else
161 OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
162
163 OS << Sample.getSamples();
164
Wenlei He5adace32019-08-20 20:52:00 +0000165 for (const auto &J : Sample.getSortedCallTargets())
166 OS << " " << J.first << ":" << J.second;
Diego Novilloc572e922014-10-30 18:00:06 +0000167 OS << "\n";
168 }
169
Dehao Chen2c7ca9b2017-04-13 19:52:10 +0000170 SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples(
Diego Novilloef548d22015-11-19 15:33:08 +0000171 S.getCallsiteSamples());
Diego Novilloaae1ed82015-10-08 19:40:37 +0000172 Indent += 1;
Dehao Chen2c7ca9b2017-04-13 19:52:10 +0000173 for (const auto &I : SortedCallsiteSamples.get())
174 for (const auto &FS : I->second) {
175 LineLocation Loc = I->first;
176 const FunctionSamples &CalleeSamples = FS.second;
177 OS.indent(Indent);
178 if (Loc.Discriminator == 0)
179 OS << Loc.LineOffset << ": ";
180 else
181 OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
Wei Mibe907322019-08-23 19:05:30 +0000182 if (std::error_code EC = writeSample(CalleeSamples))
Dehao Chen2c7ca9b2017-04-13 19:52:10 +0000183 return EC;
184 }
Diego Novilloaae1ed82015-10-08 19:40:37 +0000185 Indent -= 1;
186
Diego Novillo760c5a82015-10-13 22:48:46 +0000187 return sampleprof_error::success;
Diego Novilloc572e922014-10-30 18:00:06 +0000188}
189
Diego Novillo760c5a82015-10-13 22:48:46 +0000190std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) {
191 const auto &ret = NameTable.find(FName);
192 if (ret == NameTable.end())
193 return sampleprof_error::truncated_name_table;
Nathan Slingerland51abea72015-12-10 17:21:42 +0000194 encodeULEB128(ret->second, *OutputStream);
Diego Novillo760c5a82015-10-13 22:48:46 +0000195 return sampleprof_error::success;
196}
Diego Novilloc572e922014-10-30 18:00:06 +0000197
Diego Novillo760c5a82015-10-13 22:48:46 +0000198void SampleProfileWriterBinary::addName(StringRef FName) {
Dehao Chen8d1c9832017-05-11 23:43:44 +0000199 NameTable.insert(std::make_pair(FName, 0));
Diego Novillo760c5a82015-10-13 22:48:46 +0000200}
201
202void SampleProfileWriterBinary::addNames(const FunctionSamples &S) {
203 // Add all the names in indirect call targets.
204 for (const auto &I : S.getBodySamples()) {
205 const SampleRecord &Sample = I.second;
206 for (const auto &J : Sample.getCallTargets())
207 addName(J.first());
208 }
209
210 // Recursively add all the names for inlined callsites.
Dehao Chen2c7ca9b2017-04-13 19:52:10 +0000211 for (const auto &J : S.getCallsiteSamples())
212 for (const auto &FS : J.second) {
213 const FunctionSamples &CalleeSamples = FS.second;
214 addName(CalleeSamples.getName());
215 addNames(CalleeSamples);
216 }
Diego Novillo760c5a82015-10-13 22:48:46 +0000217}
218
Wei Mia0c08572018-06-11 22:40:43 +0000219void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) {
220 // Sort the names to make NameTable deterministic.
221 for (const auto &I : NameTable)
222 V.insert(I.first);
223 int i = 0;
224 for (const StringRef &N : V)
225 NameTable[N] = i++;
226}
Nathan Slingerland51abea72015-12-10 17:21:42 +0000227
Wei Mibe907322019-08-23 19:05:30 +0000228std::error_code SampleProfileWriterBinary::writeNameTable() {
Wei Mia0c08572018-06-11 22:40:43 +0000229 auto &OS = *OutputStream;
230 std::set<StringRef> V;
231 stablizeNameTable(V);
232
233 // Write out the name table.
234 encodeULEB128(NameTable.size(), OS);
235 for (auto N : V) {
236 OS << N;
237 encodeULEB128(0, OS);
238 }
239 return sampleprof_error::success;
240}
241
Wei Mi6a143252018-09-14 20:52:59 +0000242std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() {
243 auto &OS = *OutputStream;
244
245 // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable.
246 auto &OFS = static_cast<raw_fd_ostream &>(OS);
247 uint64_t FuncOffsetTableStart = OS.tell();
248 if (OFS.seek(TableOffset) == (uint64_t)-1)
249 return sampleprof_error::ostream_seek_unsupported;
250 support::endian::Writer Writer(*OutputStream, support::little);
251 Writer.write(FuncOffsetTableStart);
252 if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1)
253 return sampleprof_error::ostream_seek_unsupported;
254
255 // Write out the table size.
256 encodeULEB128(FuncOffsetTable.size(), OS);
257
258 // Write out FuncOffsetTable.
259 for (auto entry : FuncOffsetTable) {
260 writeNameIdx(entry.first);
261 encodeULEB128(entry.second, OS);
262 }
263 return sampleprof_error::success;
264}
265
Wei Mia0c08572018-06-11 22:40:43 +0000266std::error_code SampleProfileWriterCompactBinary::writeNameTable() {
267 auto &OS = *OutputStream;
268 std::set<StringRef> V;
269 stablizeNameTable(V);
270
271 // Write out the name table.
272 encodeULEB128(NameTable.size(), OS);
273 for (auto N : V) {
274 encodeULEB128(MD5Hash(N), OS);
275 }
276 return sampleprof_error::success;
277}
278
Wei Mibe907322019-08-23 19:05:30 +0000279std::error_code
280SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) {
Wei Mia0c08572018-06-11 22:40:43 +0000281 auto &OS = *OutputStream;
Diego Novillo760c5a82015-10-13 22:48:46 +0000282 // Write file magic identifier.
Wei Mibe907322019-08-23 19:05:30 +0000283 encodeULEB128(SPMagic(Format), OS);
Wei Mia0c08572018-06-11 22:40:43 +0000284 encodeULEB128(SPVersion(), OS);
285 return sampleprof_error::success;
286}
287
288std::error_code SampleProfileWriterBinary::writeHeader(
289 const StringMap<FunctionSamples> &ProfileMap) {
Wei Mibe907322019-08-23 19:05:30 +0000290 writeMagicIdent(Format);
Diego Novillo760c5a82015-10-13 22:48:46 +0000291
Easwaran Raman40ee23d2016-02-19 03:15:33 +0000292 computeSummary(ProfileMap);
293 if (auto EC = writeSummary())
294 return EC;
295
Diego Novillo760c5a82015-10-13 22:48:46 +0000296 // Generate the name table for all the functions referenced in the profile.
297 for (const auto &I : ProfileMap) {
298 addName(I.first());
299 addNames(I.second);
300 }
301
Wei Mia0c08572018-06-11 22:40:43 +0000302 writeNameTable();
Diego Novillo760c5a82015-10-13 22:48:46 +0000303 return sampleprof_error::success;
Diego Novilloc572e922014-10-30 18:00:06 +0000304}
305
Wei Mibe907322019-08-23 19:05:30 +0000306void SampleProfileWriterExtBinaryBase::allocSecHdrTable() {
307 support::endian::Writer Writer(*OutputStream, support::little);
308
309 Writer.write(static_cast<uint64_t>(SectionLayout.size()));
310 SecHdrTableOffset = OutputStream->tell();
311 for (uint32_t i = 0; i < SectionLayout.size(); i++) {
312 Writer.write(static_cast<uint64_t>(-1));
313 Writer.write(static_cast<uint64_t>(-1));
314 Writer.write(static_cast<uint64_t>(-1));
315 Writer.write(static_cast<uint64_t>(-1));
316 }
317}
318
319std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() {
320 auto &OFS = static_cast<raw_fd_ostream &>(*OutputStream);
321 uint64_t Saved = OutputStream->tell();
322
323 // Set OutputStream to the location saved in SecHdrTableOffset.
324 if (OFS.seek(SecHdrTableOffset) == (uint64_t)-1)
325 return sampleprof_error::ostream_seek_unsupported;
326 support::endian::Writer Writer(*OutputStream, support::little);
327
328 DenseMap<uint32_t, uint32_t> IndexMap;
329 for (uint32_t i = 0; i < SecHdrTable.size(); i++) {
330 IndexMap.insert({static_cast<uint32_t>(SecHdrTable[i].Type), i});
331 }
332
333 // Write the sections in the order specified in SectionLayout.
334 // That is the sections order Reader will see. Note that the
335 // sections order in which Reader expects to read may be different
336 // from the order in which Writer is able to write, so we need
337 // to adjust the order in SecHdrTable to be consistent with
338 // SectionLayout when we write SecHdrTable to the memory.
339 for (uint32_t i = 0; i < SectionLayout.size(); i++) {
340 uint32_t idx = IndexMap[static_cast<uint32_t>(SectionLayout[i])];
341 Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Type));
342 Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Flag));
343 Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Offset));
344 Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Size));
345 }
346
347 // Reset OutputStream.
348 if (OFS.seek(Saved) == (uint64_t)-1)
349 return sampleprof_error::ostream_seek_unsupported;
350
351 return sampleprof_error::success;
352}
353
354std::error_code SampleProfileWriterExtBinaryBase::writeHeader(
355 const StringMap<FunctionSamples> &ProfileMap) {
356 auto &OS = *OutputStream;
357 FileStart = OS.tell();
358 writeMagicIdent(Format);
359
360 initSectionLayout();
361 allocSecHdrTable();
362 return sampleprof_error::success;
363}
364
Wei Mi6a143252018-09-14 20:52:59 +0000365std::error_code SampleProfileWriterCompactBinary::writeHeader(
366 const StringMap<FunctionSamples> &ProfileMap) {
367 support::endian::Writer Writer(*OutputStream, support::little);
368 if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap))
369 return EC;
370
371 // Reserve a slot for the offset of function offset table. The slot will
372 // be populated with the offset of FuncOffsetTable later.
373 TableOffset = OutputStream->tell();
374 Writer.write(static_cast<uint64_t>(-2));
375 return sampleprof_error::success;
376}
377
Easwaran Raman40ee23d2016-02-19 03:15:33 +0000378std::error_code SampleProfileWriterBinary::writeSummary() {
379 auto &OS = *OutputStream;
Easwaran Raman7cefdb82016-05-19 21:53:28 +0000380 encodeULEB128(Summary->getTotalCount(), OS);
381 encodeULEB128(Summary->getMaxCount(), OS);
Easwaran Raman6f4903d2016-03-28 23:14:29 +0000382 encodeULEB128(Summary->getMaxFunctionCount(), OS);
Easwaran Raman7cefdb82016-05-19 21:53:28 +0000383 encodeULEB128(Summary->getNumCounts(), OS);
Easwaran Raman40ee23d2016-02-19 03:15:33 +0000384 encodeULEB128(Summary->getNumFunctions(), OS);
385 std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary();
386 encodeULEB128(Entries.size(), OS);
387 for (auto Entry : Entries) {
388 encodeULEB128(Entry.Cutoff, OS);
389 encodeULEB128(Entry.MinCount, OS);
390 encodeULEB128(Entry.NumCounts, OS);
391 }
392 return sampleprof_error::success;
393}
Dehao Chen57d1dda2016-03-03 18:09:32 +0000394std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
Nathan Slingerland51abea72015-12-10 17:21:42 +0000395 auto &OS = *OutputStream;
396
Dehao Chen57d1dda2016-03-03 18:09:32 +0000397 if (std::error_code EC = writeNameIdx(S.getName()))
Diego Novillo760c5a82015-10-13 22:48:46 +0000398 return EC;
399
Diego Novilloc572e922014-10-30 18:00:06 +0000400 encodeULEB128(S.getTotalSamples(), OS);
Diego Novilloa7f1e8e2015-10-09 17:54:24 +0000401
402 // Emit all the body samples.
Diego Novillob93483d2015-10-16 18:54:35 +0000403 encodeULEB128(S.getBodySamples().size(), OS);
Diego Novillod5336ae2014-11-01 00:56:55 +0000404 for (const auto &I : S.getBodySamples()) {
405 LineLocation Loc = I.first;
406 const SampleRecord &Sample = I.second;
Diego Novilloc572e922014-10-30 18:00:06 +0000407 encodeULEB128(Loc.LineOffset, OS);
408 encodeULEB128(Loc.Discriminator, OS);
409 encodeULEB128(Sample.getSamples(), OS);
410 encodeULEB128(Sample.getCallTargets().size(), OS);
Wenlei He5adace32019-08-20 20:52:00 +0000411 for (const auto &J : Sample.getSortedCallTargets()) {
412 StringRef Callee = J.first;
Diego Novillo38be3332015-10-15 16:36:21 +0000413 uint64_t CalleeSamples = J.second;
Diego Novillo760c5a82015-10-13 22:48:46 +0000414 if (std::error_code EC = writeNameIdx(Callee))
415 return EC;
Diego Novilloc572e922014-10-30 18:00:06 +0000416 encodeULEB128(CalleeSamples, OS);
417 }
418 }
419
Diego Novilloa7f1e8e2015-10-09 17:54:24 +0000420 // Recursively emit all the callsite samples.
Dehao Chen2c27daf2017-08-03 00:09:18 +0000421 uint64_t NumCallsites = 0;
422 for (const auto &J : S.getCallsiteSamples())
423 NumCallsites += J.second.size();
424 encodeULEB128(NumCallsites, OS);
Dehao Chen2c7ca9b2017-04-13 19:52:10 +0000425 for (const auto &J : S.getCallsiteSamples())
426 for (const auto &FS : J.second) {
427 LineLocation Loc = J.first;
428 const FunctionSamples &CalleeSamples = FS.second;
429 encodeULEB128(Loc.LineOffset, OS);
430 encodeULEB128(Loc.Discriminator, OS);
431 if (std::error_code EC = writeBody(CalleeSamples))
432 return EC;
433 }
Diego Novilloa7f1e8e2015-10-09 17:54:24 +0000434
Diego Novillo760c5a82015-10-13 22:48:46 +0000435 return sampleprof_error::success;
Diego Novilloc572e922014-10-30 18:00:06 +0000436}
Diego Novillod5336ae2014-11-01 00:56:55 +0000437
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000438/// Write samples of a top-level function to a binary file.
Diego Novillob93483d2015-10-16 18:54:35 +0000439///
440/// \returns true if the samples were written successfully, false otherwise.
Wei Mibe907322019-08-23 19:05:30 +0000441std::error_code
442SampleProfileWriterBinary::writeSample(const FunctionSamples &S) {
Nathan Slingerland51abea72015-12-10 17:21:42 +0000443 encodeULEB128(S.getHeadSamples(), *OutputStream);
Dehao Chen57d1dda2016-03-03 18:09:32 +0000444 return writeBody(S);
Diego Novillob93483d2015-10-16 18:54:35 +0000445}
446
Wei Mi6a143252018-09-14 20:52:59 +0000447std::error_code
Wei Mibe907322019-08-23 19:05:30 +0000448SampleProfileWriterCompactBinary::writeSample(const FunctionSamples &S) {
Wei Mi6a143252018-09-14 20:52:59 +0000449 uint64_t Offset = OutputStream->tell();
450 StringRef Name = S.getName();
451 FuncOffsetTable[Name] = Offset;
452 encodeULEB128(S.getHeadSamples(), *OutputStream);
453 return writeBody(S);
454}
455
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000456/// Create a sample profile file writer based on the specified format.
Diego Novillod5336ae2014-11-01 00:56:55 +0000457///
458/// \param Filename The file to create.
459///
Diego Novillod5336ae2014-11-01 00:56:55 +0000460/// \param Format Encoding format for the profile file.
461///
462/// \returns an error code indicating the status of the created writer.
Diego Novillofcd55602014-11-03 00:51:45 +0000463ErrorOr<std::unique_ptr<SampleProfileWriter>>
464SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
Diego Novillod5336ae2014-11-01 00:56:55 +0000465 std::error_code EC;
Nathan Slingerland51abea72015-12-10 17:21:42 +0000466 std::unique_ptr<raw_ostream> OS;
Wei Mibe907322019-08-23 19:05:30 +0000467 if (Format == SPF_Binary || Format == SPF_Ext_Binary ||
468 Format == SPF_Compact_Binary)
Fangrui Songd9b948b2019-08-05 05:43:48 +0000469 OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None));
Nathan Slingerland51abea72015-12-10 17:21:42 +0000470 else
Fangrui Songd9b948b2019-08-05 05:43:48 +0000471 OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_Text));
Nathan Slingerland51abea72015-12-10 17:21:42 +0000472 if (EC)
473 return EC;
474
475 return create(OS, Format);
476}
477
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000478/// Create a sample profile stream writer based on the specified format.
Nathan Slingerland51abea72015-12-10 17:21:42 +0000479///
480/// \param OS The output stream to store the profile data to.
481///
Nathan Slingerland51abea72015-12-10 17:21:42 +0000482/// \param Format Encoding format for the profile file.
483///
484/// \returns an error code indicating the status of the created writer.
485ErrorOr<std::unique_ptr<SampleProfileWriter>>
486SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
487 SampleProfileFormat Format) {
488 std::error_code EC;
Diego Novillofcd55602014-11-03 00:51:45 +0000489 std::unique_ptr<SampleProfileWriter> Writer;
Diego Novillod5336ae2014-11-01 00:56:55 +0000490
Wei Mid9be2c72018-06-12 05:53:49 +0000491 if (Format == SPF_Binary)
Wei Mia0c08572018-06-11 22:40:43 +0000492 Writer.reset(new SampleProfileWriterRawBinary(OS));
Wei Mibe907322019-08-23 19:05:30 +0000493 else if (Format == SPF_Ext_Binary)
494 Writer.reset(new SampleProfileWriterExtBinary(OS));
Wei Mia0c08572018-06-11 22:40:43 +0000495 else if (Format == SPF_Compact_Binary)
496 Writer.reset(new SampleProfileWriterCompactBinary(OS));
Diego Novillod5336ae2014-11-01 00:56:55 +0000497 else if (Format == SPF_Text)
Nathan Slingerland51abea72015-12-10 17:21:42 +0000498 Writer.reset(new SampleProfileWriterText(OS));
Diego Novillo760c5a82015-10-13 22:48:46 +0000499 else if (Format == SPF_GCC)
500 EC = sampleprof_error::unsupported_writing_format;
Diego Novillod5336ae2014-11-01 00:56:55 +0000501 else
502 EC = sampleprof_error::unrecognized_format;
503
Diego Novillofcd55602014-11-03 00:51:45 +0000504 if (EC)
505 return EC;
506
Wei Mibe907322019-08-23 19:05:30 +0000507 Writer->Format = Format;
Diego Novillofcd55602014-11-03 00:51:45 +0000508 return std::move(Writer);
Diego Novillod5336ae2014-11-01 00:56:55 +0000509}
Easwaran Raman40ee23d2016-02-19 03:15:33 +0000510
511void SampleProfileWriter::computeSummary(
512 const StringMap<FunctionSamples> &ProfileMap) {
Easwaran Ramane5a17e32016-05-19 21:07:12 +0000513 SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
Easwaran Raman40ee23d2016-02-19 03:15:33 +0000514 for (const auto &I : ProfileMap) {
515 const FunctionSamples &Profile = I.second;
Easwaran Ramane5a17e32016-05-19 21:07:12 +0000516 Builder.addRecord(Profile);
Easwaran Raman40ee23d2016-02-19 03:15:33 +0000517 }
Benjamin Kramer38de59e2016-05-20 09:18:37 +0000518 Summary = Builder.getSummary();
Easwaran Raman40ee23d2016-02-19 03:15:33 +0000519}