LLVM  9.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 
42 std::error_code
44  if (std::error_code EC = writeHeader(ProfileMap))
45  return EC;
46 
47  // Sort the ProfileMap by total samples.
48  typedef std::pair<StringRef, const FunctionSamples *> NameFunctionSamples;
49  std::vector<NameFunctionSamples> V;
50  for (const auto &I : ProfileMap)
51  V.push_back(std::make_pair(I.getKey(), &I.second));
52 
54  V.begin(), V.end(),
55  [](const NameFunctionSamples &A, const NameFunctionSamples &B) {
56  if (A.second->getTotalSamples() == B.second->getTotalSamples())
57  return A.first > B.first;
58  return A.second->getTotalSamples() > B.second->getTotalSamples();
59  });
60 
61  for (const auto &I : V) {
62  if (std::error_code EC = write(*I.second))
63  return EC;
64  }
66 }
67 
69  const StringMap<FunctionSamples> &ProfileMap) {
70  if (std::error_code EC = SampleProfileWriter::write(ProfileMap))
71  return EC;
72  if (std::error_code EC = writeFuncOffsetTable())
73  return EC;
75 }
76 
77 /// Write samples to a text file.
78 ///
79 /// Note: it may be tempting to implement this in terms of
80 /// FunctionSamples::print(). Please don't. The dump functionality is intended
81 /// for debugging and has no specified form.
82 ///
83 /// The format used here is more structured and deliberate because
84 /// it needs to be parsed by the SampleProfileReaderText class.
86  auto &OS = *OutputStream;
87  OS << S.getName() << ":" << S.getTotalSamples();
88  if (Indent == 0)
89  OS << ":" << S.getHeadSamples();
90  OS << "\n";
91 
93  for (const auto &I : SortedSamples.get()) {
94  LineLocation Loc = I->first;
95  const SampleRecord &Sample = I->second;
96  OS.indent(Indent + 1);
97  if (Loc.Discriminator == 0)
98  OS << Loc.LineOffset << ": ";
99  else
100  OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
101 
102  OS << Sample.getSamples();
103 
104  for (const auto &J : Sample.getCallTargets())
105  OS << " " << J.first() << ":" << J.second;
106  OS << "\n";
107  }
108 
110  S.getCallsiteSamples());
111  Indent += 1;
112  for (const auto &I : SortedCallsiteSamples.get())
113  for (const auto &FS : I->second) {
114  LineLocation Loc = I->first;
115  const FunctionSamples &CalleeSamples = FS.second;
116  OS.indent(Indent);
117  if (Loc.Discriminator == 0)
118  OS << Loc.LineOffset << ": ";
119  else
120  OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
121  if (std::error_code EC = write(CalleeSamples))
122  return EC;
123  }
124  Indent -= 1;
125 
127 }
128 
130  const auto &ret = NameTable.find(FName);
131  if (ret == NameTable.end())
133  encodeULEB128(ret->second, *OutputStream);
135 }
136 
137 void SampleProfileWriterBinary::addName(StringRef FName) {
138  NameTable.insert(std::make_pair(FName, 0));
139 }
140 
141 void SampleProfileWriterBinary::addNames(const FunctionSamples &S) {
142  // Add all the names in indirect call targets.
143  for (const auto &I : S.getBodySamples()) {
144  const SampleRecord &Sample = I.second;
145  for (const auto &J : Sample.getCallTargets())
146  addName(J.first());
147  }
148 
149  // Recursively add all the names for inlined callsites.
150  for (const auto &J : S.getCallsiteSamples())
151  for (const auto &FS : J.second) {
152  const FunctionSamples &CalleeSamples = FS.second;
153  addName(CalleeSamples.getName());
154  addNames(CalleeSamples);
155  }
156 }
157 
158 void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) {
159  // Sort the names to make NameTable deterministic.
160  for (const auto &I : NameTable)
161  V.insert(I.first);
162  int i = 0;
163  for (const StringRef &N : V)
164  NameTable[N] = i++;
165 }
166 
168  auto &OS = *OutputStream;
169  std::set<StringRef> V;
170  stablizeNameTable(V);
171 
172  // Write out the name table.
173  encodeULEB128(NameTable.size(), OS);
174  for (auto N : V) {
175  OS << N;
176  encodeULEB128(0, OS);
177  }
179 }
180 
182  auto &OS = *OutputStream;
183 
184  // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable.
185  auto &OFS = static_cast<raw_fd_ostream &>(OS);
186  uint64_t FuncOffsetTableStart = OS.tell();
187  if (OFS.seek(TableOffset) == (uint64_t)-1)
190  Writer.write(FuncOffsetTableStart);
191  if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1)
193 
194  // Write out the table size.
195  encodeULEB128(FuncOffsetTable.size(), OS);
196 
197  // Write out FuncOffsetTable.
198  for (auto entry : FuncOffsetTable) {
199  writeNameIdx(entry.first);
200  encodeULEB128(entry.second, OS);
201  }
203 }
204 
206  auto &OS = *OutputStream;
207  std::set<StringRef> V;
208  stablizeNameTable(V);
209 
210  // Write out the name table.
211  encodeULEB128(NameTable.size(), OS);
212  for (auto N : V) {
213  encodeULEB128(MD5Hash(N), OS);
214  }
216 }
217 
219  auto &OS = *OutputStream;
220  // Write file magic identifier.
221  encodeULEB128(SPMagic(), OS);
222  encodeULEB128(SPVersion(), OS);
224 }
225 
227  auto &OS = *OutputStream;
228  // Write file magic identifier.
230  encodeULEB128(SPVersion(), OS);
232 }
233 
235  const StringMap<FunctionSamples> &ProfileMap) {
236  writeMagicIdent();
237 
238  computeSummary(ProfileMap);
239  if (auto EC = writeSummary())
240  return EC;
241 
242  // Generate the name table for all the functions referenced in the profile.
243  for (const auto &I : ProfileMap) {
244  addName(I.first());
245  addNames(I.second);
246  }
247 
248  writeNameTable();
250 }
251 
253  const StringMap<FunctionSamples> &ProfileMap) {
255  if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap))
256  return EC;
257 
258  // Reserve a slot for the offset of function offset table. The slot will
259  // be populated with the offset of FuncOffsetTable later.
260  TableOffset = OutputStream->tell();
261  Writer.write(static_cast<uint64_t>(-2));
263 }
264 
266  auto &OS = *OutputStream;
267  encodeULEB128(Summary->getTotalCount(), OS);
268  encodeULEB128(Summary->getMaxCount(), OS);
269  encodeULEB128(Summary->getMaxFunctionCount(), OS);
270  encodeULEB128(Summary->getNumCounts(), OS);
271  encodeULEB128(Summary->getNumFunctions(), OS);
272  std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary();
273  encodeULEB128(Entries.size(), OS);
274  for (auto Entry : Entries) {
275  encodeULEB128(Entry.Cutoff, OS);
276  encodeULEB128(Entry.MinCount, OS);
277  encodeULEB128(Entry.NumCounts, OS);
278  }
280 }
282  auto &OS = *OutputStream;
283 
284  if (std::error_code EC = writeNameIdx(S.getName()))
285  return EC;
286 
288 
289  // Emit all the body samples.
290  encodeULEB128(S.getBodySamples().size(), OS);
291  for (const auto &I : S.getBodySamples()) {
292  LineLocation Loc = I.first;
293  const SampleRecord &Sample = I.second;
294  encodeULEB128(Loc.LineOffset, OS);
295  encodeULEB128(Loc.Discriminator, OS);
296  encodeULEB128(Sample.getSamples(), OS);
297  encodeULEB128(Sample.getCallTargets().size(), OS);
298  for (const auto &J : Sample.getCallTargets()) {
299  StringRef Callee = J.first();
300  uint64_t CalleeSamples = J.second;
301  if (std::error_code EC = writeNameIdx(Callee))
302  return EC;
303  encodeULEB128(CalleeSamples, OS);
304  }
305  }
306 
307  // Recursively emit all the callsite samples.
308  uint64_t NumCallsites = 0;
309  for (const auto &J : S.getCallsiteSamples())
310  NumCallsites += J.second.size();
311  encodeULEB128(NumCallsites, OS);
312  for (const auto &J : S.getCallsiteSamples())
313  for (const auto &FS : J.second) {
314  LineLocation Loc = J.first;
315  const FunctionSamples &CalleeSamples = FS.second;
316  encodeULEB128(Loc.LineOffset, OS);
317  encodeULEB128(Loc.Discriminator, OS);
318  if (std::error_code EC = writeBody(CalleeSamples))
319  return EC;
320  }
321 
323 }
324 
325 /// Write samples of a top-level function to a binary file.
326 ///
327 /// \returns true if the samples were written successfully, false otherwise.
330  return writeBody(S);
331 }
332 
333 std::error_code
335  uint64_t Offset = OutputStream->tell();
336  StringRef Name = S.getName();
337  FuncOffsetTable[Name] = Offset;
339  return writeBody(S);
340 }
341 
342 /// Create a sample profile file writer based on the specified format.
343 ///
344 /// \param Filename The file to create.
345 ///
346 /// \param Format Encoding format for the profile file.
347 ///
348 /// \returns an error code indicating the status of the created writer.
351  std::error_code EC;
352  std::unique_ptr<raw_ostream> OS;
353  if (Format == SPF_Binary || Format == SPF_Compact_Binary)
354  OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::F_None));
355  else
356  OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::F_Text));
357  if (EC)
358  return EC;
359 
360  return create(OS, Format);
361 }
362 
363 /// Create a sample profile stream writer based on the specified format.
364 ///
365 /// \param OS The output stream to store the profile data to.
366 ///
367 /// \param Format Encoding format for the profile file.
368 ///
369 /// \returns an error code indicating the status of the created writer.
371 SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
372  SampleProfileFormat Format) {
373  std::error_code EC;
374  std::unique_ptr<SampleProfileWriter> Writer;
375 
376  if (Format == SPF_Binary)
377  Writer.reset(new SampleProfileWriterRawBinary(OS));
378  else if (Format == SPF_Compact_Binary)
379  Writer.reset(new SampleProfileWriterCompactBinary(OS));
380  else if (Format == SPF_Text)
381  Writer.reset(new SampleProfileWriterText(OS));
382  else if (Format == SPF_GCC)
384  else
386 
387  if (EC)
388  return EC;
389 
390  return std::move(Writer);
391 }
392 
394  const StringMap<FunctionSamples> &ProfileMap) {
396  for (const auto &I : ProfileMap) {
397  const FunctionSamples &Profile = I.second;
398  Builder.addRecord(Profile);
399  }
400  Summary = Builder.getSummary();
401 }
virtual std::error_code writeMagicIdent() override
Represents either an error or a value T.
Definition: ErrorOr.h:56
This class represents lattice values for constants.
Definition: AllocatorList.h:23
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 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:216
std::error_code writeNameIdx(StringRef FName)
unsigned size() const
Definition: StringMap.h:111
virtual std::error_code writeMagicIdent() override
virtual std::error_code writeNameTable() override
Representation of a single sample record.
Definition: SampleProf.h:144
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:106
Sort a LocationT->SampleT map by LocationT.
Definition: SampleProf.h:567
uint64_t getHeadSamples() const
Return the total number of branch samples that have the function as the branch target.
Definition: SampleProf.h:327
virtual std::error_code writeNameTable() override
std::unique_ptr< ProfileSummary > Summary
Profile summary.
uint64_t getSamples() const
Definition: SampleProf.h:180
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:350
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: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.
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:365
Represents the relative location of an instruction.
Definition: SampleProf.h:117
#define I(x, y, z)
Definition: MD5.cpp:58
#define N
StringRef getName() const
Return the function name.
Definition: SampleProf.h:406
const CallTargetMap & getCallTargets() const
Definition: SampleProf.h:181
static uint64_t SPMagic(SampleProfileFormat Format=SPF_Binary)
Definition: SampleProf.h:89
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:597
void stable_sort(R &&Range)
Definition: STLExtras.h:1309
uint64_t getTotalSamples() const
Return the total number of samples collected inside the function.
Definition: SampleProf.h:320
const CallsiteSampleMap & getCallsiteSamples() const
Return all the callsite samples collected in the body of the function.
Definition: SampleProf.h:353
uint64_t tell() const
tell - Return the current offset with the file.
Definition: raw_ostream.h:99
print Instructions which execute on loop entry
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
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).