LLVM  12.0.0git
IntelJITEventListener.cpp
Go to the documentation of this file.
1 //===-- IntelJITEventListener.cpp - Tell Intel profiler about JITed code --===//
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 //
9 // This file defines a JITEventListener object to tell Intel(R) VTune(TM)
10 // Amplifier XE 2011 about JITted functions.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "IntelJITEventsWrapper.h"
15 #include "llvm-c/ExecutionEngine.h"
16 #include "llvm/ADT/DenseMap.h"
18 #include "llvm/Config/config.h"
22 #include "llvm/IR/DebugInfo.h"
23 #include "llvm/IR/Function.h"
24 #include "llvm/IR/Metadata.h"
25 #include "llvm/IR/ValueHandle.h"
26 #include "llvm/Object/ObjectFile.h"
27 #include "llvm/Object/SymbolSize.h"
28 #include "llvm/Support/Debug.h"
29 #include "llvm/Support/Errno.h"
31 
32 using namespace llvm;
33 using namespace llvm::object;
34 
35 #define DEBUG_TYPE "amplifier-jit-event-listener"
36 
37 namespace {
38 
39 class IntelJITEventListener : public JITEventListener {
40  typedef DenseMap<void*, unsigned int> MethodIDMap;
41 
42  std::unique_ptr<IntelJITEventsWrapper> Wrapper;
43  MethodIDMap MethodIDs;
44 
45  typedef SmallVector<const void *, 64> MethodAddressVector;
47 
48  ObjectMap LoadedObjectMap;
49  std::map<ObjectKey, OwningBinary<ObjectFile>> DebugObjects;
50 
51 public:
52  IntelJITEventListener(IntelJITEventsWrapper* libraryWrapper) {
53  Wrapper.reset(libraryWrapper);
54  }
55 
56  ~IntelJITEventListener() {
57  }
58 
59  void notifyObjectLoaded(ObjectKey Key, const ObjectFile &Obj,
60  const RuntimeDyld::LoadedObjectInfo &L) override;
61 
62  void notifyFreeingObject(ObjectKey Key) override;
63 };
64 
65 static LineNumberInfo DILineInfoToIntelJITFormat(uintptr_t StartAddress,
66  uintptr_t Address,
67  DILineInfo Line) {
68  LineNumberInfo Result;
69 
70  Result.Offset = Address - StartAddress;
71  Result.LineNumber = Line.Line;
72 
73  return Result;
74 }
75 
76 static iJIT_Method_Load FunctionDescToIntelJITFormat(
78  const char* FnName,
79  uintptr_t FnStart,
80  size_t FnSize) {
81  iJIT_Method_Load Result;
82  memset(&Result, 0, sizeof(iJIT_Method_Load));
83 
84  Result.method_id = Wrapper.iJIT_GetNewMethodID();
85  Result.method_name = const_cast<char*>(FnName);
86  Result.method_load_address = reinterpret_cast<void*>(FnStart);
87  Result.method_size = FnSize;
88 
89  Result.class_id = 0;
90  Result.class_file_name = NULL;
91  Result.user_data = NULL;
92  Result.user_data_size = 0;
93  Result.env = iJDE_JittingAPI;
94 
95  return Result;
96 }
97 
98 void IntelJITEventListener::notifyObjectLoaded(
99  ObjectKey Key, const ObjectFile &Obj,
101 
102  OwningBinary<ObjectFile> DebugObjOwner = L.getObjectForDebug(Obj);
103  const ObjectFile *DebugObj = DebugObjOwner.getBinary();
104  if (!DebugObj)
105  return;
106 
107  // Get the address of the object image for use as a unique identifier
108  const void* ObjData = DebugObj->getData().data();
109  std::unique_ptr<DIContext> Context = DWARFContext::create(*DebugObj);
110  MethodAddressVector Functions;
111 
112  // Use symbol info to iterate functions in the object.
113  for (const std::pair<SymbolRef, uint64_t> &P : computeSymbolSizes(*DebugObj)) {
114  SymbolRef Sym = P.first;
115  std::vector<LineNumberInfo> LineInfo;
116  std::string SourceFileName;
117 
118  Expected<SymbolRef::Type> SymTypeOrErr = Sym.getType();
119  if (!SymTypeOrErr) {
120  // TODO: Actually report errors helpfully.
121  consumeError(SymTypeOrErr.takeError());
122  continue;
123  }
124  SymbolRef::Type SymType = *SymTypeOrErr;
125  if (SymType != SymbolRef::ST_Function)
126  continue;
127 
129  if (!Name) {
130  // TODO: Actually report errors helpfully.
131  consumeError(Name.takeError());
132  continue;
133  }
134 
135  Expected<uint64_t> AddrOrErr = Sym.getAddress();
136  if (!AddrOrErr) {
137  // TODO: Actually report errors helpfully.
138  consumeError(AddrOrErr.takeError());
139  continue;
140  }
141  uint64_t Addr = *AddrOrErr;
142  uint64_t Size = P.second;
143 
144  auto SecOrErr = Sym.getSection();
145  if (!SecOrErr) {
146  // TODO: Actually report errors helpfully.
147  consumeError(SecOrErr.takeError());
148  continue;
149  }
150  object::section_iterator Sec = *SecOrErr;
151  if (Sec == Obj.section_end())
152  continue;
153  uint64_t Index = Sec->getIndex();
154 
155  // Record this address in a local vector
156  Functions.push_back((void*)Addr);
157 
158  // Build the function loaded notification message
159  iJIT_Method_Load FunctionMessage =
160  FunctionDescToIntelJITFormat(*Wrapper, Name->data(), Addr, Size);
161  DILineInfoTable Lines =
162  Context->getLineInfoForAddressRange({Addr, Index}, Size);
163  DILineInfoTable::iterator Begin = Lines.begin();
164  DILineInfoTable::iterator End = Lines.end();
165  for (DILineInfoTable::iterator It = Begin; It != End; ++It) {
166  LineInfo.push_back(
167  DILineInfoToIntelJITFormat((uintptr_t)Addr, It->first, It->second));
168  }
169  if (LineInfo.size() == 0) {
170  FunctionMessage.source_file_name = 0;
171  FunctionMessage.line_number_size = 0;
172  FunctionMessage.line_number_table = 0;
173  } else {
174  // Source line information for the address range is provided as
175  // a code offset for the start of the corresponding sub-range and
176  // a source line. JIT API treats offsets in LineNumberInfo structures
177  // as the end of the corresponding code region. The start of the code
178  // is taken from the previous element. Need to shift the elements.
179 
180  LineNumberInfo last = LineInfo.back();
181  last.Offset = FunctionMessage.method_size;
182  LineInfo.push_back(last);
183  for (size_t i = LineInfo.size() - 2; i > 0; --i)
184  LineInfo[i].LineNumber = LineInfo[i - 1].LineNumber;
185 
186  SourceFileName = Lines.front().second.FileName;
187  FunctionMessage.source_file_name =
188  const_cast<char *>(SourceFileName.c_str());
189  FunctionMessage.line_number_size = LineInfo.size();
190  FunctionMessage.line_number_table = &*LineInfo.begin();
191  }
192 
194  &FunctionMessage);
195  MethodIDs[(void*)Addr] = FunctionMessage.method_id;
196  }
197 
198  // To support object unload notification, we need to keep a list of
199  // registered function addresses for each loaded object. We will
200  // use the MethodIDs map to get the registered ID for each function.
201  LoadedObjectMap[ObjData] = Functions;
202  DebugObjects[Key] = std::move(DebugObjOwner);
203 }
204 
205 void IntelJITEventListener::notifyFreeingObject(ObjectKey Key) {
206  // This object may not have been registered with the listener. If it wasn't,
207  // bail out.
208  if (DebugObjects.find(Key) == DebugObjects.end())
209  return;
210 
211  // Get the address of the object image for use as a unique identifier
212  const ObjectFile &DebugObj = *DebugObjects[Key].getBinary();
213  const void* ObjData = DebugObj.getData().data();
214 
215  // Get the object's function list from LoadedObjectMap
216  ObjectMap::iterator OI = LoadedObjectMap.find(ObjData);
217  if (OI == LoadedObjectMap.end())
218  return;
219  MethodAddressVector& Functions = OI->second;
220 
221  // Walk the function list, unregistering each function
222  for (MethodAddressVector::iterator FI = Functions.begin(),
223  FE = Functions.end();
224  FI != FE;
225  ++FI) {
226  void* FnStart = const_cast<void*>(*FI);
227  MethodIDMap::iterator MI = MethodIDs.find(FnStart);
228  if (MI != MethodIDs.end()) {
230  &MI->second);
231  MethodIDs.erase(MI);
232  }
233  }
234 
235  // Erase the object from LoadedObjectMap
236  LoadedObjectMap.erase(OI);
237  DebugObjects.erase(Key);
238 }
239 
240 } // anonymous namespace.
241 
242 namespace llvm {
244  return new IntelJITEventListener(new IntelJITEventsWrapper);
245 }
246 
247 // for testing
249  IntelJITEventsWrapper* TestImpl) {
250  return new IntelJITEventListener(TestImpl);
251 }
252 
253 } // namespace llvm
254 
256 {
258 }
static JITEventListener * createIntelJITEventListener()
Information about the loaded object.
Definition: RuntimeDyld.h:70
LLVMContext & Context
unsigned int LineNumber
Definition: jitprofiling.h:170
unsigned int Offset
Definition: jitprofiling.h:167
This class represents lattice values for constants.
Definition: AllocatorList.h:23
Expected< StringRef > getName() const
Definition: ObjectFile.h:384
amdgpu Simplify well known AMD library false FunctionCallee Value const Twine & Name
JITEventListener - Abstract interface for use by the JIT to notify clients about significant events d...
This file contains the declarations for metadata subclasses.
This class is the base class for all object file types.
Definition: ObjectFile.h:225
Error takeError()
Take ownership of the stored error.
Definition: Error.h:557
unsigned int class_id
Definition: jitprofiling.h:199
A format-neutral container for source line information.
Definition: DIContext.h:31
iJDEnvironmentType env
Definition: jitprofiling.h:214
amdgpu aa AMDGPU Address space based Alias Analysis Wrapper
pLineNumberInfo line_number_table
Definition: jitprofiling.h:196
Tagged union holding either a T or a Error.
Definition: APFloat.h:42
Key
PAL metadata keys.
LLVMJITEventListenerRef LLVMCreateIntelJITEventListener(void)
Expected< section_iterator > getSection() const
Get section this symbol is defined in reference to.
Definition: ObjectFile.h:404
#define P(N)
void * method_load_address
Definition: jitprofiling.h:187
unsigned int user_data_size
Definition: jitprofiling.h:211
Expected< uint64_t > getAddress() const
Returns the symbol virtual address (i.e.
Definition: ObjectFile.h:388
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:1006
unsigned int method_id
Definition: jitprofiling.h:177
static std::unique_ptr< DWARFContext > create(const object::ObjectFile &Obj, const LoadedObjectInfo *L=nullptr, std::string DWPName="", std::function< void(Error)> RecoverableErrorHandler=WithColor::defaultErrorHandler, std::function< void(Error)> WarningHandler=WithColor::defaultWarningHandler)
unsigned int line_number_size
Definition: jitprofiling.h:193
int iJIT_NotifyEvent(iJIT_JVM_EVENT EventType, void *EventSpecificData)
virtual object::OwningBinary< object::ObjectFile > getObjectForDebug(const object::ObjectFile &Obj) const =0
uint32_t Line
Definition: DIContext.h:39
unsigned int iJIT_GetNewMethodID(void)
Expected< SymbolRef::Type > getType() const
Definition: ObjectFile.h:408
This is a &#39;vector&#39; (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:883
std::vector< std::pair< SymbolRef, uint64_t > > computeSymbolSizes(const ObjectFile &O)
Definition: SymbolSize.cpp:46
typename SuperClass::iterator iterator
Definition: SmallVector.h:365
This is a value type class that represents a single symbol in the list of symbols in the object file...
Definition: ObjectFile.h:164
unsigned int method_size
Definition: jitprofiling.h:190
LLVMAttributeRef wrap(Attribute Attr)
Definition: Attributes.h:212
virtual section_iterator section_end() const =0
uint32_t Size
Definition: Profile.cpp:46
LLVM_NODISCARD const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
Definition: StringRef.h:152
struct LLVMOpaqueJITEventListener * LLVMJITEventListenerRef
Definition: Types.h:163
IRTranslator LLVM IR MI
StringRef getData() const
Definition: Binary.cpp:40