LLVM API Documentation

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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"
17 
18 #define DEBUG_TYPE "amplifier-jit-event-listener"
19 #include "llvm/DebugInfo.h"
20 #include "llvm/IR/Function.h"
21 #include "llvm/IR/Metadata.h"
22 #include "llvm/ADT/DenseMap.h"
23 #include "llvm/ADT/OwningPtr.h"
27 #include "llvm/Object/ObjectFile.h"
28 #include "llvm/Support/Debug.h"
30 #include "llvm/Support/Errno.h"
32 #include "EventListenerCommon.h"
33 #include "IntelJITEventsWrapper.h"
34 
35 using namespace llvm;
36 using namespace llvm::jitprofiling;
37 
38 namespace {
39 
40 class IntelJITEventListener : public JITEventListener {
41  typedef DenseMap<void*, unsigned int> MethodIDMap;
42 
44  MethodIDMap MethodIDs;
45  FilenameCache Filenames;
46 
47  typedef SmallVector<const void *, 64> MethodAddressVector;
49 
50  ObjectMap LoadedObjectMap;
51 
52 public:
53  IntelJITEventListener(IntelJITEventsWrapper* libraryWrapper) {
54  Wrapper.reset(libraryWrapper);
55  }
56 
57  ~IntelJITEventListener() {
58  }
59 
60  virtual void NotifyFunctionEmitted(const Function &F,
61  void *FnStart, size_t FnSize,
62  const EmittedFunctionDetails &Details);
63 
64  virtual void NotifyFreeingMachineCode(void *OldPtr);
65 
66  virtual void NotifyObjectEmitted(const ObjectImage &Obj);
67 
68  virtual void NotifyFreeingObject(const ObjectImage &Obj);
69 };
70 
71 static LineNumberInfo LineStartToIntelJITFormat(
72  uintptr_t StartAddress,
73  uintptr_t Address,
74  DebugLoc Loc) {
75  LineNumberInfo Result;
76 
77  Result.Offset = Address - StartAddress;
78  Result.LineNumber = Loc.getLine();
79 
80  return Result;
81 }
82 
83 static LineNumberInfo DILineInfoToIntelJITFormat(uintptr_t StartAddress,
84  uintptr_t Address,
85  DILineInfo Line) {
86  LineNumberInfo Result;
87 
88  Result.Offset = Address - StartAddress;
89  Result.LineNumber = Line.getLine();
90 
91  return Result;
92 }
93 
94 static iJIT_Method_Load FunctionDescToIntelJITFormat(
96  const char* FnName,
97  uintptr_t FnStart,
98  size_t FnSize) {
99  iJIT_Method_Load Result;
100  memset(&Result, 0, sizeof(iJIT_Method_Load));
101 
102  Result.method_id = Wrapper.iJIT_GetNewMethodID();
103  Result.method_name = const_cast<char*>(FnName);
104  Result.method_load_address = reinterpret_cast<void*>(FnStart);
105  Result.method_size = FnSize;
106 
107  Result.class_id = 0;
108  Result.class_file_name = NULL;
109  Result.user_data = NULL;
110  Result.user_data_size = 0;
111  Result.env = iJDE_JittingAPI;
112 
113  return Result;
114 }
115 
116 // Adds the just-emitted function to the symbol table.
117 void IntelJITEventListener::NotifyFunctionEmitted(
118  const Function &F, void *FnStart, size_t FnSize,
119  const EmittedFunctionDetails &Details) {
120  iJIT_Method_Load FunctionMessage = FunctionDescToIntelJITFormat(*Wrapper,
121  F.getName().data(),
122  reinterpret_cast<uint64_t>(FnStart),
123  FnSize);
124 
125  std::vector<LineNumberInfo> LineInfo;
126 
127  if (!Details.LineStarts.empty()) {
128  // Now convert the line number information from the address/DebugLoc
129  // format in Details to the offset/lineno in Intel JIT API format.
130 
131  LineInfo.reserve(Details.LineStarts.size() + 1);
132 
133  DebugLoc FirstLoc = Details.LineStarts[0].Loc;
134  assert(!FirstLoc.isUnknown()
135  && "LineStarts should not contain unknown DebugLocs");
136 
137  MDNode *FirstLocScope = FirstLoc.getScope(F.getContext());
138  DISubprogram FunctionDI = getDISubprogram(FirstLocScope);
139  if (FunctionDI.Verify()) {
140  FunctionMessage.source_file_name = const_cast<char*>(
141  Filenames.getFullPath(FirstLocScope));
142 
143  LineNumberInfo FirstLine;
144  FirstLine.Offset = 0;
145  FirstLine.LineNumber = FunctionDI.getLineNumber();
146  LineInfo.push_back(FirstLine);
147  }
148 
149  for (std::vector<EmittedFunctionDetails::LineStart>::const_iterator I =
150  Details.LineStarts.begin(), E = Details.LineStarts.end();
151  I != E; ++I) {
152  // This implementation ignores the DebugLoc filename because the Intel
153  // JIT API does not support multiple source files associated with a single
154  // JIT function
155  LineInfo.push_back(LineStartToIntelJITFormat(
156  reinterpret_cast<uintptr_t>(FnStart),
157  I->Address,
158  I->Loc));
159 
160  // If we have no file name yet for the function, use the filename from
161  // the first instruction that has one
162  if (FunctionMessage.source_file_name == 0) {
163  MDNode *scope = I->Loc.getScope(
164  Details.MF->getFunction()->getContext());
165  FunctionMessage.source_file_name = const_cast<char*>(
166  Filenames.getFullPath(scope));
167  }
168  }
169 
170  FunctionMessage.line_number_size = LineInfo.size();
171  FunctionMessage.line_number_table = &*LineInfo.begin();
172  } else {
173  FunctionMessage.line_number_size = 0;
174  FunctionMessage.line_number_table = 0;
175  }
176 
178  &FunctionMessage);
179  MethodIDs[FnStart] = FunctionMessage.method_id;
180 }
181 
182 void IntelJITEventListener::NotifyFreeingMachineCode(void *FnStart) {
183  MethodIDMap::iterator I = MethodIDs.find(FnStart);
184  if (I != MethodIDs.end()) {
186  MethodIDs.erase(I);
187  }
188 }
189 
190 void IntelJITEventListener::NotifyObjectEmitted(const ObjectImage &Obj) {
191  // Get the address of the object image for use as a unique identifier
192  const void* ObjData = Obj.getData().data();
194  MethodAddressVector Functions;
195 
196  // Use symbol info to iterate functions in the object.
197  error_code ec;
199  E = Obj.end_symbols();
200  I != E && !ec;
201  I.increment(ec)) {
202  std::vector<LineNumberInfo> LineInfo;
203  std::string SourceFileName;
204 
205  object::SymbolRef::Type SymType;
206  if (I->getType(SymType)) continue;
207  if (SymType == object::SymbolRef::ST_Function) {
208  StringRef Name;
209  uint64_t Addr;
210  uint64_t Size;
211  if (I->getName(Name)) continue;
212  if (I->getAddress(Addr)) continue;
213  if (I->getSize(Size)) continue;
214 
215  // Record this address in a local vector
216  Functions.push_back((void*)Addr);
217 
218  // Build the function loaded notification message
219  iJIT_Method_Load FunctionMessage = FunctionDescToIntelJITFormat(*Wrapper,
220  Name.data(),
221  Addr,
222  Size);
223  if (Context) {
224  DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size);
225  DILineInfoTable::iterator Begin = Lines.begin();
226  DILineInfoTable::iterator End = Lines.end();
227  for (DILineInfoTable::iterator It = Begin; It != End; ++It) {
228  LineInfo.push_back(DILineInfoToIntelJITFormat((uintptr_t)Addr,
229  It->first,
230  It->second));
231  }
232  if (LineInfo.size() == 0) {
233  FunctionMessage.source_file_name = 0;
234  FunctionMessage.line_number_size = 0;
235  FunctionMessage.line_number_table = 0;
236  } else {
237  SourceFileName = Lines.front().second.getFileName();
238  FunctionMessage.source_file_name = (char *)SourceFileName.c_str();
239  FunctionMessage.line_number_size = LineInfo.size();
240  FunctionMessage.line_number_table = &*LineInfo.begin();
241  }
242  } else {
243  FunctionMessage.source_file_name = 0;
244  FunctionMessage.line_number_size = 0;
245  FunctionMessage.line_number_table = 0;
246  }
247 
249  &FunctionMessage);
250  MethodIDs[(void*)Addr] = FunctionMessage.method_id;
251  }
252  }
253 
254  // To support object unload notification, we need to keep a list of
255  // registered function addresses for each loaded object. We will
256  // use the MethodIDs map to get the registered ID for each function.
257  LoadedObjectMap[ObjData] = Functions;
258 }
259 
260 void IntelJITEventListener::NotifyFreeingObject(const ObjectImage &Obj) {
261  // Get the address of the object image for use as a unique identifier
262  const void* ObjData = Obj.getData().data();
263 
264  // Get the object's function list from LoadedObjectMap
265  ObjectMap::iterator OI = LoadedObjectMap.find(ObjData);
266  if (OI == LoadedObjectMap.end())
267  return;
268  MethodAddressVector& Functions = OI->second;
269 
270  // Walk the function list, unregistering each function
271  for (MethodAddressVector::iterator FI = Functions.begin(),
272  FE = Functions.end();
273  FI != FE;
274  ++FI) {
275  void* FnStart = const_cast<void*>(*FI);
276  MethodIDMap::iterator MI = MethodIDs.find(FnStart);
277  if (MI != MethodIDs.end()) {
279  &MI->second);
280  MethodIDs.erase(MI);
281  }
282  }
283 
284  // Erase the object from LoadedObjectMap
285  LoadedObjectMap.erase(OI);
286 }
287 
288 } // anonymous namespace.
289 
290 namespace llvm {
292  return new IntelJITEventListener(new IntelJITEventsWrapper);
293 }
294 
295 // for testing
297  IntelJITEventsWrapper* TestImpl) {
298  return new IntelJITEventListener(TestImpl);
299 }
300 
301 } // namespace llvm
302 
static JITEventListener * createIntelJITEventListener()
LLVMContext & getContext() const
Definition: Function.cpp:167
unsigned int LineNumber
Definition: jitprofiling.h:171
unsigned int Offset
Definition: jitprofiling.h:168
MDNode - a tuple of other values.
Definition: Metadata.h:69
F(f)
unsigned int class_id
Definition: jitprofiling.h:200
StringRef getName() const
Definition: Value.cpp:167
bool isUnknown() const
isUnknown - Return true if this is an unknown location.
Definition: DebugLoc.h:70
iJDEnvironmentType env
Definition: jitprofiling.h:215
static DIContext * getDWARFContext(object::ObjectFile *)
getDWARFContext - get a context for binary DWARF data.
Definition: DIContext.cpp:16
pLineNumberInfo line_number_table
Definition: jitprofiling.h:197
unsigned getLine() const
Definition: DebugLoc.h:72
DISubprogram - This is a wrapper for a subprogram (e.g. a function).
Definition: DebugInfo.h:429
const char * data() const
Definition: StringRef.h:107
virtual object::symbol_iterator end_symbols() const =0
virtual object::symbol_iterator begin_symbols() const =0
unsigned getLineNumber() const
Definition: DebugInfo.h:440
virtual StringRef getData() const =0
DISubprogram getDISubprogram(const MDNode *Scope)
getDISubprogram - Find subprogram that is enclosing this scope.
Definition: DebugInfo.cpp:885
void * method_load_address
Definition: jitprofiling.h:188
unsigned int user_data_size
Definition: jitprofiling.h:212
unsigned int method_id
Definition: jitprofiling.h:178
DILineInfo - a format-neutral container for source line information.
Definition: DIContext.h:32
unsigned int line_number_size
Definition: jitprofiling.h:194
MDNode * getScope(const LLVMContext &Ctx) const
Definition: DebugLoc.cpp:20
int iJIT_NotifyEvent(iJIT_JVM_EVENT EventType, void *EventSpecificData)
unsigned int iJIT_GetNewMethodID(void)
uint32_t getLine() const
Definition: DIContext.h:48
virtual object::ObjectFile * getObjectFile() const =0
unsigned int method_size
Definition: jitprofiling.h:191
virtual DILineInfoTable getLineInfoForAddressRange(uint64_t Address, uint64_t Size, DILineInfoSpecifier Specifier=DILineInfoSpecifier())=0
#define I(x, y, z)
Definition: MD5.cpp:54
bool Verify() const
Verify - Verify that a subprogram descriptor is well formed.
Definition: DebugInfo.cpp:512