blob: 03446367665bdcfb23a9f02c233b1fa93e8d26f4 [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 Mib5237902019-10-07 16:12:37 +000024#include "llvm/Support/Compression.h"
Wei Mi6a143252018-09-14 20:52:59 +000025#include "llvm/Support/Endian.h"
26#include "llvm/Support/EndianStream.h"
Diego Novilloc572e922014-10-30 18:00:06 +000027#include "llvm/Support/ErrorOr.h"
Eugene Zelenkoe78d1312017-03-03 01:07:34 +000028#include "llvm/Support/FileSystem.h"
Diego Novilloc572e922014-10-30 18:00:06 +000029#include "llvm/Support/LEB128.h"
Wei Mia0c08572018-06-11 22:40:43 +000030#include "llvm/Support/MD5.h"
Eugene Zelenkoe78d1312017-03-03 01:07:34 +000031#include "llvm/Support/raw_ostream.h"
32#include <algorithm>
33#include <cstdint>
34#include <memory>
Dehao Chen8d1c9832017-05-11 23:43:44 +000035#include <set>
Eugene Zelenkoe78d1312017-03-03 01:07:34 +000036#include <system_error>
37#include <utility>
38#include <vector>
Diego Novilloc572e922014-10-30 18:00:06 +000039
Diego Novilloc572e922014-10-30 18:00:06 +000040using namespace llvm;
Eugene Zelenkoe78d1312017-03-03 01:07:34 +000041using namespace sampleprof;
Diego Novilloc572e922014-10-30 18:00:06 +000042
Wei Mibe907322019-08-23 19:05:30 +000043std::error_code SampleProfileWriter::writeFuncProfiles(
44 const StringMap<FunctionSamples> &ProfileMap) {
Dehao Chen8d1c9832017-05-11 23:43:44 +000045 // Sort the ProfileMap by total samples.
46 typedef std::pair<StringRef, const FunctionSamples *> NameFunctionSamples;
47 std::vector<NameFunctionSamples> V;
48 for (const auto &I : ProfileMap)
49 V.push_back(std::make_pair(I.getKey(), &I.second));
50
Fangrui Songefd94c52019-04-23 14:51:27 +000051 llvm::stable_sort(
52 V, [](const NameFunctionSamples &A, const NameFunctionSamples &B) {
Dehao Chen8d1c9832017-05-11 23:43:44 +000053 if (A.second->getTotalSamples() == B.second->getTotalSamples())
54 return A.first > B.first;
55 return A.second->getTotalSamples() > B.second->getTotalSamples();
56 });
57
58 for (const auto &I : V) {
Wei Mibe907322019-08-23 19:05:30 +000059 if (std::error_code EC = writeSample(*I.second))
Dehao Chen8d1c9832017-05-11 23:43:44 +000060 return EC;
61 }
62 return sampleprof_error::success;
63}
64
Wei Mibe907322019-08-23 19:05:30 +000065std::error_code
66SampleProfileWriter::write(const StringMap<FunctionSamples> &ProfileMap) {
67 if (std::error_code EC = writeHeader(ProfileMap))
68 return EC;
69
70 if (std::error_code EC = writeFuncProfiles(ProfileMap))
71 return EC;
72
73 return sampleprof_error::success;
74}
75
Wei Mib5237902019-10-07 16:12:37 +000076SecHdrTableEntry &
77SampleProfileWriterExtBinaryBase::getEntryInLayout(SecType Type) {
78 auto SecIt = std::find_if(
79 SectionLayout.begin(), SectionLayout.end(),
80 [=](const auto &Entry) -> bool { return Entry.Type == Type; });
81 return *SecIt;
Wei Mibe907322019-08-23 19:05:30 +000082}
83
Wei Mib5237902019-10-07 16:12:37 +000084/// Return the current position and prepare to use it as the start
85/// position of a section.
86uint64_t SampleProfileWriterExtBinaryBase::markSectionStart(SecType Type) {
87 uint64_t SectionStart = OutputStream->tell();
88 auto &Entry = getEntryInLayout(Type);
89 // Use LocalBuf as a temporary output for writting data.
90 if (hasSecFlag(Entry, SecFlagCompress))
91 LocalBufStream.swap(OutputStream);
92 return SectionStart;
93}
94
95std::error_code SampleProfileWriterExtBinaryBase::compressAndOutput() {
96 if (!llvm::zlib::isAvailable())
97 return sampleprof_error::zlib_unavailable;
98 std::string &UncompressedStrings =
99 static_cast<raw_string_ostream *>(LocalBufStream.get())->str();
100 if (UncompressedStrings.size() == 0)
101 return sampleprof_error::success;
102 auto &OS = *OutputStream;
103 SmallString<128> CompressedStrings;
104 llvm::Error E = zlib::compress(UncompressedStrings, CompressedStrings,
105 zlib::BestSizeCompression);
106 if (E)
107 return sampleprof_error::compress_failed;
108 encodeULEB128(UncompressedStrings.size(), OS);
109 encodeULEB128(CompressedStrings.size(), OS);
110 OS << CompressedStrings.str();
111 UncompressedStrings.clear();
112 return sampleprof_error::success;
113}
114
115/// Add a new section into section header table.
116std::error_code
117SampleProfileWriterExtBinaryBase::addNewSection(SecType Type,
Wei Mibe907322019-08-23 19:05:30 +0000118 uint64_t SectionStart) {
Wei Mib5237902019-10-07 16:12:37 +0000119 auto Entry = getEntryInLayout(Type);
120 if (hasSecFlag(Entry, SecFlagCompress)) {
121 LocalBufStream.swap(OutputStream);
122 if (std::error_code EC = compressAndOutput())
123 return EC;
124 }
125 SecHdrTable.push_back({Type, Entry.Flags, SectionStart - FileStart,
126 OutputStream->tell() - SectionStart});
127 return sampleprof_error::success;
Wei Mibe907322019-08-23 19:05:30 +0000128}
129
130std::error_code SampleProfileWriterExtBinaryBase::write(
131 const StringMap<FunctionSamples> &ProfileMap) {
132 if (std::error_code EC = writeHeader(ProfileMap))
133 return EC;
134
Wei Mib5237902019-10-07 16:12:37 +0000135 std::string LocalBuf;
136 LocalBufStream = std::make_unique<raw_string_ostream>(LocalBuf);
Wei Mibe907322019-08-23 19:05:30 +0000137 if (std::error_code EC = writeSections(ProfileMap))
138 return EC;
139
140 if (std::error_code EC = writeSecHdrTable())
141 return EC;
142
143 return sampleprof_error::success;
144}
145
146std::error_code SampleProfileWriterExtBinary::writeSections(
147 const StringMap<FunctionSamples> &ProfileMap) {
Wei Mib5237902019-10-07 16:12:37 +0000148 uint64_t SectionStart = markSectionStart(SecProfSummary);
Wei Mibe907322019-08-23 19:05:30 +0000149 computeSummary(ProfileMap);
150 if (auto EC = writeSummary())
151 return EC;
Wei Mib5237902019-10-07 16:12:37 +0000152 if (std::error_code EC = addNewSection(SecProfSummary, SectionStart))
153 return EC;
Wei Mibe907322019-08-23 19:05:30 +0000154
155 // Generate the name table for all the functions referenced in the profile.
Wei Mib5237902019-10-07 16:12:37 +0000156 SectionStart = markSectionStart(SecNameTable);
Wei Mibe907322019-08-23 19:05:30 +0000157 for (const auto &I : ProfileMap) {
158 addName(I.first());
159 addNames(I.second);
160 }
161 writeNameTable();
Wei Mib5237902019-10-07 16:12:37 +0000162 if (std::error_code EC = addNewSection(SecNameTable, SectionStart))
163 return EC;
Wei Mibe907322019-08-23 19:05:30 +0000164
Wei Mib5237902019-10-07 16:12:37 +0000165 SectionStart = markSectionStart(SecLBRProfile);
Wei Mibe907322019-08-23 19:05:30 +0000166 if (std::error_code EC = writeFuncProfiles(ProfileMap))
167 return EC;
Wei Mib5237902019-10-07 16:12:37 +0000168 if (std::error_code EC = addNewSection(SecLBRProfile, SectionStart))
169 return EC;
Wei Mi798e59b2019-08-31 02:27:26 +0000170
Wei Mib5237902019-10-07 16:12:37 +0000171 if (ProfSymList && ProfSymList->toCompress())
172 setToCompressSection(SecProfileSymbolList);
173
174 SectionStart = markSectionStart(SecProfileSymbolList);
Wei Mi798e59b2019-08-31 02:27:26 +0000175 if (ProfSymList && ProfSymList->size() > 0)
176 if (std::error_code EC = ProfSymList->write(*OutputStream))
177 return EC;
Wei Mib5237902019-10-07 16:12:37 +0000178 if (std::error_code EC = addNewSection(SecProfileSymbolList, SectionStart))
179 return EC;
Wei Mibe907322019-08-23 19:05:30 +0000180
181 return sampleprof_error::success;
182}
183
Wei Mi6a143252018-09-14 20:52:59 +0000184std::error_code SampleProfileWriterCompactBinary::write(
185 const StringMap<FunctionSamples> &ProfileMap) {
186 if (std::error_code EC = SampleProfileWriter::write(ProfileMap))
187 return EC;
188 if (std::error_code EC = writeFuncOffsetTable())
189 return EC;
190 return sampleprof_error::success;
191}
192
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000193/// Write samples to a text file.
Diego Novillo8e415a82015-11-13 20:24:28 +0000194///
195/// Note: it may be tempting to implement this in terms of
Diego Novilloef548d22015-11-19 15:33:08 +0000196/// FunctionSamples::print(). Please don't. The dump functionality is intended
Diego Novillo8e415a82015-11-13 20:24:28 +0000197/// for debugging and has no specified form.
198///
199/// The format used here is more structured and deliberate because
200/// it needs to be parsed by the SampleProfileReaderText class.
Wei Mibe907322019-08-23 19:05:30 +0000201std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) {
Nathan Slingerland51abea72015-12-10 17:21:42 +0000202 auto &OS = *OutputStream;
Dehao Chen57d1dda2016-03-03 18:09:32 +0000203 OS << S.getName() << ":" << S.getTotalSamples();
Diego Novilloaae1ed82015-10-08 19:40:37 +0000204 if (Indent == 0)
205 OS << ":" << S.getHeadSamples();
206 OS << "\n";
Diego Novilloc572e922014-10-30 18:00:06 +0000207
Diego Novilloef548d22015-11-19 15:33:08 +0000208 SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples());
209 for (const auto &I : SortedSamples.get()) {
210 LineLocation Loc = I->first;
211 const SampleRecord &Sample = I->second;
Diego Novilloaae1ed82015-10-08 19:40:37 +0000212 OS.indent(Indent + 1);
Diego Novilloc572e922014-10-30 18:00:06 +0000213 if (Loc.Discriminator == 0)
214 OS << Loc.LineOffset << ": ";
215 else
216 OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
217
218 OS << Sample.getSamples();
219
Wenlei He5adace32019-08-20 20:52:00 +0000220 for (const auto &J : Sample.getSortedCallTargets())
221 OS << " " << J.first << ":" << J.second;
Diego Novilloc572e922014-10-30 18:00:06 +0000222 OS << "\n";
223 }
224
Dehao Chen2c7ca9b2017-04-13 19:52:10 +0000225 SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples(
Diego Novilloef548d22015-11-19 15:33:08 +0000226 S.getCallsiteSamples());
Diego Novilloaae1ed82015-10-08 19:40:37 +0000227 Indent += 1;
Dehao Chen2c7ca9b2017-04-13 19:52:10 +0000228 for (const auto &I : SortedCallsiteSamples.get())
229 for (const auto &FS : I->second) {
230 LineLocation Loc = I->first;
231 const FunctionSamples &CalleeSamples = FS.second;
232 OS.indent(Indent);
233 if (Loc.Discriminator == 0)
234 OS << Loc.LineOffset << ": ";
235 else
236 OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
Wei Mibe907322019-08-23 19:05:30 +0000237 if (std::error_code EC = writeSample(CalleeSamples))
Dehao Chen2c7ca9b2017-04-13 19:52:10 +0000238 return EC;
239 }
Diego Novilloaae1ed82015-10-08 19:40:37 +0000240 Indent -= 1;
241
Diego Novillo760c5a82015-10-13 22:48:46 +0000242 return sampleprof_error::success;
Diego Novilloc572e922014-10-30 18:00:06 +0000243}
244
Diego Novillo760c5a82015-10-13 22:48:46 +0000245std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) {
246 const auto &ret = NameTable.find(FName);
247 if (ret == NameTable.end())
248 return sampleprof_error::truncated_name_table;
Nathan Slingerland51abea72015-12-10 17:21:42 +0000249 encodeULEB128(ret->second, *OutputStream);
Diego Novillo760c5a82015-10-13 22:48:46 +0000250 return sampleprof_error::success;
251}
Diego Novilloc572e922014-10-30 18:00:06 +0000252
Diego Novillo760c5a82015-10-13 22:48:46 +0000253void SampleProfileWriterBinary::addName(StringRef FName) {
Dehao Chen8d1c9832017-05-11 23:43:44 +0000254 NameTable.insert(std::make_pair(FName, 0));
Diego Novillo760c5a82015-10-13 22:48:46 +0000255}
256
257void SampleProfileWriterBinary::addNames(const FunctionSamples &S) {
258 // Add all the names in indirect call targets.
259 for (const auto &I : S.getBodySamples()) {
260 const SampleRecord &Sample = I.second;
261 for (const auto &J : Sample.getCallTargets())
262 addName(J.first());
263 }
264
265 // Recursively add all the names for inlined callsites.
Dehao Chen2c7ca9b2017-04-13 19:52:10 +0000266 for (const auto &J : S.getCallsiteSamples())
267 for (const auto &FS : J.second) {
268 const FunctionSamples &CalleeSamples = FS.second;
269 addName(CalleeSamples.getName());
270 addNames(CalleeSamples);
271 }
Diego Novillo760c5a82015-10-13 22:48:46 +0000272}
273
Wei Mia0c08572018-06-11 22:40:43 +0000274void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) {
275 // Sort the names to make NameTable deterministic.
276 for (const auto &I : NameTable)
277 V.insert(I.first);
278 int i = 0;
279 for (const StringRef &N : V)
280 NameTable[N] = i++;
281}
Nathan Slingerland51abea72015-12-10 17:21:42 +0000282
Wei Mibe907322019-08-23 19:05:30 +0000283std::error_code SampleProfileWriterBinary::writeNameTable() {
Wei Mia0c08572018-06-11 22:40:43 +0000284 auto &OS = *OutputStream;
285 std::set<StringRef> V;
286 stablizeNameTable(V);
287
288 // Write out the name table.
289 encodeULEB128(NameTable.size(), OS);
290 for (auto N : V) {
291 OS << N;
292 encodeULEB128(0, OS);
293 }
294 return sampleprof_error::success;
295}
296
Wei Mi6a143252018-09-14 20:52:59 +0000297std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() {
298 auto &OS = *OutputStream;
299
300 // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable.
301 auto &OFS = static_cast<raw_fd_ostream &>(OS);
302 uint64_t FuncOffsetTableStart = OS.tell();
303 if (OFS.seek(TableOffset) == (uint64_t)-1)
304 return sampleprof_error::ostream_seek_unsupported;
305 support::endian::Writer Writer(*OutputStream, support::little);
306 Writer.write(FuncOffsetTableStart);
307 if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1)
308 return sampleprof_error::ostream_seek_unsupported;
309
310 // Write out the table size.
311 encodeULEB128(FuncOffsetTable.size(), OS);
312
313 // Write out FuncOffsetTable.
314 for (auto entry : FuncOffsetTable) {
315 writeNameIdx(entry.first);
316 encodeULEB128(entry.second, OS);
317 }
318 return sampleprof_error::success;
319}
320
Wei Mia0c08572018-06-11 22:40:43 +0000321std::error_code SampleProfileWriterCompactBinary::writeNameTable() {
322 auto &OS = *OutputStream;
323 std::set<StringRef> V;
324 stablizeNameTable(V);
325
326 // Write out the name table.
327 encodeULEB128(NameTable.size(), OS);
328 for (auto N : V) {
329 encodeULEB128(MD5Hash(N), OS);
330 }
331 return sampleprof_error::success;
332}
333
Wei Mibe907322019-08-23 19:05:30 +0000334std::error_code
335SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) {
Wei Mia0c08572018-06-11 22:40:43 +0000336 auto &OS = *OutputStream;
Diego Novillo760c5a82015-10-13 22:48:46 +0000337 // Write file magic identifier.
Wei Mibe907322019-08-23 19:05:30 +0000338 encodeULEB128(SPMagic(Format), OS);
Wei Mia0c08572018-06-11 22:40:43 +0000339 encodeULEB128(SPVersion(), OS);
340 return sampleprof_error::success;
341}
342
343std::error_code SampleProfileWriterBinary::writeHeader(
344 const StringMap<FunctionSamples> &ProfileMap) {
Wei Mibe907322019-08-23 19:05:30 +0000345 writeMagicIdent(Format);
Diego Novillo760c5a82015-10-13 22:48:46 +0000346
Easwaran Raman40ee23d2016-02-19 03:15:33 +0000347 computeSummary(ProfileMap);
348 if (auto EC = writeSummary())
349 return EC;
350
Diego Novillo760c5a82015-10-13 22:48:46 +0000351 // Generate the name table for all the functions referenced in the profile.
352 for (const auto &I : ProfileMap) {
353 addName(I.first());
354 addNames(I.second);
355 }
356
Wei Mia0c08572018-06-11 22:40:43 +0000357 writeNameTable();
Diego Novillo760c5a82015-10-13 22:48:46 +0000358 return sampleprof_error::success;
Diego Novilloc572e922014-10-30 18:00:06 +0000359}
360
Wei Mib5237902019-10-07 16:12:37 +0000361void SampleProfileWriterExtBinaryBase::setToCompressAllSections() {
362 for (auto &Entry : SectionLayout)
363 addSecFlags(Entry, SecFlagCompress);
364}
365
366void SampleProfileWriterExtBinaryBase::setToCompressSection(SecType Type) {
367 addSectionFlags(Type, SecFlagCompress);
368}
369
370void SampleProfileWriterExtBinaryBase::addSectionFlags(SecType Type,
371 SecFlags Flags) {
372 for (auto &Entry : SectionLayout) {
373 if (Entry.Type == Type)
374 addSecFlags(Entry, Flags);
375 }
376}
377
Wei Mibe907322019-08-23 19:05:30 +0000378void SampleProfileWriterExtBinaryBase::allocSecHdrTable() {
379 support::endian::Writer Writer(*OutputStream, support::little);
380
381 Writer.write(static_cast<uint64_t>(SectionLayout.size()));
382 SecHdrTableOffset = OutputStream->tell();
383 for (uint32_t i = 0; i < SectionLayout.size(); i++) {
384 Writer.write(static_cast<uint64_t>(-1));
385 Writer.write(static_cast<uint64_t>(-1));
386 Writer.write(static_cast<uint64_t>(-1));
387 Writer.write(static_cast<uint64_t>(-1));
388 }
389}
390
391std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() {
392 auto &OFS = static_cast<raw_fd_ostream &>(*OutputStream);
393 uint64_t Saved = OutputStream->tell();
394
395 // Set OutputStream to the location saved in SecHdrTableOffset.
396 if (OFS.seek(SecHdrTableOffset) == (uint64_t)-1)
397 return sampleprof_error::ostream_seek_unsupported;
398 support::endian::Writer Writer(*OutputStream, support::little);
399
400 DenseMap<uint32_t, uint32_t> IndexMap;
401 for (uint32_t i = 0; i < SecHdrTable.size(); i++) {
402 IndexMap.insert({static_cast<uint32_t>(SecHdrTable[i].Type), i});
403 }
404
405 // Write the sections in the order specified in SectionLayout.
406 // That is the sections order Reader will see. Note that the
407 // sections order in which Reader expects to read may be different
408 // from the order in which Writer is able to write, so we need
409 // to adjust the order in SecHdrTable to be consistent with
410 // SectionLayout when we write SecHdrTable to the memory.
411 for (uint32_t i = 0; i < SectionLayout.size(); i++) {
Wei Mib5237902019-10-07 16:12:37 +0000412 uint32_t idx = IndexMap[static_cast<uint32_t>(SectionLayout[i].Type)];
Wei Mibe907322019-08-23 19:05:30 +0000413 Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Type));
Wei Mib5237902019-10-07 16:12:37 +0000414 Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Flags));
Wei Mibe907322019-08-23 19:05:30 +0000415 Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Offset));
416 Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Size));
417 }
418
419 // Reset OutputStream.
420 if (OFS.seek(Saved) == (uint64_t)-1)
421 return sampleprof_error::ostream_seek_unsupported;
422
423 return sampleprof_error::success;
424}
425
426std::error_code SampleProfileWriterExtBinaryBase::writeHeader(
427 const StringMap<FunctionSamples> &ProfileMap) {
428 auto &OS = *OutputStream;
429 FileStart = OS.tell();
430 writeMagicIdent(Format);
431
Wei Mibe907322019-08-23 19:05:30 +0000432 allocSecHdrTable();
433 return sampleprof_error::success;
434}
435
Wei Mi6a143252018-09-14 20:52:59 +0000436std::error_code SampleProfileWriterCompactBinary::writeHeader(
437 const StringMap<FunctionSamples> &ProfileMap) {
438 support::endian::Writer Writer(*OutputStream, support::little);
439 if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap))
440 return EC;
441
442 // Reserve a slot for the offset of function offset table. The slot will
443 // be populated with the offset of FuncOffsetTable later.
444 TableOffset = OutputStream->tell();
445 Writer.write(static_cast<uint64_t>(-2));
446 return sampleprof_error::success;
447}
448
Easwaran Raman40ee23d2016-02-19 03:15:33 +0000449std::error_code SampleProfileWriterBinary::writeSummary() {
450 auto &OS = *OutputStream;
Easwaran Raman7cefdb82016-05-19 21:53:28 +0000451 encodeULEB128(Summary->getTotalCount(), OS);
452 encodeULEB128(Summary->getMaxCount(), OS);
Easwaran Raman6f4903d2016-03-28 23:14:29 +0000453 encodeULEB128(Summary->getMaxFunctionCount(), OS);
Easwaran Raman7cefdb82016-05-19 21:53:28 +0000454 encodeULEB128(Summary->getNumCounts(), OS);
Easwaran Raman40ee23d2016-02-19 03:15:33 +0000455 encodeULEB128(Summary->getNumFunctions(), OS);
456 std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary();
457 encodeULEB128(Entries.size(), OS);
458 for (auto Entry : Entries) {
459 encodeULEB128(Entry.Cutoff, OS);
460 encodeULEB128(Entry.MinCount, OS);
461 encodeULEB128(Entry.NumCounts, OS);
462 }
463 return sampleprof_error::success;
464}
Dehao Chen57d1dda2016-03-03 18:09:32 +0000465std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
Nathan Slingerland51abea72015-12-10 17:21:42 +0000466 auto &OS = *OutputStream;
467
Dehao Chen57d1dda2016-03-03 18:09:32 +0000468 if (std::error_code EC = writeNameIdx(S.getName()))
Diego Novillo760c5a82015-10-13 22:48:46 +0000469 return EC;
470
Diego Novilloc572e922014-10-30 18:00:06 +0000471 encodeULEB128(S.getTotalSamples(), OS);
Diego Novilloa7f1e8e2015-10-09 17:54:24 +0000472
473 // Emit all the body samples.
Diego Novillob93483d2015-10-16 18:54:35 +0000474 encodeULEB128(S.getBodySamples().size(), OS);
Diego Novillod5336ae2014-11-01 00:56:55 +0000475 for (const auto &I : S.getBodySamples()) {
476 LineLocation Loc = I.first;
477 const SampleRecord &Sample = I.second;
Diego Novilloc572e922014-10-30 18:00:06 +0000478 encodeULEB128(Loc.LineOffset, OS);
479 encodeULEB128(Loc.Discriminator, OS);
480 encodeULEB128(Sample.getSamples(), OS);
481 encodeULEB128(Sample.getCallTargets().size(), OS);
Wenlei He5adace32019-08-20 20:52:00 +0000482 for (const auto &J : Sample.getSortedCallTargets()) {
483 StringRef Callee = J.first;
Diego Novillo38be3332015-10-15 16:36:21 +0000484 uint64_t CalleeSamples = J.second;
Diego Novillo760c5a82015-10-13 22:48:46 +0000485 if (std::error_code EC = writeNameIdx(Callee))
486 return EC;
Diego Novilloc572e922014-10-30 18:00:06 +0000487 encodeULEB128(CalleeSamples, OS);
488 }
489 }
490
Diego Novilloa7f1e8e2015-10-09 17:54:24 +0000491 // Recursively emit all the callsite samples.
Dehao Chen2c27daf2017-08-03 00:09:18 +0000492 uint64_t NumCallsites = 0;
493 for (const auto &J : S.getCallsiteSamples())
494 NumCallsites += J.second.size();
495 encodeULEB128(NumCallsites, OS);
Dehao Chen2c7ca9b2017-04-13 19:52:10 +0000496 for (const auto &J : S.getCallsiteSamples())
497 for (const auto &FS : J.second) {
498 LineLocation Loc = J.first;
499 const FunctionSamples &CalleeSamples = FS.second;
500 encodeULEB128(Loc.LineOffset, OS);
501 encodeULEB128(Loc.Discriminator, OS);
502 if (std::error_code EC = writeBody(CalleeSamples))
503 return EC;
504 }
Diego Novilloa7f1e8e2015-10-09 17:54:24 +0000505
Diego Novillo760c5a82015-10-13 22:48:46 +0000506 return sampleprof_error::success;
Diego Novilloc572e922014-10-30 18:00:06 +0000507}
Diego Novillod5336ae2014-11-01 00:56:55 +0000508
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000509/// Write samples of a top-level function to a binary file.
Diego Novillob93483d2015-10-16 18:54:35 +0000510///
511/// \returns true if the samples were written successfully, false otherwise.
Wei Mibe907322019-08-23 19:05:30 +0000512std::error_code
513SampleProfileWriterBinary::writeSample(const FunctionSamples &S) {
Nathan Slingerland51abea72015-12-10 17:21:42 +0000514 encodeULEB128(S.getHeadSamples(), *OutputStream);
Dehao Chen57d1dda2016-03-03 18:09:32 +0000515 return writeBody(S);
Diego Novillob93483d2015-10-16 18:54:35 +0000516}
517
Wei Mi6a143252018-09-14 20:52:59 +0000518std::error_code
Wei Mibe907322019-08-23 19:05:30 +0000519SampleProfileWriterCompactBinary::writeSample(const FunctionSamples &S) {
Wei Mi6a143252018-09-14 20:52:59 +0000520 uint64_t Offset = OutputStream->tell();
521 StringRef Name = S.getName();
522 FuncOffsetTable[Name] = Offset;
523 encodeULEB128(S.getHeadSamples(), *OutputStream);
524 return writeBody(S);
525}
526
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000527/// Create a sample profile file writer based on the specified format.
Diego Novillod5336ae2014-11-01 00:56:55 +0000528///
529/// \param Filename The file to create.
530///
Diego Novillod5336ae2014-11-01 00:56:55 +0000531/// \param Format Encoding format for the profile file.
532///
533/// \returns an error code indicating the status of the created writer.
Diego Novillofcd55602014-11-03 00:51:45 +0000534ErrorOr<std::unique_ptr<SampleProfileWriter>>
535SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
Diego Novillod5336ae2014-11-01 00:56:55 +0000536 std::error_code EC;
Nathan Slingerland51abea72015-12-10 17:21:42 +0000537 std::unique_ptr<raw_ostream> OS;
Wei Mibe907322019-08-23 19:05:30 +0000538 if (Format == SPF_Binary || Format == SPF_Ext_Binary ||
539 Format == SPF_Compact_Binary)
Fangrui Songd9b948b2019-08-05 05:43:48 +0000540 OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None));
Nathan Slingerland51abea72015-12-10 17:21:42 +0000541 else
Fangrui Songd9b948b2019-08-05 05:43:48 +0000542 OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_Text));
Nathan Slingerland51abea72015-12-10 17:21:42 +0000543 if (EC)
544 return EC;
545
546 return create(OS, Format);
547}
548
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000549/// Create a sample profile stream writer based on the specified format.
Nathan Slingerland51abea72015-12-10 17:21:42 +0000550///
551/// \param OS The output stream to store the profile data to.
552///
Nathan Slingerland51abea72015-12-10 17:21:42 +0000553/// \param Format Encoding format for the profile file.
554///
555/// \returns an error code indicating the status of the created writer.
556ErrorOr<std::unique_ptr<SampleProfileWriter>>
557SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
558 SampleProfileFormat Format) {
559 std::error_code EC;
Diego Novillofcd55602014-11-03 00:51:45 +0000560 std::unique_ptr<SampleProfileWriter> Writer;
Diego Novillod5336ae2014-11-01 00:56:55 +0000561
Wei Mid9be2c72018-06-12 05:53:49 +0000562 if (Format == SPF_Binary)
Wei Mia0c08572018-06-11 22:40:43 +0000563 Writer.reset(new SampleProfileWriterRawBinary(OS));
Wei Mibe907322019-08-23 19:05:30 +0000564 else if (Format == SPF_Ext_Binary)
565 Writer.reset(new SampleProfileWriterExtBinary(OS));
Wei Mia0c08572018-06-11 22:40:43 +0000566 else if (Format == SPF_Compact_Binary)
567 Writer.reset(new SampleProfileWriterCompactBinary(OS));
Diego Novillod5336ae2014-11-01 00:56:55 +0000568 else if (Format == SPF_Text)
Nathan Slingerland51abea72015-12-10 17:21:42 +0000569 Writer.reset(new SampleProfileWriterText(OS));
Diego Novillo760c5a82015-10-13 22:48:46 +0000570 else if (Format == SPF_GCC)
571 EC = sampleprof_error::unsupported_writing_format;
Diego Novillod5336ae2014-11-01 00:56:55 +0000572 else
573 EC = sampleprof_error::unrecognized_format;
574
Diego Novillofcd55602014-11-03 00:51:45 +0000575 if (EC)
576 return EC;
577
Wei Mibe907322019-08-23 19:05:30 +0000578 Writer->Format = Format;
Diego Novillofcd55602014-11-03 00:51:45 +0000579 return std::move(Writer);
Diego Novillod5336ae2014-11-01 00:56:55 +0000580}
Easwaran Raman40ee23d2016-02-19 03:15:33 +0000581
582void SampleProfileWriter::computeSummary(
583 const StringMap<FunctionSamples> &ProfileMap) {
Easwaran Ramane5a17e32016-05-19 21:07:12 +0000584 SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
Easwaran Raman40ee23d2016-02-19 03:15:33 +0000585 for (const auto &I : ProfileMap) {
586 const FunctionSamples &Profile = I.second;
Easwaran Ramane5a17e32016-05-19 21:07:12 +0000587 Builder.addRecord(Profile);
Easwaran Raman40ee23d2016-02-19 03:15:33 +0000588 }
Benjamin Kramer38de59e2016-05-20 09:18:37 +0000589 Summary = Builder.getSummary();
Easwaran Raman40ee23d2016-02-19 03:15:33 +0000590}