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