xref: /llvm-project/llvm/include/llvm/ProfileData/InstrProfCorrelator.h (revision e03f427196ec67a8a5cfbdd658f9eabe9bce83ce)
1 //===- InstrProfCorrelator.h ------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 // This file defines InstrProfCorrelator used to generate PGO/coverage profiles
9 // from raw profile data and debug info/binary file.
10 //===----------------------------------------------------------------------===//
11 
12 #ifndef LLVM_PROFILEDATA_INSTRPROFCORRELATOR_H
13 #define LLVM_PROFILEDATA_INSTRPROFCORRELATOR_H
14 
15 #include "llvm/ADT/DenseSet.h"
16 #include "llvm/Debuginfod/BuildIDFetcher.h"
17 #include "llvm/Object/BuildID.h"
18 #include "llvm/ProfileData/InstrProf.h"
19 #include "llvm/Support/Error.h"
20 #include "llvm/Support/MemoryBuffer.h"
21 #include "llvm/Support/YAMLTraits.h"
22 #include <optional>
23 #include <vector>
24 
25 namespace llvm {
26 class DWARFContext;
27 class DWARFDie;
28 namespace object {
29 class ObjectFile;
30 }
31 
32 /// InstrProfCorrelator - A base class used to create raw instrumentation data
33 /// to their functions.
34 class InstrProfCorrelator {
35 public:
36   /// Indicate if we should use the debug info or profile metadata sections to
37   /// correlate.
38   enum ProfCorrelatorKind { NONE, DEBUG_INFO, BINARY };
39 
40   static llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
41   get(StringRef Filename, ProfCorrelatorKind FileKind,
42       const object::BuildIDFetcher *BIDFetcher = nullptr,
43       const ArrayRef<llvm::object::BuildID> BIs = {});
44 
45   /// Construct a ProfileData vector used to correlate raw instrumentation data
46   /// to their functions.
47   /// \param MaxWarnings the maximum number of warnings to emit (0 = no limit)
48   virtual Error correlateProfileData(int MaxWarnings) = 0;
49 
50   /// Process debug info and dump the correlation data.
51   /// \param MaxWarnings the maximum number of warnings to emit (0 = no limit)
52   virtual Error dumpYaml(int MaxWarnings, raw_ostream &OS) = 0;
53 
54   /// Return the number of ProfileData elements.
55   std::optional<size_t> getDataSize() const;
56 
57   /// Return a pointer to the names string that this class constructs.
58   const char *getNamesPointer() const { return Names.c_str(); }
59 
60   /// Return the number of bytes in the names string.
61   size_t getNamesSize() const { return Names.size(); }
62 
63   /// Return the size of the counters section in bytes.
64   uint64_t getCountersSectionSize() const {
65     return Ctx->CountersSectionEnd - Ctx->CountersSectionStart;
66   }
67 
68   static const char *FunctionNameAttributeName;
69   static const char *CFGHashAttributeName;
70   static const char *NumCountersAttributeName;
71 
72   enum InstrProfCorrelatorKind { CK_32Bit, CK_64Bit };
73   InstrProfCorrelatorKind getKind() const { return Kind; }
74   virtual ~InstrProfCorrelator() = default;
75 
76 protected:
77   struct Context {
78     static llvm::Expected<std::unique_ptr<Context>>
79     get(std::unique_ptr<MemoryBuffer> Buffer, const object::ObjectFile &Obj,
80         ProfCorrelatorKind FileKind);
81     std::unique_ptr<MemoryBuffer> Buffer;
82     /// The address range of the __llvm_prf_cnts section.
83     uint64_t CountersSectionStart;
84     uint64_t CountersSectionEnd;
85     /// The pointer points to start/end of profile data/name sections if
86     /// FileKind is Binary.
87     const char *DataStart;
88     const char *DataEnd;
89     const char *NameStart;
90     size_t NameSize;
91     /// True if target and host have different endian orders.
92     bool ShouldSwapBytes;
93   };
94   const std::unique_ptr<Context> Ctx;
95 
96   InstrProfCorrelator(InstrProfCorrelatorKind K, std::unique_ptr<Context> Ctx)
97       : Ctx(std::move(Ctx)), Kind(K) {}
98 
99   std::string Names;
100   std::vector<std::string> NamesVec;
101 
102   struct Probe {
103     std::string FunctionName;
104     std::optional<std::string> LinkageName;
105     yaml::Hex64 CFGHash;
106     yaml::Hex64 CounterOffset;
107     uint32_t NumCounters;
108     std::optional<std::string> FilePath;
109     std::optional<int> LineNumber;
110   };
111 
112   struct CorrelationData {
113     std::vector<Probe> Probes;
114   };
115 
116   friend struct yaml::MappingTraits<Probe>;
117   friend struct yaml::SequenceElementTraits<Probe>;
118   friend struct yaml::MappingTraits<CorrelationData>;
119 
120 private:
121   static llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
122   get(std::unique_ptr<MemoryBuffer> Buffer, ProfCorrelatorKind FileKind);
123 
124   const InstrProfCorrelatorKind Kind;
125 };
126 
127 /// InstrProfCorrelatorImpl - A child of InstrProfCorrelator with a template
128 /// pointer type so that the ProfileData vector can be materialized.
129 template <class IntPtrT>
130 class InstrProfCorrelatorImpl : public InstrProfCorrelator {
131 public:
132   InstrProfCorrelatorImpl(std::unique_ptr<InstrProfCorrelator::Context> Ctx);
133   static bool classof(const InstrProfCorrelator *C);
134 
135   /// Return a pointer to the underlying ProfileData vector that this class
136   /// constructs.
137   const RawInstrProf::ProfileData<IntPtrT> *getDataPointer() const {
138     return Data.empty() ? nullptr : Data.data();
139   }
140 
141   /// Return the number of ProfileData elements.
142   size_t getDataSize() const { return Data.size(); }
143 
144   static llvm::Expected<std::unique_ptr<InstrProfCorrelatorImpl<IntPtrT>>>
145   get(std::unique_ptr<InstrProfCorrelator::Context> Ctx,
146       const object::ObjectFile &Obj, ProfCorrelatorKind FileKind);
147 
148 protected:
149   std::vector<RawInstrProf::ProfileData<IntPtrT>> Data;
150 
151   Error correlateProfileData(int MaxWarnings) override;
152   virtual void correlateProfileDataImpl(
153       int MaxWarnings,
154       InstrProfCorrelator::CorrelationData *Data = nullptr) = 0;
155 
156   virtual Error correlateProfileNameImpl() = 0;
157 
158   Error dumpYaml(int MaxWarnings, raw_ostream &OS) override;
159 
160   void addDataProbe(uint64_t FunctionName, uint64_t CFGHash,
161                     IntPtrT CounterOffset, IntPtrT FunctionPtr,
162                     uint32_t NumCounters);
163 
164   // Byte-swap the value if necessary.
165   template <class T> T maybeSwap(T Value) const {
166     return Ctx->ShouldSwapBytes ? llvm::byteswap(Value) : Value;
167   }
168 
169 private:
170   InstrProfCorrelatorImpl(InstrProfCorrelatorKind Kind,
171                           std::unique_ptr<InstrProfCorrelator::Context> Ctx)
172       : InstrProfCorrelator(Kind, std::move(Ctx)){};
173   llvm::DenseSet<IntPtrT> CounterOffsets;
174 };
175 
176 /// DwarfInstrProfCorrelator - A child of InstrProfCorrelatorImpl that takes
177 /// DWARF debug info as input to correlate profiles.
178 template <class IntPtrT>
179 class DwarfInstrProfCorrelator : public InstrProfCorrelatorImpl<IntPtrT> {
180 public:
181   DwarfInstrProfCorrelator(std::unique_ptr<DWARFContext> DICtx,
182                            std::unique_ptr<InstrProfCorrelator::Context> Ctx)
183       : InstrProfCorrelatorImpl<IntPtrT>(std::move(Ctx)),
184         DICtx(std::move(DICtx)) {}
185 
186 private:
187   std::unique_ptr<DWARFContext> DICtx;
188 
189   /// Return the address of the object that the provided DIE symbolizes.
190   std::optional<uint64_t> getLocation(const DWARFDie &Die) const;
191 
192   /// Returns true if the provided DIE symbolizes an instrumentation probe
193   /// symbol.
194   static bool isDIEOfProbe(const DWARFDie &Die);
195 
196   /// Iterate over DWARF DIEs to find those that symbolize instrumentation
197   /// probes and construct the ProfileData vector and Names string.
198   ///
199   /// Here is some example DWARF for an instrumentation probe we are looking
200   /// for:
201   /// \code
202   ///   DW_TAG_subprogram
203   ///   DW_AT_low_pc	(0x0000000000000000)
204   ///   DW_AT_high_pc	(0x0000000000000014)
205   ///   DW_AT_name	("foo")
206   ///     DW_TAG_variable
207   ///       DW_AT_name	("__profc_foo")
208   ///       DW_AT_location	(DW_OP_addr 0x0)
209   ///       DW_TAG_LLVM_annotation
210   ///         DW_AT_name	("Function Name")
211   ///         DW_AT_const_value	("foo")
212   ///       DW_TAG_LLVM_annotation
213   ///         DW_AT_name	("CFG Hash")
214   ///         DW_AT_const_value	(12345678)
215   ///       DW_TAG_LLVM_annotation
216   ///         DW_AT_name	("Num Counters")
217   ///         DW_AT_const_value	(2)
218   ///       NULL
219   ///     NULL
220   /// \endcode
221   /// \param MaxWarnings the maximum number of warnings to emit (0 = no limit)
222   /// \param Data if provided, populate with the correlation data found
223   void correlateProfileDataImpl(
224       int MaxWarnings,
225       InstrProfCorrelator::CorrelationData *Data = nullptr) override;
226 
227   Error correlateProfileNameImpl() override;
228 };
229 
230 /// BinaryInstrProfCorrelator - A child of InstrProfCorrelatorImpl that
231 /// takes an object file as input to correlate profiles.
232 template <class IntPtrT>
233 class BinaryInstrProfCorrelator : public InstrProfCorrelatorImpl<IntPtrT> {
234 public:
235   BinaryInstrProfCorrelator(std::unique_ptr<InstrProfCorrelator::Context> Ctx)
236       : InstrProfCorrelatorImpl<IntPtrT>(std::move(Ctx)) {}
237 
238   /// Return a pointer to the names string that this class constructs.
239   const char *getNamesPointer() const { return this->Ctx.NameStart; }
240 
241   /// Return the number of bytes in the names string.
242   size_t getNamesSize() const { return this->Ctx.NameSize; }
243 
244 private:
245   void correlateProfileDataImpl(
246       int MaxWarnings,
247       InstrProfCorrelator::CorrelationData *Data = nullptr) override;
248 
249   Error correlateProfileNameImpl() override;
250 };
251 
252 } // end namespace llvm
253 
254 #endif // LLVM_PROFILEDATA_INSTRPROFCORRELATOR_H
255