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