LLVM  8.0.1
SampleProfWriter.cpp
Go to the documentation of this file.
1 //===- SampleProfWriter.cpp - Write LLVM sample profile data --------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the class that writes LLVM sample profiles. It
11 // supports two file formats: text and binary. The textual representation
12 // is useful for debugging and testing purposes. The binary representation
13 // is more compact, resulting in smaller file sizes. However, they can
14 // both be used interchangeably.
15 //
16 // See lib/ProfileData/SampleProfReader.cpp for documentation on each of the
17 // supported formats.
18 //
19 //===----------------------------------------------------------------------===//
20 
22 #include "llvm/ADT/StringRef.h"
25 #include "llvm/Support/Endian.h"
27 #include "llvm/Support/ErrorOr.h"
29 #include "llvm/Support/LEB128.h"
30 #include "llvm/Support/MD5.h"
32 #include <algorithm>
33 #include <cstdint>
34 #include <memory>
35 #include <set>
36 #include <system_error>
37 #include <utility>
38 #include <vector>
39 
40 using namespace llvm;
41 using namespace sampleprof;
42 
43 std::error_code
45  if (std::error_code EC = writeHeader(ProfileMap))
46  return EC;
47 
48  // Sort the ProfileMap by total samples.
49  typedef std::pair<StringRef, const FunctionSamples *> NameFunctionSamples;
50  std::vector<NameFunctionSamples> V;
51  for (const auto &I : ProfileMap)
52  V.push_back(std::make_pair(I.getKey(), &I.second));
53 
54  std::stable_sort(
55  V.begin(), V.end(),
56  [](const NameFunctionSamples &A, const NameFunctionSamples &B) {
57  if (A.second->getTotalSamples() == B.second->getTotalSamples())
58  return A.first > B.first;
59  return A.second->getTotalSamples() > B.second->getTotalSamples();
60  });
61 
62  for (const auto &I : V) {
63  if (std::error_code EC = write(*I.second))
64  return EC;
65  }
67 }
68 
70  const StringMap<FunctionSamples> &ProfileMap) {
71  if (std::error_code EC = SampleProfileWriter::write(ProfileMap))
72  return EC;
73  if (std::error_code EC = writeFuncOffsetTable())
74  return EC;
76 }
77 
78 /// Write samples to a text file.
79 ///
80 /// Note: it may be tempting to implement this in terms of
81 /// FunctionSamples::print(). Please don't. The dump functionality is intended
82 /// for debugging and has no specified form.
83 ///
84 /// The format used here is more structured and deliberate because
85 /// it needs to be parsed by the SampleProfileReaderText class.
87  auto &OS = *OutputStream;
88  OS << S.getName() << ":" << S.getTotalSamples();
89  if (Indent == 0)
90  OS << ":" << S.getHeadSamples();
91  OS << "\n";
92 
94  for (const auto &I : SortedSamples.get()) {
95  LineLocation Loc = I->first;
96  const SampleRecord &Sample = I->second;
97  OS.indent(Indent + 1);
98  if (Loc.Discriminator == 0)
99  OS << Loc.LineOffset << ": ";
100  else
101  OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
102 
103  OS << Sample.getSamples();
104 
105  for (const auto &J : Sample.getCallTargets())
106  OS << " " << J.first() << ":" << J.second;
107  OS << "\n";
108  }
109 
111  S.getCallsiteSamples());
112  Indent += 1;
113  for (const auto &I : SortedCallsiteSamples.get())
114  for (const auto &FS : I->second) {
115  LineLocation Loc = I->first;
116  const FunctionSamples &CalleeSamples = FS.second;
117  OS.indent(Indent);
118  if (Loc.Discriminator == 0)
119  OS << Loc.LineOffset << ": ";
120  else
121  OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
122  if (std::error_code EC = write(CalleeSamples))
123  return EC;
124  }
125  Indent -= 1;
126 
128 }
129 
131  const auto &ret = NameTable.find(FName);
132  if (ret == NameTable.end())
134  encodeULEB128(ret->second, *OutputStream);
136 }
137 
138 void SampleProfileWriterBinary::addName(StringRef FName) {
139  NameTable.insert(std::make_pair(FName, 0));
140 }
141 
142 void SampleProfileWriterBinary::addNames(const FunctionSamples &S) {
143  // Add all the names in indirect call targets.
144  for (const auto &I : S.getBodySamples()) {
145  const SampleRecord &Sample = I.second;
146  for (const auto &J : Sample.getCallTargets())
147  addName(J.first());
148  }
149 
150  // Recursively add all the names for inlined callsites.
151  for (const auto &J : S.getCallsiteSamples())
152  for (const auto &FS : J.second) {
153  const FunctionSamples &CalleeSamples = FS.second;
154  addName(CalleeSamples.getName());
155  addNames(CalleeSamples);
156  }
157 }
158 
159 void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) {
160  // Sort the names to make NameTable deterministic.
161  for (const auto &I : NameTable)
162  V.insert(I.first);
163  int i = 0;
164  for (const StringRef &N : V)
165  NameTable[N] = i++;
166 }
167 
169  auto &OS = *OutputStream;
170  std::set<StringRef> V;
171  stablizeNameTable(V);
172 
173  // Write out the name table.
174  encodeULEB128(NameTable.size(), OS);
175  for (auto N : V) {
176  OS << N;
177  encodeULEB128(0, OS);
178  }
180 }
181 
183  auto &OS = *OutputStream;
184 
185  // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable.
186  auto &OFS = static_cast<raw_fd_ostream &>(OS);
187  uint64_t FuncOffsetTableStart = OS.tell();
188  if (OFS.seek(TableOffset) == (uint64_t)-1)
191  Writer.write(FuncOffsetTableStart);
192  if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1)
194 
195  // Write out the table size.
196  encodeULEB128(FuncOffsetTable.size(), OS);
197 
198  // Write out FuncOffsetTable.
199  for (auto entry : FuncOffsetTable) {
200  writeNameIdx(entry.first);
201  encodeULEB128(entry.second, OS);
202  }
204 }
205 
207  auto &OS = *OutputStream;
208  std::set<StringRef> V;
209  stablizeNameTable(V);
210 
211  // Write out the name table.
212  encodeULEB128(NameTable.size(), OS);
213  for (auto N : V) {
214  encodeULEB128(MD5Hash(N), OS);
215  }
217 }
218 
220  auto &OS = *OutputStream;
221  // Write file magic identifier.
222  encodeULEB128(SPMagic(), OS);
223  encodeULEB128(SPVersion(), OS);
225 }
226 
228  auto &OS = *OutputStream;
229  // Write file magic identifier.
231  encodeULEB128(SPVersion(), OS);
233 }
234 
236  const StringMap<FunctionSamples> &ProfileMap) {
237  writeMagicIdent();
238 
239  computeSummary(ProfileMap);
240  if (auto EC = writeSummary())
241  return EC;
242 
243  // Generate the name table for all the functions referenced in the profile.
244  for (const auto &I : ProfileMap) {
245  addName(I.first());
246  addNames(I.second);
247  }
248 
249  writeNameTable();
251 }
252 
254  const StringMap<FunctionSamples> &ProfileMap) {
256  if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap))
257  return EC;
258 
259  // Reserve a slot for the offset of function offset table. The slot will
260  // be populated with the offset of FuncOffsetTable later.
261  TableOffset = OutputStream->tell();
262  Writer.write(static_cast<uint64_t>(-2));
264 }
265 
267  auto &OS = *OutputStream;
268  encodeULEB128(Summary->getTotalCount(), OS);
269  encodeULEB128(Summary->getMaxCount(), OS);
270  encodeULEB128(Summary->getMaxFunctionCount(), OS);
271  encodeULEB128(Summary->getNumCounts(), OS);
272  encodeULEB128(Summary->getNumFunctions(), OS);
273  std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary();
274  encodeULEB128(Entries.size(), OS);
275  for (auto Entry : Entries) {
276  encodeULEB128(Entry.Cutoff, OS);
277  encodeULEB128(Entry.MinCount, OS);
278  encodeULEB128(Entry.NumCounts, OS);
279  }
281 }
283  auto &OS = *OutputStream;
284 
285  if (std::error_code EC = writeNameIdx(S.getName()))
286  return EC;
287 
289 
290  // Emit all the body samples.
291  encodeULEB128(S.getBodySamples().size(), OS);
292  for (const auto &I : S.getBodySamples()) {
293  LineLocation Loc = I.first;
294  const SampleRecord &Sample = I.second;
295  encodeULEB128(Loc.LineOffset, OS);
296  encodeULEB128(Loc.Discriminator, OS);
297  encodeULEB128(Sample.getSamples(), OS);
298  encodeULEB128(Sample.getCallTargets().size(), OS);
299  for (const auto &J : Sample.getCallTargets()) {
300  StringRef Callee = J.first();
301  uint64_t CalleeSamples = J.second;
302  if (std::error_code EC = writeNameIdx(Callee))
303  return EC;
304  encodeULEB128(CalleeSamples, OS);
305  }
306  }
307 
308  // Recursively emit all the callsite samples.
309  uint64_t NumCallsites = 0;
310  for (const auto &J : S.getCallsiteSamples())
311  NumCallsites += J.second.size();
312  encodeULEB128(NumCallsites, OS);
313  for (const auto &J : S.getCallsiteSamples())
314  for (const auto &FS : J.second) {
315  LineLocation Loc = J.first;
316  const FunctionSamples &CalleeSamples = FS.second;
317  encodeULEB128(Loc.LineOffset, OS);
318  encodeULEB128(Loc.Discriminator, OS);
319  if (std::error_code EC = writeBody(CalleeSamples))
320  return EC;
321  }
322 
324 }
325 
326 /// Write samples of a top-level function to a binary file.
327 ///
328 /// \returns true if the samples were written successfully, false otherwise.
331  return writeBody(S);
332 }
333 
334 std::error_code
336  uint64_t Offset = OutputStream->tell();
337  StringRef Name = S.getName();
338  FuncOffsetTable[Name] = Offset;
340  return writeBody(S);
341 }
342 
343 /// Create a sample profile file writer based on the specified format.
344 ///
345 /// \param Filename The file to create.
346 ///
347 /// \param Format Encoding format for the profile file.
348 ///
349 /// \returns an error code indicating the status of the created writer.
352  std::error_code EC;
353  std::unique_ptr<raw_ostream> OS;
354  if (Format == SPF_Binary || Format == SPF_Compact_Binary)
355  OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::F_None));
356  else
357  OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::F_Text));
358  if (EC)
359  return EC;
360 
361  return create(OS, Format);
362 }
363 
364 /// Create a sample profile stream writer based on the specified format.
365 ///
366 /// \param OS The output stream to store the profile data to.
367 ///
368 /// \param Format Encoding format for the profile file.
369 ///
370 /// \returns an error code indicating the status of the created writer.
372 SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
373  SampleProfileFormat Format) {
374  std::error_code EC;
375  std::unique_ptr<SampleProfileWriter> Writer;
376 
377  if (Format == SPF_Binary)
378  Writer.reset(new SampleProfileWriterRawBinary(OS));
379  else if (Format == SPF_Compact_Binary)
380  Writer.reset(new SampleProfileWriterCompactBinary(OS));
381  else if (Format == SPF_Text)
382  Writer.reset(new SampleProfileWriterText(OS));
383  else if (Format == SPF_GCC)
385  else
387 
388  if (EC)
389  return EC;
390 
391  return std::move(Writer);
392 }
393 
395  const StringMap<FunctionSamples> &ProfileMap) {
397  for (const auto &I : ProfileMap) {
398  const FunctionSamples &Profile = I.second;
399  Builder.addRecord(Profile);
400  }
401  Summary = Builder.getSummary();
402 }
virtual std::error_code writeMagicIdent() override
Represents either an error or a value T.
Definition: ErrorOr.h:57
This class represents lattice values for constants.
Definition: AllocatorList.h:24
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:65
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:217
amdgpu Simplify well known AMD library false Value Value const Twine & Name
std::error_code writeNameIdx(StringRef FName)
unsigned size() const
Definition: StringMap.h:112
virtual std::error_code writeMagicIdent() override
virtual std::error_code writeNameTable() override
Representation of a single sample record.
Definition: SampleProf.h:145
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:107
amdgpu Simplify well known AMD library false Value * Callee
Sort a LocationT->SampleT map by LocationT.
Definition: SampleProf.h:542
uint64_t getHeadSamples() const
Return the total number of branch samples that have the function as the branch target.
Definition: SampleProf.h:328
virtual std::error_code writeNameTable() override
std::unique_ptr< ProfileSummary > Summary
Profile summary.
uint64_t getSamples() const
Definition: SampleProf.h:181
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
const BodySampleMap & getBodySamples() const
Return all the samples collected in the body of the function.
Definition: SampleProf.h:351
virtual std::error_code write(const FunctionSamples &S) override
Write samples of a top-level function to a binary file.
virtual std::error_code write(const FunctionSamples &S) override
Write samples of a top-level function to a binary file.
void stablizeNameTable(std::set< StringRef > &V)
virtual std::error_code write(const FunctionSamples &S)=0
Write sample profiles in S.
void write(ArrayRef< value_type > Val)
Definition: EndianStream.h:56
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:81
static ErrorOr< std::unique_ptr< SampleProfileWriter > > create(StringRef Filename, SampleProfileFormat Format)
Profile writer factory.
void addRecord(const sampleprof::FunctionSamples &FS)
StringMap - This is an unconventional map that is specialized for handling keys that are "strings"...
Definition: StringMap.h:220
std::error_code writeBody(const FunctionSamples &S)
std::unique_ptr< ProfileSummary > getSummary()
Adapter to write values to a stream in a particular byte order.
Definition: EndianStream.h:52
A raw_ostream that writes to a file descriptor.
Definition: raw_ostream.h:366
Represents the relative location of an instruction.
Definition: SampleProf.h:118
#define I(x, y, z)
Definition: MD5.cpp:58
#define N
StringRef getName() const
Return the function name.
Definition: SampleProf.h:407
const CallTargetMap & getCallTargets() const
Definition: SampleProf.h:182
static uint64_t SPMagic(SampleProfileFormat Format=SPF_Binary)
Definition: SampleProf.h:90
Provides ErrorOr<T> smart pointer.
virtual std::error_code writeHeader(const StringMap< FunctionSamples > &ProfileMap)=0
Write a file header for the profile file.
Definition: JSON.cpp:598
uint64_t getTotalSamples() const
Return the total number of samples collected inside the function.
Definition: SampleProf.h:321
const CallsiteSampleMap & getCallsiteSamples() const
Return all the callsite samples collected in the body of the function.
Definition: SampleProf.h:354
uint64_t tell() const
tell - Return the current offset with the file.
Definition: raw_ostream.h:100
print Instructions which execute on loop entry
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:49
void computeSummary(const StringMap< FunctionSamples > &ProfileMap)
Compute summary for this profile.
std::error_code write(const FunctionSamples &S) override
Write samples to a text file.
Sample-based profile writer (text format).