SampleProfWriter.cpp revision 303975
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
21#include "llvm/ProfileData/SampleProfWriter.h"
22#include "llvm/Support/Debug.h"
23#include "llvm/Support/ErrorOr.h"
24#include "llvm/Support/LEB128.h"
25#include "llvm/Support/LineIterator.h"
26#include "llvm/Support/MemoryBuffer.h"
27#include "llvm/Support/Regex.h"
28
29using namespace llvm::sampleprof;
30using namespace llvm;
31
32/// \brief Write samples to a text file.
33///
34/// Note: it may be tempting to implement this in terms of
35/// FunctionSamples::print().  Please don't.  The dump functionality is intended
36/// for debugging and has no specified form.
37///
38/// The format used here is more structured and deliberate because
39/// it needs to be parsed by the SampleProfileReaderText class.
40std::error_code SampleProfileWriterText::write(StringRef FName,
41                                               const FunctionSamples &S) {
42  auto &OS = *OutputStream;
43
44  OS << FName << ":" << S.getTotalSamples();
45  if (Indent == 0)
46    OS << ":" << S.getHeadSamples();
47  OS << "\n";
48
49  SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples());
50  for (const auto &I : SortedSamples.get()) {
51    LineLocation Loc = I->first;
52    const SampleRecord &Sample = I->second;
53    OS.indent(Indent + 1);
54    if (Loc.Discriminator == 0)
55      OS << Loc.LineOffset << ": ";
56    else
57      OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
58
59    OS << Sample.getSamples();
60
61    for (const auto &J : Sample.getCallTargets())
62      OS << " " << J.first() << ":" << J.second;
63    OS << "\n";
64  }
65
66  SampleSorter<CallsiteLocation, FunctionSamples> SortedCallsiteSamples(
67      S.getCallsiteSamples());
68  Indent += 1;
69  for (const auto &I : SortedCallsiteSamples.get()) {
70    CallsiteLocation Loc = I->first;
71    const FunctionSamples &CalleeSamples = I->second;
72    OS.indent(Indent);
73    if (Loc.Discriminator == 0)
74      OS << Loc.LineOffset << ": ";
75    else
76      OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
77    if (std::error_code EC = write(Loc.CalleeName, CalleeSamples))
78      return EC;
79  }
80  Indent -= 1;
81
82  return sampleprof_error::success;
83}
84
85std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) {
86  const auto &ret = NameTable.find(FName);
87  if (ret == NameTable.end())
88    return sampleprof_error::truncated_name_table;
89  encodeULEB128(ret->second, *OutputStream);
90  return sampleprof_error::success;
91}
92
93void SampleProfileWriterBinary::addName(StringRef FName) {
94  auto NextIdx = NameTable.size();
95  NameTable.insert(std::make_pair(FName, NextIdx));
96}
97
98void SampleProfileWriterBinary::addNames(const FunctionSamples &S) {
99  // Add all the names in indirect call targets.
100  for (const auto &I : S.getBodySamples()) {
101    const SampleRecord &Sample = I.second;
102    for (const auto &J : Sample.getCallTargets())
103      addName(J.first());
104  }
105
106  // Recursively add all the names for inlined callsites.
107  for (const auto &J : S.getCallsiteSamples()) {
108    CallsiteLocation Loc = J.first;
109    const FunctionSamples &CalleeSamples = J.second;
110    addName(Loc.CalleeName);
111    addNames(CalleeSamples);
112  }
113}
114
115std::error_code SampleProfileWriterBinary::writeHeader(
116    const StringMap<FunctionSamples> &ProfileMap) {
117  auto &OS = *OutputStream;
118
119  // Write file magic identifier.
120  encodeULEB128(SPMagic(), OS);
121  encodeULEB128(SPVersion(), OS);
122
123  // Generate the name table for all the functions referenced in the profile.
124  for (const auto &I : ProfileMap) {
125    addName(I.first());
126    addNames(I.second);
127  }
128
129  // Write out the name table.
130  encodeULEB128(NameTable.size(), OS);
131  for (auto N : NameTable) {
132    OS << N.first;
133    encodeULEB128(0, OS);
134  }
135
136  return sampleprof_error::success;
137}
138
139std::error_code SampleProfileWriterBinary::writeBody(StringRef FName,
140                                                     const FunctionSamples &S) {
141  auto &OS = *OutputStream;
142
143  if (std::error_code EC = writeNameIdx(FName))
144    return EC;
145
146  encodeULEB128(S.getTotalSamples(), OS);
147
148  // Emit all the body samples.
149  encodeULEB128(S.getBodySamples().size(), OS);
150  for (const auto &I : S.getBodySamples()) {
151    LineLocation Loc = I.first;
152    const SampleRecord &Sample = I.second;
153    encodeULEB128(Loc.LineOffset, OS);
154    encodeULEB128(Loc.Discriminator, OS);
155    encodeULEB128(Sample.getSamples(), OS);
156    encodeULEB128(Sample.getCallTargets().size(), OS);
157    for (const auto &J : Sample.getCallTargets()) {
158      StringRef Callee = J.first();
159      uint64_t CalleeSamples = J.second;
160      if (std::error_code EC = writeNameIdx(Callee))
161        return EC;
162      encodeULEB128(CalleeSamples, OS);
163    }
164  }
165
166  // Recursively emit all the callsite samples.
167  encodeULEB128(S.getCallsiteSamples().size(), OS);
168  for (const auto &J : S.getCallsiteSamples()) {
169    CallsiteLocation Loc = J.first;
170    const FunctionSamples &CalleeSamples = J.second;
171    encodeULEB128(Loc.LineOffset, OS);
172    encodeULEB128(Loc.Discriminator, OS);
173    if (std::error_code EC = writeBody(Loc.CalleeName, CalleeSamples))
174      return EC;
175  }
176
177  return sampleprof_error::success;
178}
179
180/// \brief Write samples of a top-level function to a binary file.
181///
182/// \returns true if the samples were written successfully, false otherwise.
183std::error_code SampleProfileWriterBinary::write(StringRef FName,
184                                                 const FunctionSamples &S) {
185  encodeULEB128(S.getHeadSamples(), *OutputStream);
186  return writeBody(FName, S);
187}
188
189/// \brief Create a sample profile file writer based on the specified format.
190///
191/// \param Filename The file to create.
192///
193/// \param Writer The writer to instantiate according to the specified format.
194///
195/// \param Format Encoding format for the profile file.
196///
197/// \returns an error code indicating the status of the created writer.
198ErrorOr<std::unique_ptr<SampleProfileWriter>>
199SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
200  std::error_code EC;
201  std::unique_ptr<raw_ostream> OS;
202  if (Format == SPF_Binary)
203    OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::F_None));
204  else
205    OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::F_Text));
206  if (EC)
207    return EC;
208
209  return create(OS, Format);
210}
211
212/// \brief Create a sample profile stream writer based on the specified format.
213///
214/// \param OS The output stream to store the profile data to.
215///
216/// \param Writer The writer to instantiate according to the specified format.
217///
218/// \param Format Encoding format for the profile file.
219///
220/// \returns an error code indicating the status of the created writer.
221ErrorOr<std::unique_ptr<SampleProfileWriter>>
222SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
223                            SampleProfileFormat Format) {
224  std::error_code EC;
225  std::unique_ptr<SampleProfileWriter> Writer;
226
227  if (Format == SPF_Binary)
228    Writer.reset(new SampleProfileWriterBinary(OS));
229  else if (Format == SPF_Text)
230    Writer.reset(new SampleProfileWriterText(OS));
231  else if (Format == SPF_GCC)
232    EC = sampleprof_error::unsupported_writing_format;
233  else
234    EC = sampleprof_error::unrecognized_format;
235
236  if (EC)
237    return EC;
238
239  return std::move(Writer);
240}
241