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