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