1c572e92cSDiego Novillo //===- SampleProfWriter.cpp - Write LLVM sample profile data --------------===//
2c572e92cSDiego Novillo //
3c572e92cSDiego Novillo //                      The LLVM Compiler Infrastructure
4c572e92cSDiego Novillo //
5c572e92cSDiego Novillo // This file is distributed under the University of Illinois Open Source
6c572e92cSDiego Novillo // License. See LICENSE.TXT for details.
7c572e92cSDiego Novillo //
8c572e92cSDiego Novillo //===----------------------------------------------------------------------===//
9c572e92cSDiego Novillo //
10c572e92cSDiego Novillo // This file implements the class that writes LLVM sample profiles. It
11c572e92cSDiego Novillo // supports two file formats: text and binary. The textual representation
12c572e92cSDiego Novillo // is useful for debugging and testing purposes. The binary representation
13c572e92cSDiego Novillo // is more compact, resulting in smaller file sizes. However, they can
14c572e92cSDiego Novillo // both be used interchangeably.
15c572e92cSDiego Novillo //
16c572e92cSDiego Novillo // See lib/ProfileData/SampleProfReader.cpp for documentation on each of the
17c572e92cSDiego Novillo // supported formats.
18c572e92cSDiego Novillo //
19c572e92cSDiego Novillo //===----------------------------------------------------------------------===//
20c572e92cSDiego Novillo 
21c572e92cSDiego Novillo #include "llvm/ProfileData/SampleProfWriter.h"
22c572e92cSDiego Novillo #include "llvm/Support/Debug.h"
23c572e92cSDiego Novillo #include "llvm/Support/ErrorOr.h"
24c572e92cSDiego Novillo #include "llvm/Support/LEB128.h"
25c572e92cSDiego Novillo #include "llvm/Support/LineIterator.h"
26d9903888SChandler Carruth #include "llvm/Support/MemoryBuffer.h"
27c572e92cSDiego Novillo #include "llvm/Support/Regex.h"
28c572e92cSDiego Novillo 
29c572e92cSDiego Novillo using namespace llvm::sampleprof;
30c572e92cSDiego Novillo using namespace llvm;
31c572e92cSDiego Novillo 
32c572e92cSDiego Novillo /// \brief Write samples to a text file.
338e415a82SDiego Novillo ///
348e415a82SDiego Novillo /// Note: it may be tempting to implement this in terms of
35*ef548d29SDiego Novillo /// FunctionSamples::print().  Please don't.  The dump functionality is intended
368e415a82SDiego Novillo /// for debugging and has no specified form.
378e415a82SDiego Novillo ///
388e415a82SDiego Novillo /// The format used here is more structured and deliberate because
398e415a82SDiego Novillo /// it needs to be parsed by the SampleProfileReaderText class.
40760c5a8fSDiego Novillo std::error_code SampleProfileWriterText::write(StringRef FName,
41760c5a8fSDiego Novillo                                                const FunctionSamples &S) {
42aae1ed8eSDiego Novillo   OS << FName << ":" << S.getTotalSamples();
43aae1ed8eSDiego Novillo   if (Indent == 0)
44aae1ed8eSDiego Novillo     OS << ":" << S.getHeadSamples();
45aae1ed8eSDiego Novillo   OS << "\n";
46c572e92cSDiego Novillo 
47*ef548d29SDiego Novillo   SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples());
48*ef548d29SDiego Novillo   for (const auto &I : SortedSamples.get()) {
49*ef548d29SDiego Novillo     LineLocation Loc = I->first;
50*ef548d29SDiego Novillo     const SampleRecord &Sample = I->second;
51aae1ed8eSDiego Novillo     OS.indent(Indent + 1);
52c572e92cSDiego Novillo     if (Loc.Discriminator == 0)
53c572e92cSDiego Novillo       OS << Loc.LineOffset << ": ";
54c572e92cSDiego Novillo     else
55c572e92cSDiego Novillo       OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
56c572e92cSDiego Novillo 
57c572e92cSDiego Novillo     OS << Sample.getSamples();
58c572e92cSDiego Novillo 
59d5336ae2SDiego Novillo     for (const auto &J : Sample.getCallTargets())
60d5336ae2SDiego Novillo       OS << " " << J.first() << ":" << J.second;
61c572e92cSDiego Novillo     OS << "\n";
62c572e92cSDiego Novillo   }
63c572e92cSDiego Novillo 
64*ef548d29SDiego Novillo   SampleSorter<CallsiteLocation, FunctionSamples> SortedCallsiteSamples(
65*ef548d29SDiego Novillo       S.getCallsiteSamples());
66aae1ed8eSDiego Novillo   Indent += 1;
67*ef548d29SDiego Novillo   for (const auto &I : SortedCallsiteSamples.get()) {
68*ef548d29SDiego Novillo     CallsiteLocation Loc = I->first;
69*ef548d29SDiego Novillo     const FunctionSamples &CalleeSamples = I->second;
70aae1ed8eSDiego Novillo     OS.indent(Indent);
71aae1ed8eSDiego Novillo     if (Loc.Discriminator == 0)
72aae1ed8eSDiego Novillo       OS << Loc.LineOffset << ": ";
73aae1ed8eSDiego Novillo     else
74aae1ed8eSDiego Novillo       OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
75760c5a8fSDiego Novillo     if (std::error_code EC = write(Loc.CalleeName, CalleeSamples))
76760c5a8fSDiego Novillo       return EC;
77aae1ed8eSDiego Novillo   }
78aae1ed8eSDiego Novillo   Indent -= 1;
79aae1ed8eSDiego Novillo 
80760c5a8fSDiego Novillo   return sampleprof_error::success;
81c572e92cSDiego Novillo }
82c572e92cSDiego Novillo 
83760c5a8fSDiego Novillo std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) {
84760c5a8fSDiego Novillo   const auto &ret = NameTable.find(FName);
85760c5a8fSDiego Novillo   if (ret == NameTable.end())
86760c5a8fSDiego Novillo     return sampleprof_error::truncated_name_table;
87760c5a8fSDiego Novillo   encodeULEB128(ret->second, OS);
88760c5a8fSDiego Novillo   return sampleprof_error::success;
89760c5a8fSDiego Novillo }
90c572e92cSDiego Novillo 
91760c5a8fSDiego Novillo void SampleProfileWriterBinary::addName(StringRef FName) {
92760c5a8fSDiego Novillo   auto NextIdx = NameTable.size();
93760c5a8fSDiego Novillo   NameTable.insert(std::make_pair(FName, NextIdx));
94760c5a8fSDiego Novillo }
95760c5a8fSDiego Novillo 
96760c5a8fSDiego Novillo void SampleProfileWriterBinary::addNames(const FunctionSamples &S) {
97760c5a8fSDiego Novillo   // Add all the names in indirect call targets.
98760c5a8fSDiego Novillo   for (const auto &I : S.getBodySamples()) {
99760c5a8fSDiego Novillo     const SampleRecord &Sample = I.second;
100760c5a8fSDiego Novillo     for (const auto &J : Sample.getCallTargets())
101760c5a8fSDiego Novillo       addName(J.first());
102760c5a8fSDiego Novillo   }
103760c5a8fSDiego Novillo 
104760c5a8fSDiego Novillo   // Recursively add all the names for inlined callsites.
105760c5a8fSDiego Novillo   for (const auto &J : S.getCallsiteSamples()) {
106760c5a8fSDiego Novillo     CallsiteLocation Loc = J.first;
107760c5a8fSDiego Novillo     const FunctionSamples &CalleeSamples = J.second;
108760c5a8fSDiego Novillo     addName(Loc.CalleeName);
109760c5a8fSDiego Novillo     addNames(CalleeSamples);
110760c5a8fSDiego Novillo   }
111760c5a8fSDiego Novillo }
112760c5a8fSDiego Novillo 
113760c5a8fSDiego Novillo std::error_code SampleProfileWriterBinary::writeHeader(
114760c5a8fSDiego Novillo     const StringMap<FunctionSamples> &ProfileMap) {
115760c5a8fSDiego Novillo   // Write file magic identifier.
116c572e92cSDiego Novillo   encodeULEB128(SPMagic(), OS);
117c572e92cSDiego Novillo   encodeULEB128(SPVersion(), OS);
118760c5a8fSDiego Novillo 
119760c5a8fSDiego Novillo   // Generate the name table for all the functions referenced in the profile.
120760c5a8fSDiego Novillo   for (const auto &I : ProfileMap) {
121760c5a8fSDiego Novillo     addName(I.first());
122760c5a8fSDiego Novillo     addNames(I.second);
123760c5a8fSDiego Novillo   }
124760c5a8fSDiego Novillo 
125760c5a8fSDiego Novillo   // Write out the name table.
126760c5a8fSDiego Novillo   encodeULEB128(NameTable.size(), OS);
127760c5a8fSDiego Novillo   for (auto N : NameTable) {
128760c5a8fSDiego Novillo     OS << N.first;
129760c5a8fSDiego Novillo     encodeULEB128(0, OS);
130760c5a8fSDiego Novillo   }
131760c5a8fSDiego Novillo 
132760c5a8fSDiego Novillo   return sampleprof_error::success;
133c572e92cSDiego Novillo }
134c572e92cSDiego Novillo 
135b93483dbSDiego Novillo std::error_code SampleProfileWriterBinary::writeBody(StringRef FName,
136c572e92cSDiego Novillo                                                      const FunctionSamples &S) {
137760c5a8fSDiego Novillo   if (std::error_code EC = writeNameIdx(FName))
138760c5a8fSDiego Novillo     return EC;
139760c5a8fSDiego Novillo 
140c572e92cSDiego Novillo   encodeULEB128(S.getTotalSamples(), OS);
141a7f1e8efSDiego Novillo 
142a7f1e8efSDiego Novillo   // Emit all the body samples.
143b93483dbSDiego Novillo   encodeULEB128(S.getBodySamples().size(), OS);
144d5336ae2SDiego Novillo   for (const auto &I : S.getBodySamples()) {
145d5336ae2SDiego Novillo     LineLocation Loc = I.first;
146d5336ae2SDiego Novillo     const SampleRecord &Sample = I.second;
147c572e92cSDiego Novillo     encodeULEB128(Loc.LineOffset, OS);
148c572e92cSDiego Novillo     encodeULEB128(Loc.Discriminator, OS);
149c572e92cSDiego Novillo     encodeULEB128(Sample.getSamples(), OS);
150c572e92cSDiego Novillo     encodeULEB128(Sample.getCallTargets().size(), OS);
151d5336ae2SDiego Novillo     for (const auto &J : Sample.getCallTargets()) {
152760c5a8fSDiego Novillo       StringRef Callee = J.first();
15338be3330SDiego Novillo       uint64_t CalleeSamples = J.second;
154760c5a8fSDiego Novillo       if (std::error_code EC = writeNameIdx(Callee))
155760c5a8fSDiego Novillo         return EC;
156c572e92cSDiego Novillo       encodeULEB128(CalleeSamples, OS);
157c572e92cSDiego Novillo     }
158c572e92cSDiego Novillo   }
159c572e92cSDiego Novillo 
160a7f1e8efSDiego Novillo   // Recursively emit all the callsite samples.
161a7f1e8efSDiego Novillo   encodeULEB128(S.getCallsiteSamples().size(), OS);
162a7f1e8efSDiego Novillo   for (const auto &J : S.getCallsiteSamples()) {
163a7f1e8efSDiego Novillo     CallsiteLocation Loc = J.first;
164a7f1e8efSDiego Novillo     const FunctionSamples &CalleeSamples = J.second;
165a7f1e8efSDiego Novillo     encodeULEB128(Loc.LineOffset, OS);
166a7f1e8efSDiego Novillo     encodeULEB128(Loc.Discriminator, OS);
167b93483dbSDiego Novillo     if (std::error_code EC = writeBody(Loc.CalleeName, CalleeSamples))
168760c5a8fSDiego Novillo       return EC;
169a7f1e8efSDiego Novillo   }
170a7f1e8efSDiego Novillo 
171760c5a8fSDiego Novillo   return sampleprof_error::success;
172c572e92cSDiego Novillo }
173d5336ae2SDiego Novillo 
174b93483dbSDiego Novillo /// \brief Write samples of a top-level function to a binary file.
175b93483dbSDiego Novillo ///
176b93483dbSDiego Novillo /// \returns true if the samples were written successfully, false otherwise.
177b93483dbSDiego Novillo std::error_code SampleProfileWriterBinary::write(StringRef FName,
178b93483dbSDiego Novillo                                                  const FunctionSamples &S) {
179b93483dbSDiego Novillo   encodeULEB128(S.getHeadSamples(), OS);
180b93483dbSDiego Novillo   return writeBody(FName, S);
181b93483dbSDiego Novillo }
182b93483dbSDiego Novillo 
183d5336ae2SDiego Novillo /// \brief Create a sample profile writer based on the specified format.
184d5336ae2SDiego Novillo ///
185d5336ae2SDiego Novillo /// \param Filename The file to create.
186d5336ae2SDiego Novillo ///
187d5336ae2SDiego Novillo /// \param Writer The writer to instantiate according to the specified format.
188d5336ae2SDiego Novillo ///
189d5336ae2SDiego Novillo /// \param Format Encoding format for the profile file.
190d5336ae2SDiego Novillo ///
191d5336ae2SDiego Novillo /// \returns an error code indicating the status of the created writer.
192fcd55607SDiego Novillo ErrorOr<std::unique_ptr<SampleProfileWriter>>
193fcd55607SDiego Novillo SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
194d5336ae2SDiego Novillo   std::error_code EC;
195fcd55607SDiego Novillo   std::unique_ptr<SampleProfileWriter> Writer;
196d5336ae2SDiego Novillo 
197d5336ae2SDiego Novillo   if (Format == SPF_Binary)
198d5336ae2SDiego Novillo     Writer.reset(new SampleProfileWriterBinary(Filename, EC));
199d5336ae2SDiego Novillo   else if (Format == SPF_Text)
200d5336ae2SDiego Novillo     Writer.reset(new SampleProfileWriterText(Filename, EC));
201760c5a8fSDiego Novillo   else if (Format == SPF_GCC)
202760c5a8fSDiego Novillo     EC = sampleprof_error::unsupported_writing_format;
203d5336ae2SDiego Novillo   else
204d5336ae2SDiego Novillo     EC = sampleprof_error::unrecognized_format;
205d5336ae2SDiego Novillo 
206fcd55607SDiego Novillo   if (EC)
207d5336ae2SDiego Novillo     return EC;
208fcd55607SDiego Novillo 
209fcd55607SDiego Novillo   return std::move(Writer);
210d5336ae2SDiego Novillo }
211