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