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#ifndef LLVM_PROFILEDATA_SAMPLEPROF_H_
15#define LLVM_PROFILEDATA_SAMPLEPROF_H_
16
17#include "llvm/ADT/DenseMap.h"
18#include "llvm/ADT/SmallVector.h"
19#include "llvm/ADT/StringMap.h"
20#include "llvm/Support/Debug.h"
21#include "llvm/Support/raw_ostream.h"
22#include <system_error>
23
24namespace llvm {
25
26const std::error_category &sampleprof_category();
27
28enum class sampleprof_error {
29  success = 0,
30  bad_magic,
31  unsupported_version,
32  too_large,
33  truncated,
34  malformed,
35  unrecognized_format
36};
37
38inline std::error_code make_error_code(sampleprof_error E) {
39  return std::error_code(static_cast<int>(E), sampleprof_category());
40}
41
42} // end namespace llvm
43
44namespace std {
45template <>
46struct is_error_code_enum<llvm::sampleprof_error> : std::true_type {};
47}
48
49namespace llvm {
50
51namespace sampleprof {
52
53static inline uint64_t SPMagic() {
54  return uint64_t('S') << (64 - 8) | uint64_t('P') << (64 - 16) |
55         uint64_t('R') << (64 - 24) | uint64_t('O') << (64 - 32) |
56         uint64_t('F') << (64 - 40) | uint64_t('4') << (64 - 48) |
57         uint64_t('2') << (64 - 56) | uint64_t(0xff);
58}
59
60static inline uint64_t SPVersion() { return 100; }
61
62/// \brief Represents the relative location of an instruction.
63///
64/// Instruction locations are specified by the line offset from the
65/// beginning of the function (marked by the line where the function
66/// header is) and the discriminator value within that line.
67///
68/// The discriminator value is useful to distinguish instructions
69/// that are on the same line but belong to different basic blocks
70/// (e.g., the two post-increment instructions in "if (p) x++; else y++;").
71struct LineLocation {
72  LineLocation(int L, unsigned D) : LineOffset(L), Discriminator(D) {}
73  int LineOffset;
74  unsigned Discriminator;
75};
76
77} // End namespace sampleprof
78
79template <> struct DenseMapInfo<sampleprof::LineLocation> {
80  typedef DenseMapInfo<int> OffsetInfo;
81  typedef DenseMapInfo<unsigned> DiscriminatorInfo;
82  static inline sampleprof::LineLocation getEmptyKey() {
83    return sampleprof::LineLocation(OffsetInfo::getEmptyKey(),
84                                    DiscriminatorInfo::getEmptyKey());
85  }
86  static inline sampleprof::LineLocation getTombstoneKey() {
87    return sampleprof::LineLocation(OffsetInfo::getTombstoneKey(),
88                                    DiscriminatorInfo::getTombstoneKey());
89  }
90  static inline unsigned getHashValue(sampleprof::LineLocation Val) {
91    return DenseMapInfo<std::pair<int, unsigned>>::getHashValue(
92        std::pair<int, unsigned>(Val.LineOffset, Val.Discriminator));
93  }
94  static inline bool isEqual(sampleprof::LineLocation LHS,
95                             sampleprof::LineLocation RHS) {
96    return LHS.LineOffset == RHS.LineOffset &&
97           LHS.Discriminator == RHS.Discriminator;
98  }
99};
100
101namespace sampleprof {
102
103/// \brief 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.
113class SampleRecord {
114public:
115  typedef StringMap<unsigned> CallTargetMap;
116
117  SampleRecord() : NumSamples(0), CallTargets() {}
118
119  /// \brief Increment the number of samples for this record by \p S.
120  ///
121  /// Sample counts accumulate using saturating arithmetic, to avoid wrapping
122  /// around unsigned integers.
123  void addSamples(unsigned S) {
124    if (NumSamples <= std::numeric_limits<unsigned>::max() - S)
125      NumSamples += S;
126    else
127      NumSamples = std::numeric_limits<unsigned>::max();
128  }
129
130  /// \brief Add called function \p F with samples \p S.
131  ///
132  /// Sample counts accumulate using saturating arithmetic, to avoid wrapping
133  /// around unsigned integers.
134  void addCalledTarget(StringRef F, unsigned S) {
135    unsigned &TargetSamples = CallTargets[F];
136    if (TargetSamples <= std::numeric_limits<unsigned>::max() - S)
137      TargetSamples += S;
138    else
139      TargetSamples = std::numeric_limits<unsigned>::max();
140  }
141
142  /// \brief Return true if this sample record contains function calls.
143  bool hasCalls() const { return CallTargets.size() > 0; }
144
145  unsigned getSamples() const { return NumSamples; }
146  const CallTargetMap &getCallTargets() const { return CallTargets; }
147
148  /// \brief Merge the samples in \p Other into this record.
149  void merge(const SampleRecord &Other) {
150    addSamples(Other.getSamples());
151    for (const auto &I : Other.getCallTargets())
152      addCalledTarget(I.first(), I.second);
153  }
154
155private:
156  unsigned NumSamples;
157  CallTargetMap CallTargets;
158};
159
160typedef DenseMap<LineLocation, SampleRecord> BodySampleMap;
161
162/// \brief Representation of the samples collected for a function.
163///
164/// This data structure contains all the collected samples for the body
165/// of a function. Each sample corresponds to a LineLocation instance
166/// within the body of the function.
167class FunctionSamples {
168public:
169  FunctionSamples() : TotalSamples(0), TotalHeadSamples(0) {}
170  void print(raw_ostream &OS = dbgs());
171  void addTotalSamples(unsigned Num) { TotalSamples += Num; }
172  void addHeadSamples(unsigned Num) { TotalHeadSamples += Num; }
173  void addBodySamples(int LineOffset, unsigned Discriminator, unsigned Num) {
174    assert(LineOffset >= 0);
175    // When dealing with instruction weights, we use the value
176    // zero to indicate the absence of a sample. If we read an
177    // actual zero from the profile file, use the value 1 to
178    // avoid the confusion later on.
179    if (Num == 0)
180      Num = 1;
181    BodySamples[LineLocation(LineOffset, Discriminator)].addSamples(Num);
182  }
183  void addCalledTargetSamples(int LineOffset, unsigned Discriminator,
184                              std::string FName, unsigned Num) {
185    assert(LineOffset >= 0);
186    BodySamples[LineLocation(LineOffset, Discriminator)].addCalledTarget(FName,
187                                                                         Num);
188  }
189
190  /// \brief Return the sample record at the given location.
191  /// Each location is specified by \p LineOffset and \p Discriminator.
192  SampleRecord &sampleRecordAt(const LineLocation &Loc) {
193    return BodySamples[Loc];
194  }
195
196  /// \brief Return the number of samples collected at the given location.
197  /// Each location is specified by \p LineOffset and \p Discriminator.
198  unsigned samplesAt(int LineOffset, unsigned Discriminator) {
199    return sampleRecordAt(LineLocation(LineOffset, Discriminator)).getSamples();
200  }
201
202  bool empty() const { return BodySamples.empty(); }
203
204  /// \brief Return the total number of samples collected inside the function.
205  unsigned getTotalSamples() const { return TotalSamples; }
206
207  /// \brief Return the total number of samples collected at the head of the
208  /// function.
209  unsigned getHeadSamples() const { return TotalHeadSamples; }
210
211  /// \brief Return all the samples collected in the body of the function.
212  const BodySampleMap &getBodySamples() const { return BodySamples; }
213
214  /// \brief Merge the samples in \p Other into this one.
215  void merge(const FunctionSamples &Other) {
216    addTotalSamples(Other.getTotalSamples());
217    addHeadSamples(Other.getHeadSamples());
218    for (const auto &I : Other.getBodySamples()) {
219      const LineLocation &Loc = I.first;
220      const SampleRecord &Rec = I.second;
221      sampleRecordAt(Loc).merge(Rec);
222    }
223  }
224
225private:
226  /// \brief Total number of samples collected inside this function.
227  ///
228  /// Samples are cumulative, they include all the samples collected
229  /// inside this function and all its inlined callees.
230  unsigned TotalSamples;
231
232  /// \brief Total number of samples collected at the head of the function.
233  unsigned TotalHeadSamples;
234
235  /// \brief Map instruction locations to collected samples.
236  ///
237  /// Each entry in this map contains the number of samples
238  /// collected at the corresponding line offset. All line locations
239  /// are an offset from the start of the function.
240  BodySampleMap BodySamples;
241};
242
243} // End namespace sampleprof
244
245} // End namespace llvm
246
247#endif // LLVM_PROFILEDATA_SAMPLEPROF_H_
248