LLVM  4.0.0
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 "llvm/Config/config.h"
16 #include "IntelJITEventsWrapper.h"
17 #include "llvm/ADT/DenseMap.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<const char*, OwningBinary<ObjectFile>> DebugObjects;
50 
51 public:
52  IntelJITEventListener(IntelJITEventsWrapper* libraryWrapper) {
53  Wrapper.reset(libraryWrapper);
54  }
55 
56  ~IntelJITEventListener() {
57  }
58 
59  void NotifyObjectEmitted(const ObjectFile &Obj,
60  const RuntimeDyld::LoadedObjectInfo &L) override;
61 
62  void NotifyFreeingObject(const ObjectFile &Obj) 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::NotifyObjectEmitted(
99  const ObjectFile &Obj,
101 
102  OwningBinary<ObjectFile> DebugObjOwner = L.getObjectForDebug(Obj);
103  const ObjectFile &DebugObj = *DebugObjOwner.getBinary();
104 
105  // Get the address of the object image for use as a unique identifier
106  const void* ObjData = DebugObj.getData().data();
107  DIContext* Context = new DWARFContextInMemory(DebugObj);
108  MethodAddressVector Functions;
109 
110  // Use symbol info to iterate functions in the object.
111  for (const std::pair<SymbolRef, uint64_t> &P : computeSymbolSizes(DebugObj)) {
112  SymbolRef Sym = P.first;
113  std::vector<LineNumberInfo> LineInfo;
114  std::string SourceFileName;
115 
116  Expected<SymbolRef::Type> SymTypeOrErr = Sym.getType();
117  if (!SymTypeOrErr) {
118  // TODO: Actually report errors helpfully.
119  consumeError(SymTypeOrErr.takeError());
120  continue;
121  }
122  SymbolRef::Type SymType = *SymTypeOrErr;
123  if (SymType != SymbolRef::ST_Function)
124  continue;
125 
127  if (!Name) {
128  // TODO: Actually report errors helpfully.
129  consumeError(Name.takeError());
130  continue;
131  }
132 
133  Expected<uint64_t> AddrOrErr = Sym.getAddress();
134  if (!AddrOrErr) {
135  // TODO: Actually report errors helpfully.
136  consumeError(AddrOrErr.takeError());
137  continue;
138  }
139  uint64_t Addr = *AddrOrErr;
140  uint64_t Size = P.second;
141 
142  // Record this address in a local vector
143  Functions.push_back((void*)Addr);
144 
145  // Build the function loaded notification message
146  iJIT_Method_Load FunctionMessage =
147  FunctionDescToIntelJITFormat(*Wrapper, Name->data(), Addr, Size);
148  DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size);
149  DILineInfoTable::iterator Begin = Lines.begin();
150  DILineInfoTable::iterator End = Lines.end();
151  for (DILineInfoTable::iterator It = Begin; It != End; ++It) {
152  LineInfo.push_back(
153  DILineInfoToIntelJITFormat((uintptr_t)Addr, It->first, It->second));
154  }
155  if (LineInfo.size() == 0) {
156  FunctionMessage.source_file_name = 0;
157  FunctionMessage.line_number_size = 0;
158  FunctionMessage.line_number_table = 0;
159  } else {
160  // Source line information for the address range is provided as
161  // a code offset for the start of the corresponding sub-range and
162  // a source line. JIT API treats offsets in LineNumberInfo structures
163  // as the end of the corresponding code region. The start of the code
164  // is taken from the previous element. Need to shift the elements.
165 
166  LineNumberInfo last = LineInfo.back();
167  last.Offset = FunctionMessage.method_size;
168  LineInfo.push_back(last);
169  for (size_t i = LineInfo.size() - 2; i > 0; --i)
170  LineInfo[i].LineNumber = LineInfo[i - 1].LineNumber;
171 
172  SourceFileName = Lines.front().second.FileName;
173  FunctionMessage.source_file_name =
174  const_cast<char *>(SourceFileName.c_str());
175  FunctionMessage.line_number_size = LineInfo.size();
176  FunctionMessage.line_number_table = &*LineInfo.begin();
177  }
178 
180  &FunctionMessage);
181  MethodIDs[(void*)Addr] = FunctionMessage.method_id;
182  }
183 
184  // To support object unload notification, we need to keep a list of
185  // registered function addresses for each loaded object. We will
186  // use the MethodIDs map to get the registered ID for each function.
187  LoadedObjectMap[ObjData] = Functions;
188  DebugObjects[Obj.getData().data()] = std::move(DebugObjOwner);
189 }
190 
191 void IntelJITEventListener::NotifyFreeingObject(const ObjectFile &Obj) {
192  // This object may not have been registered with the listener. If it wasn't,
193  // bail out.
194  if (DebugObjects.find(Obj.getData().data()) == DebugObjects.end())
195  return;
196 
197  // Get the address of the object image for use as a unique identifier
198  const ObjectFile &DebugObj = *DebugObjects[Obj.getData().data()].getBinary();
199  const void* ObjData = DebugObj.getData().data();
200 
201  // Get the object's function list from LoadedObjectMap
202  ObjectMap::iterator OI = LoadedObjectMap.find(ObjData);
203  if (OI == LoadedObjectMap.end())
204  return;
205  MethodAddressVector& Functions = OI->second;
206 
207  // Walk the function list, unregistering each function
208  for (MethodAddressVector::iterator FI = Functions.begin(),
209  FE = Functions.end();
210  FI != FE;
211  ++FI) {
212  void* FnStart = const_cast<void*>(*FI);
213  MethodIDMap::iterator MI = MethodIDs.find(FnStart);
214  if (MI != MethodIDs.end()) {
216  &MI->second);
217  MethodIDs.erase(MI);
218  }
219  }
220 
221  // Erase the object from LoadedObjectMap
222  LoadedObjectMap.erase(OI);
223  DebugObjects.erase(Obj.getData().data());
224 }
225 
226 } // anonymous namespace.
227 
228 namespace llvm {
230  return new IntelJITEventListener(new IntelJITEventsWrapper);
231 }
232 
233 // for testing
235  IntelJITEventsWrapper* TestImpl) {
236  return new IntelJITEventListener(TestImpl);
237 }
238 
239 } // namespace llvm
240 
MachineLoop * L
static JITEventListener * createIntelJITEventListener()
Information about the loaded object.
Definition: RuntimeDyld.h:67
LLVMContext & Context
Expected< StringRef > getName() const
Definition: ObjectFile.h:316
unsigned int LineNumber
Definition: jitprofiling.h:171
unsigned int Offset
Definition: jitprofiling.h:168
size_t i
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:178
Error takeError()
Take ownership of the stored error.
unsigned int class_id
Definition: jitprofiling.h:200
DILineInfo - a format-neutral container for source line information.
Definition: DIContext.h:32
iJDEnvironmentType env
Definition: jitprofiling.h:215
pLineNumberInfo line_number_table
Definition: jitprofiling.h:197
StringRef getData() const
Definition: Binary.cpp:33
Tagged union holding either a T or a Error.
Expected< SymbolRef::Type > getType() const
Definition: ObjectFile.h:340
DWARFContextInMemory is the simplest possible implementation of a DWARFContext.
Definition: DWARFContext.h:255
#define P(N)
void * method_load_address
Definition: jitprofiling.h:188
static const unsigned End
unsigned int user_data_size
Definition: jitprofiling.h:212
void consumeError(Error Err)
Consume a Error without doing anything.
unsigned int method_id
Definition: jitprofiling.h:178
Expected< uint64_t > getAddress() const
Returns the symbol virtual address (i.e.
Definition: ObjectFile.h:320
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)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:843
std::vector< std::pair< SymbolRef, uint64_t > > computeSymbolSizes(const ObjectFile &O)
Definition: SymbolSize.cpp:41
This is a value type class that represents a single symbol in the list of symbols in the object file...
Definition: ObjectFile.h:116
unsigned int method_size
Definition: jitprofiling.h:191
virtual DILineInfoTable getLineInfoForAddressRange(uint64_t Address, uint64_t Size, DILineInfoSpecifier Specifier=DILineInfoSpecifier())=0
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:125
IRTranslator LLVM IR MI