f62f79064c4e654f11f9f7454625e8bdfcbd08ae
[oota-llvm.git] / include / llvm / ProfileData / SampleProf.h
1 //=-- SampleProf.h - Sampling profiling format support --------------------===//
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 contains common definitions used in the reading and writing of
11 // sample profile data.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #ifndef LLVM_PROFILEDATA_SAMPLEPROF_H_
16 #define LLVM_PROFILEDATA_SAMPLEPROF_H_
17
18 #include "llvm/ADT/SmallVector.h"
19 #include "llvm/ADT/StringMap.h"
20 #include "llvm/Support/Debug.h"
21 #include "llvm/Support/ErrorOr.h"
22 #include "llvm/Support/raw_ostream.h"
23
24 #include <map>
25 #include <system_error>
26
27 namespace llvm {
28
29 const std::error_category &sampleprof_category();
30
31 enum class sampleprof_error {
32   success = 0,
33   bad_magic,
34   unsupported_version,
35   too_large,
36   truncated,
37   malformed,
38   unrecognized_format,
39   unsupported_writing_format,
40   truncated_name_table,
41   not_implemented
42 };
43
44 inline std::error_code make_error_code(sampleprof_error E) {
45   return std::error_code(static_cast<int>(E), sampleprof_category());
46 }
47
48 } // end namespace llvm
49
50 namespace std {
51 template <>
52 struct is_error_code_enum<llvm::sampleprof_error> : std::true_type {};
53 }
54
55 namespace llvm {
56
57 namespace sampleprof {
58
59 static inline uint64_t SPMagic() {
60   return uint64_t('S') << (64 - 8) | uint64_t('P') << (64 - 16) |
61          uint64_t('R') << (64 - 24) | uint64_t('O') << (64 - 32) |
62          uint64_t('F') << (64 - 40) | uint64_t('4') << (64 - 48) |
63          uint64_t('2') << (64 - 56) | uint64_t(0xff);
64 }
65
66 static inline uint64_t SPVersion() { return 102; }
67
68 /// Represents the relative location of an instruction.
69 ///
70 /// Instruction locations are specified by the line offset from the
71 /// beginning of the function (marked by the line where the function
72 /// header is) and the discriminator value within that line.
73 ///
74 /// The discriminator value is useful to distinguish instructions
75 /// that are on the same line but belong to different basic blocks
76 /// (e.g., the two post-increment instructions in "if (p) x++; else y++;").
77 struct LineLocation {
78   LineLocation(uint32_t L, uint32_t D) : LineOffset(L), Discriminator(D) {}
79   void print(raw_ostream &OS) const;
80   void dump() const;
81   bool operator<(const LineLocation &O) const {
82     return LineOffset < O.LineOffset ||
83            (LineOffset == O.LineOffset && Discriminator < O.Discriminator);
84   }
85
86   uint32_t LineOffset;
87   uint32_t Discriminator;
88 };
89
90 raw_ostream &operator<<(raw_ostream &OS, const LineLocation &Loc);
91
92 /// Represents the relative location of a callsite.
93 ///
94 /// Callsite locations are specified by the line offset from the
95 /// beginning of the function (marked by the line where the function
96 /// head is), the discriminator value within that line, and the callee
97 /// function name.
98 struct CallsiteLocation : public LineLocation {
99   CallsiteLocation(uint32_t L, uint32_t D, StringRef N)
100       : LineLocation(L, D), CalleeName(N) {}
101   void print(raw_ostream &OS) const;
102   void dump() const;
103
104   StringRef CalleeName;
105 };
106
107 raw_ostream &operator<<(raw_ostream &OS, const CallsiteLocation &Loc);
108
109 /// Representation of a single sample record.
110 ///
111 /// A sample record is represented by a positive integer value, which
112 /// indicates how frequently was the associated line location executed.
113 ///
114 /// Additionally, if the associated location contains a function call,
115 /// the record will hold a list of all the possible called targets. For
116 /// direct calls, this will be the exact function being invoked. For
117 /// indirect calls (function pointers, virtual table dispatch), this
118 /// will be a list of one or more functions.
119 class SampleRecord {
120 public:
121   typedef StringMap<uint64_t> CallTargetMap;
122
123   SampleRecord() : NumSamples(0), CallTargets() {}
124
125   /// Increment the number of samples for this record by \p S.
126   ///
127   /// Sample counts accumulate using saturating arithmetic, to avoid wrapping
128   /// around unsigned integers.
129   void addSamples(uint64_t S) { NumSamples = SaturatingAdd(NumSamples, S); }
130
131   /// Add called function \p F with samples \p S.
132   ///
133   /// Sample counts accumulate using saturating arithmetic, to avoid wrapping
134   /// around unsigned integers.
135   void addCalledTarget(StringRef F, uint64_t S) {
136     uint64_t &TargetSamples = CallTargets[F];
137     TargetSamples = SaturatingAdd(TargetSamples, S);
138   }
139
140   /// Return true if this sample record contains function calls.
141   bool hasCalls() const { return CallTargets.size() > 0; }
142
143   uint64_t getSamples() const { return NumSamples; }
144   const CallTargetMap &getCallTargets() const { return CallTargets; }
145
146   /// Merge the samples in \p Other into this record.
147   void merge(const SampleRecord &Other) {
148     addSamples(Other.getSamples());
149     for (const auto &I : Other.getCallTargets())
150       addCalledTarget(I.first(), I.second);
151   }
152
153   void print(raw_ostream &OS, unsigned Indent) const;
154   void dump() const;
155
156 private:
157   uint64_t NumSamples;
158   CallTargetMap CallTargets;
159 };
160
161 raw_ostream &operator<<(raw_ostream &OS, const SampleRecord &Sample);
162
163 typedef std::map<LineLocation, SampleRecord> BodySampleMap;
164 class FunctionSamples;
165 typedef std::map<CallsiteLocation, FunctionSamples> CallsiteSampleMap;
166
167 /// Representation of the samples collected for a function.
168 ///
169 /// This data structure contains all the collected samples for the body
170 /// of a function. Each sample corresponds to a LineLocation instance
171 /// within the body of the function.
172 class FunctionSamples {
173 public:
174   FunctionSamples() : TotalSamples(0), TotalHeadSamples(0) {}
175   void print(raw_ostream &OS = dbgs(), unsigned Indent = 0) const;
176   void dump() const;
177   void addTotalSamples(uint64_t Num) { TotalSamples += Num; }
178   void addHeadSamples(uint64_t Num) { TotalHeadSamples += Num; }
179   void addBodySamples(uint32_t LineOffset, uint32_t Discriminator,
180                       uint64_t Num) {
181     BodySamples[LineLocation(LineOffset, Discriminator)].addSamples(Num);
182   }
183   void addCalledTargetSamples(uint32_t LineOffset, uint32_t Discriminator,
184                               std::string FName, uint64_t Num) {
185     BodySamples[LineLocation(LineOffset, Discriminator)].addCalledTarget(FName,
186                                                                          Num);
187   }
188
189   /// Return the number of samples collected at the given location.
190   /// Each location is specified by \p LineOffset and \p Discriminator.
191   /// If the location is not found in profile, return error.
192   ErrorOr<uint64_t> findSamplesAt(uint32_t LineOffset,
193                                   uint32_t Discriminator) const {
194     const auto &ret = BodySamples.find(LineLocation(LineOffset, Discriminator));
195     if (ret == BodySamples.end())
196       return std::error_code();
197     else
198       return ret->second.getSamples();
199   }
200
201   /// Return the function samples at the given callsite location.
202   FunctionSamples &functionSamplesAt(const CallsiteLocation &Loc) {
203     return CallsiteSamples[Loc];
204   }
205
206   /// Return a pointer to function samples at the given callsite location.
207   const FunctionSamples *
208   findFunctionSamplesAt(const CallsiteLocation &Loc) const {
209     auto iter = CallsiteSamples.find(Loc);
210     if (iter == CallsiteSamples.end()) {
211       return nullptr;
212     } else {
213       return &iter->second;
214     }
215   }
216
217   bool empty() const { return TotalSamples == 0; }
218
219   /// Return the total number of samples collected inside the function.
220   uint64_t getTotalSamples() const { return TotalSamples; }
221
222   /// Return the total number of samples collected at the head of the
223   /// function.
224   uint64_t getHeadSamples() const { return TotalHeadSamples; }
225
226   /// Return all the samples collected in the body of the function.
227   const BodySampleMap &getBodySamples() const { return BodySamples; }
228
229   /// Return all the callsite samples collected in the body of the function.
230   const CallsiteSampleMap &getCallsiteSamples() const {
231     return CallsiteSamples;
232   }
233
234   /// Merge the samples in \p Other into this one.
235   void merge(const FunctionSamples &Other) {
236     addTotalSamples(Other.getTotalSamples());
237     addHeadSamples(Other.getHeadSamples());
238     for (const auto &I : Other.getBodySamples()) {
239       const LineLocation &Loc = I.first;
240       const SampleRecord &Rec = I.second;
241       BodySamples[Loc].merge(Rec);
242     }
243     for (const auto &I : Other.getCallsiteSamples()) {
244       const CallsiteLocation &Loc = I.first;
245       const FunctionSamples &Rec = I.second;
246       functionSamplesAt(Loc).merge(Rec);
247     }
248   }
249
250 private:
251   /// Total number of samples collected inside this function.
252   ///
253   /// Samples are cumulative, they include all the samples collected
254   /// inside this function and all its inlined callees.
255   uint64_t TotalSamples;
256
257   /// Total number of samples collected at the head of the function.
258   /// This is an approximation of the number of calls made to this function
259   /// at runtime.
260   uint64_t TotalHeadSamples;
261
262   /// Map instruction locations to collected samples.
263   ///
264   /// Each entry in this map contains the number of samples
265   /// collected at the corresponding line offset. All line locations
266   /// are an offset from the start of the function.
267   BodySampleMap BodySamples;
268
269   /// Map call sites to collected samples for the called function.
270   ///
271   /// Each entry in this map corresponds to all the samples
272   /// collected for the inlined function call at the given
273   /// location. For example, given:
274   ///
275   ///     void foo() {
276   ///  1    bar();
277   ///  ...
278   ///  8    baz();
279   ///     }
280   ///
281   /// If the bar() and baz() calls were inlined inside foo(), this
282   /// map will contain two entries.  One for all the samples collected
283   /// in the call to bar() at line offset 1, the other for all the samples
284   /// collected in the call to baz() at line offset 8.
285   CallsiteSampleMap CallsiteSamples;
286 };
287
288 raw_ostream &operator<<(raw_ostream &OS, const FunctionSamples &FS);
289
290 /// Sort a LocationT->SampleT map by LocationT.
291 ///
292 /// It produces a sorted list of <LocationT, SampleT> records by ascending
293 /// order of LocationT.
294 template <class LocationT, class SampleT> class SampleSorter {
295 public:
296   typedef std::pair<const LocationT, SampleT> SamplesWithLoc;
297   typedef SmallVector<const SamplesWithLoc *, 20> SamplesWithLocList;
298
299   SampleSorter(const std::map<LocationT, SampleT> &Samples) {
300     for (const auto &I : Samples)
301       V.push_back(&I);
302     std::stable_sort(V.begin(), V.end(),
303                      [](const SamplesWithLoc *A, const SamplesWithLoc *B) {
304                        return A->first < B->first;
305                      });
306   }
307   const SamplesWithLocList &get() const { return V; }
308
309 private:
310   SamplesWithLocList V;
311 };
312
313 } // end namespace sampleprof
314
315 } // end namespace llvm
316
317 #endif // LLVM_PROFILEDATA_SAMPLEPROF_H_