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. |
54 | const char *getNamesPointer() const { return Names.c_str(); } |
55 | |
56 | /// Return the number of bytes in the names string. |
57 | size_t getNamesSize() const { return Names.size(); } |
58 | |
59 | /// Return the size of the counters section in bytes. |
60 | uint64_t () 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 }; |
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 ; |
80 | uint64_t ; |
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 | |
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 | |