blob: 8d09af31f94bf30a5d5233657240aeee867bc47b [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(
Wei Mi09dcfe62019-10-09 21:36:03 +000079 SectionHdrLayout.begin(), SectionHdrLayout.end(),
Wei Mib5237902019-10-07 16:12:37 +000080 [=](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
Wei Mi09dcfe62019-10-09 21:36:03 +0000146std::error_code
147SampleProfileWriterExtBinary::writeSample(const FunctionSamples &S) {
148 uint64_t Offset = OutputStream->tell();
149 StringRef Name = S.getName();
150 FuncOffsetTable[Name] = Offset - SecLBRProfileStart;
151 encodeULEB128(S.getHeadSamples(), *OutputStream);
152 return writeBody(S);
153}
154
155std::error_code SampleProfileWriterExtBinary::writeFuncOffsetTable() {
156 auto &OS = *OutputStream;
157
158 // Write out the table size.
159 encodeULEB128(FuncOffsetTable.size(), OS);
160
161 // Write out FuncOffsetTable.
162 for (auto entry : FuncOffsetTable) {
163 writeNameIdx(entry.first);
164 encodeULEB128(entry.second, OS);
165 }
166 return sampleprof_error::success;
167}
168
Wei Mibe907322019-08-23 19:05:30 +0000169std::error_code SampleProfileWriterExtBinary::writeSections(
170 const StringMap<FunctionSamples> &ProfileMap) {
Wei Mib5237902019-10-07 16:12:37 +0000171 uint64_t SectionStart = markSectionStart(SecProfSummary);
Wei Mibe907322019-08-23 19:05:30 +0000172 computeSummary(ProfileMap);
173 if (auto EC = writeSummary())
174 return EC;
Wei Mib5237902019-10-07 16:12:37 +0000175 if (std::error_code EC = addNewSection(SecProfSummary, SectionStart))
176 return EC;
Wei Mibe907322019-08-23 19:05:30 +0000177
178 // Generate the name table for all the functions referenced in the profile.
Wei Mib5237902019-10-07 16:12:37 +0000179 SectionStart = markSectionStart(SecNameTable);
Wei Mibe907322019-08-23 19:05:30 +0000180 for (const auto &I : ProfileMap) {
181 addName(I.first());
182 addNames(I.second);
183 }
184 writeNameTable();
Wei Mib5237902019-10-07 16:12:37 +0000185 if (std::error_code EC = addNewSection(SecNameTable, SectionStart))
186 return EC;
Wei Mibe907322019-08-23 19:05:30 +0000187
Wei Mib5237902019-10-07 16:12:37 +0000188 SectionStart = markSectionStart(SecLBRProfile);
Wei Mi09dcfe62019-10-09 21:36:03 +0000189 SecLBRProfileStart = OutputStream->tell();
Wei Mibe907322019-08-23 19:05:30 +0000190 if (std::error_code EC = writeFuncProfiles(ProfileMap))
191 return EC;
Wei Mib5237902019-10-07 16:12:37 +0000192 if (std::error_code EC = addNewSection(SecLBRProfile, SectionStart))
193 return EC;
Wei Mi798e59b2019-08-31 02:27:26 +0000194
Wei Mib5237902019-10-07 16:12:37 +0000195 if (ProfSymList && ProfSymList->toCompress())
196 setToCompressSection(SecProfileSymbolList);
197
198 SectionStart = markSectionStart(SecProfileSymbolList);
Wei Mi798e59b2019-08-31 02:27:26 +0000199 if (ProfSymList && ProfSymList->size() > 0)
200 if (std::error_code EC = ProfSymList->write(*OutputStream))
201 return EC;
Wei Mib5237902019-10-07 16:12:37 +0000202 if (std::error_code EC = addNewSection(SecProfileSymbolList, SectionStart))
203 return EC;
Wei Mibe907322019-08-23 19:05:30 +0000204
Wei Mi09dcfe62019-10-09 21:36:03 +0000205 SectionStart = markSectionStart(SecFuncOffsetTable);
206 if (std::error_code EC = writeFuncOffsetTable())
207 return EC;
208 if (std::error_code EC = addNewSection(SecFuncOffsetTable, SectionStart))
209 return EC;
210
Wei Mibe907322019-08-23 19:05:30 +0000211 return sampleprof_error::success;
212}
213
Wei Mi6a143252018-09-14 20:52:59 +0000214std::error_code SampleProfileWriterCompactBinary::write(
215 const StringMap<FunctionSamples> &ProfileMap) {
216 if (std::error_code EC = SampleProfileWriter::write(ProfileMap))
217 return EC;
218 if (std::error_code EC = writeFuncOffsetTable())
219 return EC;
220 return sampleprof_error::success;
221}
222
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000223/// Write samples to a text file.
Diego Novillo8e415a82015-11-13 20:24:28 +0000224///
225/// Note: it may be tempting to implement this in terms of
Diego Novilloef548d22015-11-19 15:33:08 +0000226/// FunctionSamples::print(). Please don't. The dump functionality is intended
Diego Novillo8e415a82015-11-13 20:24:28 +0000227/// for debugging and has no specified form.
228///
229/// The format used here is more structured and deliberate because
230/// it needs to be parsed by the SampleProfileReaderText class.
Wei Mibe907322019-08-23 19:05:30 +0000231std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) {
Nathan Slingerland51abea72015-12-10 17:21:42 +0000232 auto &OS = *OutputStream;
Dehao Chen57d1dda2016-03-03 18:09:32 +0000233 OS << S.getName() << ":" << S.getTotalSamples();
Diego Novilloaae1ed82015-10-08 19:40:37 +0000234 if (Indent == 0)
235 OS << ":" << S.getHeadSamples();
236 OS << "\n";
Diego Novilloc572e922014-10-30 18:00:06 +0000237
Diego Novilloef548d22015-11-19 15:33:08 +0000238 SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples());
239 for (const auto &I : SortedSamples.get()) {
240 LineLocation Loc = I->first;
241 const SampleRecord &Sample = I->second;
Diego Novilloaae1ed82015-10-08 19:40:37 +0000242 OS.indent(Indent + 1);
Diego Novilloc572e922014-10-30 18:00:06 +0000243 if (Loc.Discriminator == 0)
244 OS << Loc.LineOffset << ": ";
245 else
246 OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
247
248 OS << Sample.getSamples();
249
Wenlei He5adace32019-08-20 20:52:00 +0000250 for (const auto &J : Sample.getSortedCallTargets())
251 OS << " " << J.first << ":" << J.second;
Diego Novilloc572e922014-10-30 18:00:06 +0000252 OS << "\n";
253 }
254
Dehao Chen2c7ca9b2017-04-13 19:52:10 +0000255 SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples(
Diego Novilloef548d22015-11-19 15:33:08 +0000256 S.getCallsiteSamples());
Diego Novilloaae1ed82015-10-08 19:40:37 +0000257 Indent += 1;
Dehao Chen2c7ca9b2017-04-13 19:52:10 +0000258 for (const auto &I : SortedCallsiteSamples.get())
259 for (const auto &FS : I->second) {
260 LineLocation Loc = I->first;
261 const FunctionSamples &CalleeSamples = FS.second;
262 OS.indent(Indent);
263 if (Loc.Discriminator == 0)
264 OS << Loc.LineOffset << ": ";
265 else
266 OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
Wei Mibe907322019-08-23 19:05:30 +0000267 if (std::error_code EC = writeSample(CalleeSamples))
Dehao Chen2c7ca9b2017-04-13 19:52:10 +0000268 return EC;
269 }
Diego Novilloaae1ed82015-10-08 19:40:37 +0000270 Indent -= 1;
271
Diego Novillo760c5a82015-10-13 22:48:46 +0000272 return sampleprof_error::success;
Diego Novilloc572e922014-10-30 18:00:06 +0000273}
274
Diego Novillo760c5a82015-10-13 22:48:46 +0000275std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) {
276 const auto &ret = NameTable.find(FName);
277 if (ret == NameTable.end())
278 return sampleprof_error::truncated_name_table;
Nathan Slingerland51abea72015-12-10 17:21:42 +0000279 encodeULEB128(ret->second, *OutputStream);
Diego Novillo760c5a82015-10-13 22:48:46 +0000280 return sampleprof_error::success;
281}
Diego Novilloc572e922014-10-30 18:00:06 +0000282
Diego Novillo760c5a82015-10-13 22:48:46 +0000283void SampleProfileWriterBinary::addName(StringRef FName) {
Dehao Chen8d1c9832017-05-11 23:43:44 +0000284 NameTable.insert(std::make_pair(FName, 0));
Diego Novillo760c5a82015-10-13 22:48:46 +0000285}
286
287void SampleProfileWriterBinary::addNames(const FunctionSamples &S) {
288 // Add all the names in indirect call targets.
289 for (const auto &I : S.getBodySamples()) {
290 const SampleRecord &Sample = I.second;
291 for (const auto &J : Sample.getCallTargets())
292 addName(J.first());
293 }
294
295 // Recursively add all the names for inlined callsites.
Dehao Chen2c7ca9b2017-04-13 19:52:10 +0000296 for (const auto &J : S.getCallsiteSamples())
297 for (const auto &FS : J.second) {
298 const FunctionSamples &CalleeSamples = FS.second;
299 addName(CalleeSamples.getName());
300 addNames(CalleeSamples);
301 }
Diego Novillo760c5a82015-10-13 22:48:46 +0000302}
303
Wei Mia0c08572018-06-11 22:40:43 +0000304void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) {
305 // Sort the names to make NameTable deterministic.
306 for (const auto &I : NameTable)
307 V.insert(I.first);
308 int i = 0;
309 for (const StringRef &N : V)
310 NameTable[N] = i++;
311}
Nathan Slingerland51abea72015-12-10 17:21:42 +0000312
Wei Mibe907322019-08-23 19:05:30 +0000313std::error_code SampleProfileWriterBinary::writeNameTable() {
Wei Mia0c08572018-06-11 22:40:43 +0000314 auto &OS = *OutputStream;
315 std::set<StringRef> V;
316 stablizeNameTable(V);
317
318 // Write out the name table.
319 encodeULEB128(NameTable.size(), OS);
320 for (auto N : V) {
321 OS << N;
322 encodeULEB128(0, OS);
323 }
324 return sampleprof_error::success;
325}
326
Wei Mi6a143252018-09-14 20:52:59 +0000327std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() {
328 auto &OS = *OutputStream;
329
330 // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable.
331 auto &OFS = static_cast<raw_fd_ostream &>(OS);
332 uint64_t FuncOffsetTableStart = OS.tell();
333 if (OFS.seek(TableOffset) == (uint64_t)-1)
334 return sampleprof_error::ostream_seek_unsupported;
335 support::endian::Writer Writer(*OutputStream, support::little);
336 Writer.write(FuncOffsetTableStart);
337 if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1)
338 return sampleprof_error::ostream_seek_unsupported;
339
340 // Write out the table size.
341 encodeULEB128(FuncOffsetTable.size(), OS);
342
343 // Write out FuncOffsetTable.
344 for (auto entry : FuncOffsetTable) {
345 writeNameIdx(entry.first);
346 encodeULEB128(entry.second, OS);
347 }
348 return sampleprof_error::success;
349}
350
Wei Mia0c08572018-06-11 22:40:43 +0000351std::error_code SampleProfileWriterCompactBinary::writeNameTable() {
352 auto &OS = *OutputStream;
353 std::set<StringRef> V;
354 stablizeNameTable(V);
355
356 // Write out the name table.
357 encodeULEB128(NameTable.size(), OS);
358 for (auto N : V) {
359 encodeULEB128(MD5Hash(N), OS);
360 }
361 return sampleprof_error::success;
362}
363
Wei Mibe907322019-08-23 19:05:30 +0000364std::error_code
365SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) {
Wei Mia0c08572018-06-11 22:40:43 +0000366 auto &OS = *OutputStream;
Diego Novillo760c5a82015-10-13 22:48:46 +0000367 // Write file magic identifier.
Wei Mibe907322019-08-23 19:05:30 +0000368 encodeULEB128(SPMagic(Format), OS);
Wei Mia0c08572018-06-11 22:40:43 +0000369 encodeULEB128(SPVersion(), OS);
370 return sampleprof_error::success;
371}
372
373std::error_code SampleProfileWriterBinary::writeHeader(
374 const StringMap<FunctionSamples> &ProfileMap) {
Wei Mibe907322019-08-23 19:05:30 +0000375 writeMagicIdent(Format);
Diego Novillo760c5a82015-10-13 22:48:46 +0000376
Easwaran Raman40ee23d2016-02-19 03:15:33 +0000377 computeSummary(ProfileMap);
378 if (auto EC = writeSummary())
379 return EC;
380
Diego Novillo760c5a82015-10-13 22:48:46 +0000381 // Generate the name table for all the functions referenced in the profile.
382 for (const auto &I : ProfileMap) {
383 addName(I.first());
384 addNames(I.second);
385 }
386
Wei Mia0c08572018-06-11 22:40:43 +0000387 writeNameTable();
Diego Novillo760c5a82015-10-13 22:48:46 +0000388 return sampleprof_error::success;
Diego Novilloc572e922014-10-30 18:00:06 +0000389}
390
Wei Mib5237902019-10-07 16:12:37 +0000391void SampleProfileWriterExtBinaryBase::setToCompressAllSections() {
Wei Mi09dcfe62019-10-09 21:36:03 +0000392 for (auto &Entry : SectionHdrLayout)
Wei Mib5237902019-10-07 16:12:37 +0000393 addSecFlags(Entry, SecFlagCompress);
394}
395
396void SampleProfileWriterExtBinaryBase::setToCompressSection(SecType Type) {
397 addSectionFlags(Type, SecFlagCompress);
398}
399
400void SampleProfileWriterExtBinaryBase::addSectionFlags(SecType Type,
401 SecFlags Flags) {
Wei Mi09dcfe62019-10-09 21:36:03 +0000402 for (auto &Entry : SectionHdrLayout) {
Wei Mib5237902019-10-07 16:12:37 +0000403 if (Entry.Type == Type)
404 addSecFlags(Entry, Flags);
405 }
406}
407
Wei Mibe907322019-08-23 19:05:30 +0000408void SampleProfileWriterExtBinaryBase::allocSecHdrTable() {
409 support::endian::Writer Writer(*OutputStream, support::little);
410
Wei Mi09dcfe62019-10-09 21:36:03 +0000411 Writer.write(static_cast<uint64_t>(SectionHdrLayout.size()));
Wei Mibe907322019-08-23 19:05:30 +0000412 SecHdrTableOffset = OutputStream->tell();
Wei Mi09dcfe62019-10-09 21:36:03 +0000413 for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) {
Wei Mibe907322019-08-23 19:05:30 +0000414 Writer.write(static_cast<uint64_t>(-1));
415 Writer.write(static_cast<uint64_t>(-1));
416 Writer.write(static_cast<uint64_t>(-1));
417 Writer.write(static_cast<uint64_t>(-1));
418 }
419}
420
421std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() {
422 auto &OFS = static_cast<raw_fd_ostream &>(*OutputStream);
423 uint64_t Saved = OutputStream->tell();
424
425 // Set OutputStream to the location saved in SecHdrTableOffset.
426 if (OFS.seek(SecHdrTableOffset) == (uint64_t)-1)
427 return sampleprof_error::ostream_seek_unsupported;
428 support::endian::Writer Writer(*OutputStream, support::little);
429
430 DenseMap<uint32_t, uint32_t> IndexMap;
431 for (uint32_t i = 0; i < SecHdrTable.size(); i++) {
432 IndexMap.insert({static_cast<uint32_t>(SecHdrTable[i].Type), i});
433 }
434
Wei Mi09dcfe62019-10-09 21:36:03 +0000435 // Write the section header table in the order specified in
436 // SectionHdrLayout. That is the sections order Reader will see.
437 // Note that the sections order in which Reader expects to read
438 // may be different from the order in which Writer is able to
439 // write, so we need to adjust the order in SecHdrTable to be
440 // consistent with SectionHdrLayout when we write SecHdrTable
441 // to the memory.
442 for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) {
443 uint32_t idx = IndexMap[static_cast<uint32_t>(SectionHdrLayout[i].Type)];
Wei Mibe907322019-08-23 19:05:30 +0000444 Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Type));
Wei Mib5237902019-10-07 16:12:37 +0000445 Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Flags));
Wei Mibe907322019-08-23 19:05:30 +0000446 Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Offset));
447 Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Size));
448 }
449
450 // Reset OutputStream.
451 if (OFS.seek(Saved) == (uint64_t)-1)
452 return sampleprof_error::ostream_seek_unsupported;
453
454 return sampleprof_error::success;
455}
456
457std::error_code SampleProfileWriterExtBinaryBase::writeHeader(
458 const StringMap<FunctionSamples> &ProfileMap) {
459 auto &OS = *OutputStream;
460 FileStart = OS.tell();
461 writeMagicIdent(Format);
462
Wei Mibe907322019-08-23 19:05:30 +0000463 allocSecHdrTable();
464 return sampleprof_error::success;
465}
466
Wei Mi6a143252018-09-14 20:52:59 +0000467std::error_code SampleProfileWriterCompactBinary::writeHeader(
468 const StringMap<FunctionSamples> &ProfileMap) {
469 support::endian::Writer Writer(*OutputStream, support::little);
470 if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap))
471 return EC;
472
473 // Reserve a slot for the offset of function offset table. The slot will
474 // be populated with the offset of FuncOffsetTable later.
475 TableOffset = OutputStream->tell();
476 Writer.write(static_cast<uint64_t>(-2));
477 return sampleprof_error::success;
478}
479
Easwaran Raman40ee23d2016-02-19 03:15:33 +0000480std::error_code SampleProfileWriterBinary::writeSummary() {
481 auto &OS = *OutputStream;
Easwaran Raman7cefdb82016-05-19 21:53:28 +0000482 encodeULEB128(Summary->getTotalCount(), OS);
483 encodeULEB128(Summary->getMaxCount(), OS);
Easwaran Raman6f4903d2016-03-28 23:14:29 +0000484 encodeULEB128(Summary->getMaxFunctionCount(), OS);
Easwaran Raman7cefdb82016-05-19 21:53:28 +0000485 encodeULEB128(Summary->getNumCounts(), OS);
Easwaran Raman40ee23d2016-02-19 03:15:33 +0000486 encodeULEB128(Summary->getNumFunctions(), OS);
487 std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary();
488 encodeULEB128(Entries.size(), OS);
489 for (auto Entry : Entries) {
490 encodeULEB128(Entry.Cutoff, OS);
491 encodeULEB128(Entry.MinCount, OS);
492 encodeULEB128(Entry.NumCounts, OS);
493 }
494 return sampleprof_error::success;
495}
Dehao Chen57d1dda2016-03-03 18:09:32 +0000496std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
Nathan Slingerland51abea72015-12-10 17:21:42 +0000497 auto &OS = *OutputStream;
498
Dehao Chen57d1dda2016-03-03 18:09:32 +0000499 if (std::error_code EC = writeNameIdx(S.getName()))
Diego Novillo760c5a82015-10-13 22:48:46 +0000500 return EC;
501
Diego Novilloc572e922014-10-30 18:00:06 +0000502 encodeULEB128(S.getTotalSamples(), OS);
Diego Novilloa7f1e8e2015-10-09 17:54:24 +0000503
504 // Emit all the body samples.
Diego Novillob93483d2015-10-16 18:54:35 +0000505 encodeULEB128(S.getBodySamples().size(), OS);
Diego Novillod5336ae2014-11-01 00:56:55 +0000506 for (const auto &I : S.getBodySamples()) {
507 LineLocation Loc = I.first;
508 const SampleRecord &Sample = I.second;
Diego Novilloc572e922014-10-30 18:00:06 +0000509 encodeULEB128(Loc.LineOffset, OS);
510 encodeULEB128(Loc.Discriminator, OS);
511 encodeULEB128(Sample.getSamples(), OS);
512 encodeULEB128(Sample.getCallTargets().size(), OS);
Wenlei He5adace32019-08-20 20:52:00 +0000513 for (const auto &J : Sample.getSortedCallTargets()) {
514 StringRef Callee = J.first;
Diego Novillo38be3332015-10-15 16:36:21 +0000515 uint64_t CalleeSamples = J.second;
Diego Novillo760c5a82015-10-13 22:48:46 +0000516 if (std::error_code EC = writeNameIdx(Callee))
517 return EC;
Diego Novilloc572e922014-10-30 18:00:06 +0000518 encodeULEB128(CalleeSamples, OS);
519 }
520 }
521
Diego Novilloa7f1e8e2015-10-09 17:54:24 +0000522 // Recursively emit all the callsite samples.
Dehao Chen2c27daf2017-08-03 00:09:18 +0000523 uint64_t NumCallsites = 0;
524 for (const auto &J : S.getCallsiteSamples())
525 NumCallsites += J.second.size();
526 encodeULEB128(NumCallsites, OS);
Dehao Chen2c7ca9b2017-04-13 19:52:10 +0000527 for (const auto &J : S.getCallsiteSamples())
528 for (const auto &FS : J.second) {
529 LineLocation Loc = J.first;
530 const FunctionSamples &CalleeSamples = FS.second;
531 encodeULEB128(Loc.LineOffset, OS);
532 encodeULEB128(Loc.Discriminator, OS);
533 if (std::error_code EC = writeBody(CalleeSamples))
534 return EC;
535 }
Diego Novilloa7f1e8e2015-10-09 17:54:24 +0000536
Diego Novillo760c5a82015-10-13 22:48:46 +0000537 return sampleprof_error::success;
Diego Novilloc572e922014-10-30 18:00:06 +0000538}
Diego Novillod5336ae2014-11-01 00:56:55 +0000539
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000540/// Write samples of a top-level function to a binary file.
Diego Novillob93483d2015-10-16 18:54:35 +0000541///
542/// \returns true if the samples were written successfully, false otherwise.
Wei Mibe907322019-08-23 19:05:30 +0000543std::error_code
544SampleProfileWriterBinary::writeSample(const FunctionSamples &S) {
Nathan Slingerland51abea72015-12-10 17:21:42 +0000545 encodeULEB128(S.getHeadSamples(), *OutputStream);
Dehao Chen57d1dda2016-03-03 18:09:32 +0000546 return writeBody(S);
Diego Novillob93483d2015-10-16 18:54:35 +0000547}
548
Wei Mi6a143252018-09-14 20:52:59 +0000549std::error_code
Wei Mibe907322019-08-23 19:05:30 +0000550SampleProfileWriterCompactBinary::writeSample(const FunctionSamples &S) {
Wei Mi6a143252018-09-14 20:52:59 +0000551 uint64_t Offset = OutputStream->tell();
552 StringRef Name = S.getName();
553 FuncOffsetTable[Name] = Offset;
554 encodeULEB128(S.getHeadSamples(), *OutputStream);
555 return writeBody(S);
556}
557
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000558/// Create a sample profile file writer based on the specified format.
Diego Novillod5336ae2014-11-01 00:56:55 +0000559///
560/// \param Filename The file to create.
561///
Diego Novillod5336ae2014-11-01 00:56:55 +0000562/// \param Format Encoding format for the profile file.
563///
564/// \returns an error code indicating the status of the created writer.
Diego Novillofcd55602014-11-03 00:51:45 +0000565ErrorOr<std::unique_ptr<SampleProfileWriter>>
566SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
Diego Novillod5336ae2014-11-01 00:56:55 +0000567 std::error_code EC;
Nathan Slingerland51abea72015-12-10 17:21:42 +0000568 std::unique_ptr<raw_ostream> OS;
Wei Mibe907322019-08-23 19:05:30 +0000569 if (Format == SPF_Binary || Format == SPF_Ext_Binary ||
570 Format == SPF_Compact_Binary)
Fangrui Songd9b948b2019-08-05 05:43:48 +0000571 OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None));
Nathan Slingerland51abea72015-12-10 17:21:42 +0000572 else
Fangrui Songd9b948b2019-08-05 05:43:48 +0000573 OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_Text));
Nathan Slingerland51abea72015-12-10 17:21:42 +0000574 if (EC)
575 return EC;
576
577 return create(OS, Format);
578}
579
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000580/// Create a sample profile stream writer based on the specified format.
Nathan Slingerland51abea72015-12-10 17:21:42 +0000581///
582/// \param OS The output stream to store the profile data to.
583///
Nathan Slingerland51abea72015-12-10 17:21:42 +0000584/// \param Format Encoding format for the profile file.
585///
586/// \returns an error code indicating the status of the created writer.
587ErrorOr<std::unique_ptr<SampleProfileWriter>>
588SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
589 SampleProfileFormat Format) {
590 std::error_code EC;
Diego Novillofcd55602014-11-03 00:51:45 +0000591 std::unique_ptr<SampleProfileWriter> Writer;
Diego Novillod5336ae2014-11-01 00:56:55 +0000592
Wei Mid9be2c72018-06-12 05:53:49 +0000593 if (Format == SPF_Binary)
Wei Mia0c08572018-06-11 22:40:43 +0000594 Writer.reset(new SampleProfileWriterRawBinary(OS));
Wei Mibe907322019-08-23 19:05:30 +0000595 else if (Format == SPF_Ext_Binary)
596 Writer.reset(new SampleProfileWriterExtBinary(OS));
Wei Mia0c08572018-06-11 22:40:43 +0000597 else if (Format == SPF_Compact_Binary)
598 Writer.reset(new SampleProfileWriterCompactBinary(OS));
Diego Novillod5336ae2014-11-01 00:56:55 +0000599 else if (Format == SPF_Text)
Nathan Slingerland51abea72015-12-10 17:21:42 +0000600 Writer.reset(new SampleProfileWriterText(OS));
Diego Novillo760c5a82015-10-13 22:48:46 +0000601 else if (Format == SPF_GCC)
602 EC = sampleprof_error::unsupported_writing_format;
Diego Novillod5336ae2014-11-01 00:56:55 +0000603 else
604 EC = sampleprof_error::unrecognized_format;
605
Diego Novillofcd55602014-11-03 00:51:45 +0000606 if (EC)
607 return EC;
608
Wei Mibe907322019-08-23 19:05:30 +0000609 Writer->Format = Format;
Diego Novillofcd55602014-11-03 00:51:45 +0000610 return std::move(Writer);
Diego Novillod5336ae2014-11-01 00:56:55 +0000611}
Easwaran Raman40ee23d2016-02-19 03:15:33 +0000612
613void SampleProfileWriter::computeSummary(
614 const StringMap<FunctionSamples> &ProfileMap) {
Easwaran Ramane5a17e32016-05-19 21:07:12 +0000615 SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
Easwaran Raman40ee23d2016-02-19 03:15:33 +0000616 for (const auto &I : ProfileMap) {
617 const FunctionSamples &Profile = I.second;
Easwaran Ramane5a17e32016-05-19 21:07:12 +0000618 Builder.addRecord(Profile);
Easwaran Raman40ee23d2016-02-19 03:15:33 +0000619 }
Benjamin Kramer38de59e2016-05-20 09:18:37 +0000620 Summary = Builder.getSummary();
Easwaran Raman40ee23d2016-02-19 03:15:33 +0000621}