LLVM  10.0.0svn
SampleProfWriter.cpp
Go to the documentation of this file.
1 //===- SampleProfWriter.cpp - Write LLVM sample profile data --------------===//
2 //
3 // 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
6 //
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 
21 #include "llvm/ADT/StringRef.h"
24 #include "llvm/Support/Endian.h"
26 #include "llvm/Support/ErrorOr.h"
28 #include "llvm/Support/LEB128.h"
29 #include "llvm/Support/MD5.h"
31 #include <algorithm>
32 #include <cstdint>
33 #include <memory>
34 #include <set>
35 #include <system_error>
36 #include <utility>
37 #include <vector>
38 
39 using namespace llvm;
40 using namespace sampleprof;
41 
43  const StringMap<FunctionSamples> &ProfileMap) {
44  // 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 
51  V, [](const NameFunctionSamples &A, const NameFunctionSamples &B) {
52  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) {
58  if (std::error_code EC = writeSample(*I.second))
59  return EC;
60  }
62 }
63 
64 std::error_code
66  if (std::error_code EC = writeHeader(ProfileMap))
67  return EC;
68 
69  if (std::error_code EC = writeFuncProfiles(ProfileMap))
70  return EC;
71 
73 }
74 
75 /// Return the current position and prepare to use it as the start
76 /// position of a section.
78  return OutputStream->tell();
79 }
80 
81 /// Add a new section into section header table. Return the position
82 /// of SectionEnd.
83 uint64_t
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 
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 
104 }
105 
106 std::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  SectionStart = addNewSection(SecLBRProfile, SectionStart);
125 
126  if (ProfSymList && ProfSymList->size() > 0)
127  if (std::error_code EC = ProfSymList->write(*OutputStream))
128  return EC;
129  addNewSection(SecProfileSymbolList, SectionStart);
130 
132 }
133 
135  const StringMap<FunctionSamples> &ProfileMap) {
136  if (std::error_code EC = SampleProfileWriter::write(ProfileMap))
137  return EC;
138  if (std::error_code EC = writeFuncOffsetTable())
139  return EC;
141 }
142 
143 /// Write samples to a text file.
144 ///
145 /// Note: it may be tempting to implement this in terms of
146 /// FunctionSamples::print(). Please don't. The dump functionality is intended
147 /// for debugging and has no specified form.
148 ///
149 /// The format used here is more structured and deliberate because
150 /// it needs to be parsed by the SampleProfileReaderText class.
152  auto &OS = *OutputStream;
153  OS << S.getName() << ":" << S.getTotalSamples();
154  if (Indent == 0)
155  OS << ":" << S.getHeadSamples();
156  OS << "\n";
157 
159  for (const auto &I : SortedSamples.get()) {
160  LineLocation Loc = I->first;
161  const SampleRecord &Sample = I->second;
162  OS.indent(Indent + 1);
163  if (Loc.Discriminator == 0)
164  OS << Loc.LineOffset << ": ";
165  else
166  OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
167 
168  OS << Sample.getSamples();
169 
170  for (const auto &J : Sample.getSortedCallTargets())
171  OS << " " << J.first << ":" << J.second;
172  OS << "\n";
173  }
174 
176  S.getCallsiteSamples());
177  Indent += 1;
178  for (const auto &I : SortedCallsiteSamples.get())
179  for (const auto &FS : I->second) {
180  LineLocation Loc = I->first;
181  const FunctionSamples &CalleeSamples = FS.second;
182  OS.indent(Indent);
183  if (Loc.Discriminator == 0)
184  OS << Loc.LineOffset << ": ";
185  else
186  OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
187  if (std::error_code EC = writeSample(CalleeSamples))
188  return EC;
189  }
190  Indent -= 1;
191 
193 }
194 
196  const auto &ret = NameTable.find(FName);
197  if (ret == NameTable.end())
199  encodeULEB128(ret->second, *OutputStream);
201 }
202 
204  NameTable.insert(std::make_pair(FName, 0));
205 }
206 
208  // Add all the names in indirect call targets.
209  for (const auto &I : S.getBodySamples()) {
210  const SampleRecord &Sample = I.second;
211  for (const auto &J : Sample.getCallTargets())
212  addName(J.first());
213  }
214 
215  // Recursively add all the names for inlined callsites.
216  for (const auto &J : S.getCallsiteSamples())
217  for (const auto &FS : J.second) {
218  const FunctionSamples &CalleeSamples = FS.second;
219  addName(CalleeSamples.getName());
220  addNames(CalleeSamples);
221  }
222 }
223 
224 void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) {
225  // Sort the names to make NameTable deterministic.
226  for (const auto &I : NameTable)
227  V.insert(I.first);
228  int i = 0;
229  for (const StringRef &N : V)
230  NameTable[N] = i++;
231 }
232 
234  auto &OS = *OutputStream;
235  std::set<StringRef> V;
236  stablizeNameTable(V);
237 
238  // Write out the name table.
239  encodeULEB128(NameTable.size(), OS);
240  for (auto N : V) {
241  OS << N;
242  encodeULEB128(0, OS);
243  }
245 }
246 
248  auto &OS = *OutputStream;
249 
250  // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable.
251  auto &OFS = static_cast<raw_fd_ostream &>(OS);
252  uint64_t FuncOffsetTableStart = OS.tell();
253  if (OFS.seek(TableOffset) == (uint64_t)-1)
256  Writer.write(FuncOffsetTableStart);
257  if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1)
259 
260  // Write out the table size.
261  encodeULEB128(FuncOffsetTable.size(), OS);
262 
263  // Write out FuncOffsetTable.
264  for (auto entry : FuncOffsetTable) {
265  writeNameIdx(entry.first);
266  encodeULEB128(entry.second, OS);
267  }
269 }
270 
272  auto &OS = *OutputStream;
273  std::set<StringRef> V;
274  stablizeNameTable(V);
275 
276  // Write out the name table.
277  encodeULEB128(NameTable.size(), OS);
278  for (auto N : V) {
279  encodeULEB128(MD5Hash(N), OS);
280  }
282 }
283 
284 std::error_code
286  auto &OS = *OutputStream;
287  // Write file magic identifier.
288  encodeULEB128(SPMagic(Format), OS);
289  encodeULEB128(SPVersion(), OS);
291 }
292 
294  const StringMap<FunctionSamples> &ProfileMap) {
295  writeMagicIdent(Format);
296 
297  computeSummary(ProfileMap);
298  if (auto EC = writeSummary())
299  return EC;
300 
301  // Generate the name table for all the functions referenced in the profile.
302  for (const auto &I : ProfileMap) {
303  addName(I.first());
304  addNames(I.second);
305  }
306 
307  writeNameTable();
309 }
310 
311 void SampleProfileWriterExtBinaryBase::allocSecHdrTable() {
313 
314  Writer.write(static_cast<uint64_t>(SectionLayout.size()));
315  SecHdrTableOffset = OutputStream->tell();
316  for (uint32_t i = 0; i < SectionLayout.size(); i++) {
317  Writer.write(static_cast<uint64_t>(-1));
318  Writer.write(static_cast<uint64_t>(-1));
319  Writer.write(static_cast<uint64_t>(-1));
320  Writer.write(static_cast<uint64_t>(-1));
321  }
322 }
323 
324 std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() {
325  auto &OFS = static_cast<raw_fd_ostream &>(*OutputStream);
326  uint64_t Saved = OutputStream->tell();
327 
328  // Set OutputStream to the location saved in SecHdrTableOffset.
329  if (OFS.seek(SecHdrTableOffset) == (uint64_t)-1)
332 
334  for (uint32_t i = 0; i < SecHdrTable.size(); i++) {
335  IndexMap.insert({static_cast<uint32_t>(SecHdrTable[i].Type), i});
336  }
337 
338  // Write the sections in the order specified in SectionLayout.
339  // That is the sections order Reader will see. Note that the
340  // sections order in which Reader expects to read may be different
341  // from the order in which Writer is able to write, so we need
342  // to adjust the order in SecHdrTable to be consistent with
343  // SectionLayout when we write SecHdrTable to the memory.
344  for (uint32_t i = 0; i < SectionLayout.size(); i++) {
345  uint32_t idx = IndexMap[static_cast<uint32_t>(SectionLayout[i])];
346  Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Type));
347  Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Flag));
348  Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Offset));
349  Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Size));
350  }
351 
352  // Reset OutputStream.
353  if (OFS.seek(Saved) == (uint64_t)-1)
355 
357 }
358 
359 std::error_code SampleProfileWriterExtBinaryBase::writeHeader(
360  const StringMap<FunctionSamples> &ProfileMap) {
361  auto &OS = *OutputStream;
362  FileStart = OS.tell();
363  writeMagicIdent(Format);
364 
365  initSectionLayout();
366  allocSecHdrTable();
368 }
369 
371  const StringMap<FunctionSamples> &ProfileMap) {
373  if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap))
374  return EC;
375 
376  // Reserve a slot for the offset of function offset table. The slot will
377  // be populated with the offset of FuncOffsetTable later.
378  TableOffset = OutputStream->tell();
379  Writer.write(static_cast<uint64_t>(-2));
381 }
382 
384  auto &OS = *OutputStream;
385  encodeULEB128(Summary->getTotalCount(), OS);
386  encodeULEB128(Summary->getMaxCount(), OS);
387  encodeULEB128(Summary->getMaxFunctionCount(), OS);
388  encodeULEB128(Summary->getNumCounts(), OS);
389  encodeULEB128(Summary->getNumFunctions(), OS);
390  std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary();
391  encodeULEB128(Entries.size(), OS);
392  for (auto Entry : Entries) {
393  encodeULEB128(Entry.Cutoff, OS);
394  encodeULEB128(Entry.MinCount, OS);
395  encodeULEB128(Entry.NumCounts, OS);
396  }
398 }
400  auto &OS = *OutputStream;
401 
402  if (std::error_code EC = writeNameIdx(S.getName()))
403  return EC;
404 
406 
407  // Emit all the body samples.
408  encodeULEB128(S.getBodySamples().size(), OS);
409  for (const auto &I : S.getBodySamples()) {
410  LineLocation Loc = I.first;
411  const SampleRecord &Sample = I.second;
412  encodeULEB128(Loc.LineOffset, OS);
413  encodeULEB128(Loc.Discriminator, OS);
414  encodeULEB128(Sample.getSamples(), OS);
415  encodeULEB128(Sample.getCallTargets().size(), OS);
416  for (const auto &J : Sample.getSortedCallTargets()) {
417  StringRef Callee = J.first;
418  uint64_t CalleeSamples = J.second;
419  if (std::error_code EC = writeNameIdx(Callee))
420  return EC;
421  encodeULEB128(CalleeSamples, OS);
422  }
423  }
424 
425  // Recursively emit all the callsite samples.
426  uint64_t NumCallsites = 0;
427  for (const auto &J : S.getCallsiteSamples())
428  NumCallsites += J.second.size();
429  encodeULEB128(NumCallsites, OS);
430  for (const auto &J : S.getCallsiteSamples())
431  for (const auto &FS : J.second) {
432  LineLocation Loc = J.first;
433  const FunctionSamples &CalleeSamples = FS.second;
434  encodeULEB128(Loc.LineOffset, OS);
435  encodeULEB128(Loc.Discriminator, OS);
436  if (std::error_code EC = writeBody(CalleeSamples))
437  return EC;
438  }
439 
441 }
442 
443 /// Write samples of a top-level function to a binary file.
444 ///
445 /// \returns true if the samples were written successfully, false otherwise.
446 std::error_code
449  return writeBody(S);
450 }
451 
452 std::error_code
454  uint64_t Offset = OutputStream->tell();
455  StringRef Name = S.getName();
456  FuncOffsetTable[Name] = Offset;
458  return writeBody(S);
459 }
460 
461 /// Create a sample profile file writer based on the specified format.
462 ///
463 /// \param Filename The file to create.
464 ///
465 /// \param Format Encoding format for the profile file.
466 ///
467 /// \returns an error code indicating the status of the created writer.
470  std::error_code EC;
471  std::unique_ptr<raw_ostream> OS;
472  if (Format == SPF_Binary || Format == SPF_Ext_Binary ||
473  Format == SPF_Compact_Binary)
474  OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None));
475  else
476  OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_Text));
477  if (EC)
478  return EC;
479 
480  return create(OS, Format);
481 }
482 
483 /// Create a sample profile stream writer based on the specified format.
484 ///
485 /// \param OS The output stream to store the profile data to.
486 ///
487 /// \param Format Encoding format for the profile file.
488 ///
489 /// \returns an error code indicating the status of the created writer.
491 SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
493  std::error_code EC;
494  std::unique_ptr<SampleProfileWriter> Writer;
495 
496  if (Format == SPF_Binary)
497  Writer.reset(new SampleProfileWriterRawBinary(OS));
498  else if (Format == SPF_Ext_Binary)
499  Writer.reset(new SampleProfileWriterExtBinary(OS));
500  else if (Format == SPF_Compact_Binary)
501  Writer.reset(new SampleProfileWriterCompactBinary(OS));
502  else if (Format == SPF_Text)
503  Writer.reset(new SampleProfileWriterText(OS));
504  else if (Format == SPF_GCC)
506  else
508 
509  if (EC)
510  return EC;
511 
512  Writer->Format = Format;
513  return std::move(Writer);
514 }
515 
517  const StringMap<FunctionSamples> &ProfileMap) {
519  for (const auto &I : ProfileMap) {
520  const FunctionSamples &Profile = I.second;
521  Builder.addRecord(Profile);
522  }
523  Summary = Builder.getSummary();
524 }
Represents either an error or a value T.
Definition: ErrorOr.h:56
uint64_t markSectionStart()
Return the current position and prepare to use it as the start position of a section.
This class represents lattice values for constants.
Definition: AllocatorList.h:23
virtual std::error_code write(const StringMap< FunctionSamples > &ProfileMap) override
Write all the sample profiles in the given map of samples.
amdgpu Simplify well known AMD library false FunctionCallee Value const Twine & Name
void addRecord(const sampleprof::FunctionSamples &FS, bool isCallsiteSample=false)
uint64_t MD5Hash(StringRef Str)
Helper to compute and return lower 64 bits of the given string&#39;s MD5 hash.
Definition: MD5.h:109
std::unique_ptr< raw_ostream > OutputStream
Output stream where to emit the profile to.
static const ArrayRef< uint32_t > DefaultCutoffs
A vector of useful cutoff values for detailed summary.
Definition: ProfileCommon.h:64
virtual std::error_code write(const StringMap< FunctionSamples > &ProfileMap) override
Write all the sample profiles in the given map of samples.
virtual std::error_code writeHeader(const StringMap< FunctionSamples > &ProfileMap) override
Write a file header for the profile file.
Representation of the samples collected for a function.
Definition: SampleProf.h:267
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition: DenseMap.h:195
std::error_code writeNameIdx(StringRef FName)
virtual std::error_code writeFuncProfiles(const StringMap< FunctionSamples > &ProfileMap)
unsigned size() const
Definition: StringMap.h:111
virtual std::error_code writeNameTable() override
std::error_code writeSample(const FunctionSamples &S) override
Write samples to a text file.
Representation of a single sample record.
Definition: SampleProf.h:173
virtual std::error_code writeHeader(const StringMap< FunctionSamples > &ProfileMap) override
Write a file header for the profile file.
static uint64_t SPVersion()
Definition: SampleProf.h:113
The file should be opened in text mode on platforms that make this distinction.
Definition: FileSystem.h:767
Sort a LocationT->SampleT map by LocationT.
Definition: SampleProf.h:585
uint64_t getHeadSamples() const
Return the total number of branch samples that have the function as the branch target.
Definition: SampleProf.h:378
Flag
These should be considered private to the implementation of the MCInstrDesc class.
Definition: MCInstrDesc.h:131
virtual std::error_code write(const StringMap< FunctionSamples > &ProfileMap)
Write all the sample profiles in the given map of samples.
std::unique_ptr< ProfileSummary > Summary
Profile summary.
uint64_t getSamples() const
Definition: SampleProf.h:219
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
The instances of the Type class are immutable: once they are created, they are never changed...
Definition: Type.h:45
uint64_t addNewSection(SecType Sec, uint64_t SectionStart)
Add a new section into section header table.
const BodySampleMap & getBodySamples() const
Return all the samples collected in the body of the function.
Definition: SampleProf.h:401
void stablizeNameTable(std::set< StringRef > &V)
virtual std::error_code writeSample(const FunctionSamples &S) override
Write samples of a top-level function to a binary file.
virtual std::error_code writeSample(const FunctionSamples &S)=0
Write sample profiles in S.
void write(ArrayRef< value_type > Val)
Definition: EndianStream.h:55
unsigned encodeULEB128(uint64_t Value, raw_ostream &OS, unsigned PadTo=0)
Utility function to encode a ULEB128 value to an output stream.
Definition: LEB128.h:80
static ErrorOr< std::unique_ptr< SampleProfileWriter > > create(StringRef Filename, SampleProfileFormat Format)
Profile writer factory.
SampleProfileFormat Format
Profile format.
StringMap - This is an unconventional map that is specialized for handling keys that are "strings"...
Definition: StringMap.h:219
std::error_code writeBody(const FunctionSamples &S)
amdgpu Simplify well known AMD library false FunctionCallee Callee
std::unique_ptr< ProfileSummary > getSummary()
Adapter to write values to a stream in a particular byte order.
Definition: EndianStream.h:51
A raw_ostream that writes to a file descriptor.
Definition: raw_ostream.h:384
Represents the relative location of an instruction.
Definition: SampleProf.h:146
#define I(x, y, z)
Definition: MD5.cpp:58
#define N
StringRef getName() const
Return the function name.
Definition: SampleProf.h:457
uint32_t Size
Definition: Profile.cpp:46
const CallTargetMap & getCallTargets() const
Definition: SampleProf.h:220
static uint64_t SPMagic(SampleProfileFormat Format=SPF_Binary)
Definition: SampleProf.h:96
Provides ErrorOr<T> smart pointer.
virtual std::error_code writeHeader(const StringMap< FunctionSamples > &ProfileMap)=0
Write a file header for the profile file.
void stable_sort(R &&Range)
Definition: STLExtras.h:1289
uint64_t getTotalSamples() const
Return the total number of samples collected inside the function.
Definition: SampleProf.h:371
const CallsiteSampleMap & getCallsiteSamples() const
Return all the callsite samples collected in the body of the function.
Definition: SampleProf.h:404
uint64_t tell() const
tell - Return the current offset with the file.
Definition: raw_ostream.h:111
print Instructions which execute on loop entry
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
const SortedCallTargetSet getSortedCallTargets() const
Definition: SampleProf.h:221
void computeSummary(const StringMap< FunctionSamples > &ProfileMap)
Compute summary for this profile.
virtual std::error_code writeMagicIdent(SampleProfileFormat Format)
virtual std::error_code writeSample(const FunctionSamples &S) override
Write samples of a top-level function to a binary file.
Sample-based profile writer (text format).