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 profiles from
9 // raw profile data and debug info.
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   static llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
35   get(StringRef DebugInfoFilename);
36 
37   /// Construct a ProfileData vector used to correlate raw instrumentation data
38   /// to their functions.
39   virtual Error correlateProfileData() = 0;
40 
41   /// Process debug info and dump the correlation data.
42   virtual Error dumpYaml(raw_ostream &OS) = 0;
43 
44   /// Return the number of ProfileData elements.
45   std::optional<size_t> getDataSize() const;
46 
47   /// Return a pointer to the names string that this class constructs.
48   const char *getNamesPointer() const { return Names.c_str(); }
49 
50   /// Return the number of bytes in the names string.
51   size_t getNamesSize() const { return Names.size(); }
52 
53   /// Return the size of the counters section in bytes.
54   uint64_t getCountersSectionSize() const {
55     return Ctx->CountersSectionEnd - Ctx->CountersSectionStart;
56   }
57 
58   static const char *FunctionNameAttributeName;
59   static const char *CFGHashAttributeName;
60   static const char *NumCountersAttributeName;
61 
62   enum InstrProfCorrelatorKind { CK_32Bit, CK_64Bit };
63   InstrProfCorrelatorKind getKind() const { return Kind; }
64   virtual ~InstrProfCorrelator() = default;
65 
66 protected:
67   struct Context {
68     static llvm::Expected<std::unique_ptr<Context>>
69     get(std::unique_ptr<MemoryBuffer> Buffer, const object::ObjectFile &Obj);
70     std::unique_ptr<MemoryBuffer> Buffer;
71     /// The address range of the __llvm_prf_cnts section.
72     uint64_t CountersSectionStart;
73     uint64_t CountersSectionEnd;
74     /// True if target and host have different endian orders.
75     bool ShouldSwapBytes;
76   };
77   const std::unique_ptr<Context> Ctx;
78 
79   InstrProfCorrelator(InstrProfCorrelatorKind K, std::unique_ptr<Context> Ctx)
80       : Ctx(std::move(Ctx)), Kind(K) {}
81 
82   std::string Names;
83   std::vector<std::string> NamesVec;
84 
85   struct Probe {
86     std::string FunctionName;
87     std::optional<std::string> LinkageName;
88     yaml::Hex64 CFGHash;
89     yaml::Hex64 CounterOffset;
90     uint32_t NumCounters;
91     std::optional<std::string> FilePath;
92     std::optional<int> LineNumber;
93   };
94 
95   struct CorrelationData {
96     std::vector<Probe> Probes;
97   };
98 
99   friend struct yaml::MappingTraits<Probe>;
100   friend struct yaml::SequenceElementTraits<Probe>;
101   friend struct yaml::MappingTraits<CorrelationData>;
102 
103 private:
104   static llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
105   get(std::unique_ptr<MemoryBuffer> Buffer);
106 
107   const InstrProfCorrelatorKind Kind;
108 };
109 
110 /// InstrProfCorrelatorImpl - A child of InstrProfCorrelator with a template
111 /// pointer type so that the ProfileData vector can be materialized.
112 template <class IntPtrT>
113 class InstrProfCorrelatorImpl : public InstrProfCorrelator {
114 public:
115   InstrProfCorrelatorImpl(std::unique_ptr<InstrProfCorrelator::Context> Ctx);
116   static bool classof(const InstrProfCorrelator *C);
117 
118   /// Return a pointer to the underlying ProfileData vector that this class
119   /// constructs.
120   const RawInstrProf::ProfileData<IntPtrT> *getDataPointer() const {
121     return Data.empty() ? nullptr : Data.data();
122   }
123 
124   /// Return the number of ProfileData elements.
125   size_t getDataSize() const { return Data.size(); }
126 
127   static llvm::Expected<std::unique_ptr<InstrProfCorrelatorImpl<IntPtrT>>>
128   get(std::unique_ptr<InstrProfCorrelator::Context> Ctx,
129       const object::ObjectFile &Obj);
130 
131 protected:
132   std::vector<RawInstrProf::ProfileData<IntPtrT>> Data;
133 
134   Error correlateProfileData() override;
135   virtual void correlateProfileDataImpl(
136       InstrProfCorrelator::CorrelationData *Data = nullptr) = 0;
137 
138   Error dumpYaml(raw_ostream &OS) override;
139 
140   void addProbe(StringRef FunctionName, uint64_t CFGHash, IntPtrT CounterOffset,
141                 IntPtrT FunctionPtr, uint32_t NumCounters);
142 
143 private:
144   InstrProfCorrelatorImpl(InstrProfCorrelatorKind Kind,
145                           std::unique_ptr<InstrProfCorrelator::Context> Ctx)
146       : InstrProfCorrelator(Kind, std::move(Ctx)){};
147   llvm::DenseSet<IntPtrT> CounterOffsets;
148 
149   // Byte-swap the value if necessary.
150   template <class T> T maybeSwap(T Value) const {
151     return Ctx->ShouldSwapBytes ? sys::getSwappedBytes(Value) : Value;
152   }
153 };
154 
155 /// DwarfInstrProfCorrelator - A child of InstrProfCorrelatorImpl that takes
156 /// DWARF debug info as input to correlate profiles.
157 template <class IntPtrT>
158 class DwarfInstrProfCorrelator : public InstrProfCorrelatorImpl<IntPtrT> {
159 public:
160   DwarfInstrProfCorrelator(std::unique_ptr<DWARFContext> DICtx,
161                            std::unique_ptr<InstrProfCorrelator::Context> Ctx)
162       : InstrProfCorrelatorImpl<IntPtrT>(std::move(Ctx)),
163         DICtx(std::move(DICtx)) {}
164 
165 private:
166   std::unique_ptr<DWARFContext> DICtx;
167 
168   /// Return the address of the object that the provided DIE symbolizes.
169   std::optional<uint64_t> getLocation(const DWARFDie &Die) const;
170 
171   /// Returns true if the provided DIE symbolizes an instrumentation probe
172   /// symbol.
173   static bool isDIEOfProbe(const DWARFDie &Die);
174 
175   /// Iterate over DWARF DIEs to find those that symbolize instrumentation
176   /// probes and construct the ProfileData vector and Names string.
177   ///
178   /// Here is some example DWARF for an instrumentation probe we are looking
179   /// for:
180   /// \code
181   ///   DW_TAG_subprogram
182   ///   DW_AT_low_pc	(0x0000000000000000)
183   ///   DW_AT_high_pc	(0x0000000000000014)
184   ///   DW_AT_name	("foo")
185   ///     DW_TAG_variable
186   ///       DW_AT_name	("__profc_foo")
187   ///       DW_AT_location	(DW_OP_addr 0x0)
188   ///       DW_TAG_LLVM_annotation
189   ///         DW_AT_name	("Function Name")
190   ///         DW_AT_const_value	("foo")
191   ///       DW_TAG_LLVM_annotation
192   ///         DW_AT_name	("CFG Hash")
193   ///         DW_AT_const_value	(12345678)
194   ///       DW_TAG_LLVM_annotation
195   ///         DW_AT_name	("Num Counters")
196   ///         DW_AT_const_value	(2)
197   ///       NULL
198   ///     NULL
199   /// \endcode
200   void correlateProfileDataImpl(
201       InstrProfCorrelator::CorrelationData *Data = nullptr) override;
202 };
203 
204 } // end namespace llvm
205 
206 #endif // LLVM_PROFILEDATA_INSTRPROFCORRELATOR_H
207