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