IntelJITEventListener.cpp revision 0b8c9a80f20772c3793201ab5b251d3520b9cea3
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 "llvm/ExecutionEngine/JITEventListener.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"
24#include "llvm/CodeGen/MachineFunction.h"
25#include "llvm/ExecutionEngine/ObjectImage.h"
26#include "llvm/Support/Debug.h"
27#include "llvm/Support/raw_ostream.h"
28#include "llvm/Support/Errno.h"
29#include "llvm/Support/ValueHandle.h"
30#include "EventListenerCommon.h"
31#include "IntelJITEventsWrapper.h"
32
33using namespace llvm;
34using namespace llvm::jitprofiling;
35
36namespace {
37
38class IntelJITEventListener : public JITEventListener {
39  typedef DenseMap<void*, unsigned int> MethodIDMap;
40
41  OwningPtr<IntelJITEventsWrapper> Wrapper;
42  MethodIDMap MethodIDs;
43  FilenameCache Filenames;
44
45  typedef SmallVector<const void *, 64> MethodAddressVector;
46  typedef DenseMap<const void *, MethodAddressVector>  ObjectMap;
47
48  ObjectMap  LoadedObjectMap;
49
50public:
51  IntelJITEventListener(IntelJITEventsWrapper* libraryWrapper) {
52      Wrapper.reset(libraryWrapper);
53  }
54
55  ~IntelJITEventListener() {
56  }
57
58  virtual void NotifyFunctionEmitted(const Function &F,
59                                     void *FnStart, size_t FnSize,
60                                     const EmittedFunctionDetails &Details);
61
62  virtual void NotifyFreeingMachineCode(void *OldPtr);
63
64  virtual void NotifyObjectEmitted(const ObjectImage &Obj);
65
66  virtual void NotifyFreeingObject(const ObjectImage &Obj);
67};
68
69static LineNumberInfo LineStartToIntelJITFormat(
70    uintptr_t StartAddress,
71    uintptr_t Address,
72    DebugLoc Loc) {
73  LineNumberInfo Result;
74
75  Result.Offset = Address - StartAddress;
76  Result.LineNumber = Loc.getLine();
77
78  return Result;
79}
80
81static iJIT_Method_Load FunctionDescToIntelJITFormat(
82    IntelJITEventsWrapper& Wrapper,
83    const char* FnName,
84    uintptr_t FnStart,
85    size_t FnSize) {
86  iJIT_Method_Load Result;
87  memset(&Result, 0, sizeof(iJIT_Method_Load));
88
89  Result.method_id = Wrapper.iJIT_GetNewMethodID();
90  Result.method_name = const_cast<char*>(FnName);
91  Result.method_load_address = reinterpret_cast<void*>(FnStart);
92  Result.method_size = FnSize;
93
94  Result.class_id = 0;
95  Result.class_file_name = NULL;
96  Result.user_data = NULL;
97  Result.user_data_size = 0;
98  Result.env = iJDE_JittingAPI;
99
100  return Result;
101}
102
103// Adds the just-emitted function to the symbol table.
104void IntelJITEventListener::NotifyFunctionEmitted(
105    const Function &F, void *FnStart, size_t FnSize,
106    const EmittedFunctionDetails &Details) {
107  iJIT_Method_Load FunctionMessage = FunctionDescToIntelJITFormat(*Wrapper,
108                                      F.getName().data(),
109                                      reinterpret_cast<uint64_t>(FnStart),
110                                      FnSize);
111
112  std::vector<LineNumberInfo> LineInfo;
113
114  if (!Details.LineStarts.empty()) {
115    // Now convert the line number information from the address/DebugLoc
116    // format in Details to the offset/lineno in Intel JIT API format.
117
118    LineInfo.reserve(Details.LineStarts.size() + 1);
119
120    DebugLoc FirstLoc = Details.LineStarts[0].Loc;
121    assert(!FirstLoc.isUnknown()
122           && "LineStarts should not contain unknown DebugLocs");
123
124    MDNode *FirstLocScope = FirstLoc.getScope(F.getContext());
125    DISubprogram FunctionDI = getDISubprogram(FirstLocScope);
126    if (FunctionDI.Verify()) {
127      FunctionMessage.source_file_name = const_cast<char*>(
128                                          Filenames.getFullPath(FirstLocScope));
129
130      LineNumberInfo FirstLine;
131      FirstLine.Offset = 0;
132      FirstLine.LineNumber = FunctionDI.getLineNumber();
133      LineInfo.push_back(FirstLine);
134    }
135
136    for (std::vector<EmittedFunctionDetails::LineStart>::const_iterator I =
137          Details.LineStarts.begin(), E = Details.LineStarts.end();
138          I != E; ++I) {
139      // This implementation ignores the DebugLoc filename because the Intel
140      // JIT API does not support multiple source files associated with a single
141      // JIT function
142      LineInfo.push_back(LineStartToIntelJITFormat(
143                          reinterpret_cast<uintptr_t>(FnStart),
144                          I->Address,
145                          I->Loc));
146
147      // If we have no file name yet for the function, use the filename from
148      // the first instruction that has one
149      if (FunctionMessage.source_file_name == 0) {
150        MDNode *scope = I->Loc.getScope(
151          Details.MF->getFunction()->getContext());
152        FunctionMessage.source_file_name = const_cast<char*>(
153                                                  Filenames.getFullPath(scope));
154      }
155    }
156
157    FunctionMessage.line_number_size = LineInfo.size();
158    FunctionMessage.line_number_table = &*LineInfo.begin();
159  } else {
160    FunctionMessage.line_number_size = 0;
161    FunctionMessage.line_number_table = 0;
162  }
163
164  Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED,
165                            &FunctionMessage);
166  MethodIDs[FnStart] = FunctionMessage.method_id;
167}
168
169void IntelJITEventListener::NotifyFreeingMachineCode(void *FnStart) {
170  MethodIDMap::iterator I = MethodIDs.find(FnStart);
171  if (I != MethodIDs.end()) {
172    Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START, &I->second);
173    MethodIDs.erase(I);
174  }
175}
176
177void IntelJITEventListener::NotifyObjectEmitted(const ObjectImage &Obj) {
178  // Get the address of the object image for use as a unique identifier
179  const void* ObjData = Obj.getData().data();
180  MethodAddressVector Functions;
181
182  // Use symbol info to iterate functions in the object.
183  error_code ec;
184  for (object::symbol_iterator I = Obj.begin_symbols(),
185                               E = Obj.end_symbols();
186                        I != E && !ec;
187                        I.increment(ec)) {
188    object::SymbolRef::Type SymType;
189    if (I->getType(SymType)) continue;
190    if (SymType == object::SymbolRef::ST_Function) {
191      StringRef Name;
192      uint64_t  Addr;
193      uint64_t  Size;
194      if (I->getName(Name)) continue;
195      if (I->getAddress(Addr)) continue;
196      if (I->getSize(Size)) continue;
197
198      // Record this address in a local vector
199      Functions.push_back((void*)Addr);
200
201      // Build the function loaded notification message
202      iJIT_Method_Load FunctionMessage = FunctionDescToIntelJITFormat(*Wrapper,
203                                           Name.data(),
204                                           Addr,
205                                           Size);
206
207      // FIXME: Try to find line info for this function in the DWARF sections.
208      FunctionMessage.source_file_name = 0;
209      FunctionMessage.line_number_size = 0;
210      FunctionMessage.line_number_table = 0;
211
212      Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED,
213                                &FunctionMessage);
214      MethodIDs[(void*)Addr] = FunctionMessage.method_id;
215    }
216  }
217
218  // To support object unload notification, we need to keep a list of
219  // registered function addresses for each loaded object.  We will
220  // use the MethodIDs map to get the registered ID for each function.
221  LoadedObjectMap[ObjData] = Functions;
222}
223
224void IntelJITEventListener::NotifyFreeingObject(const ObjectImage &Obj) {
225  // Get the address of the object image for use as a unique identifier
226  const void* ObjData = Obj.getData().data();
227
228  // Get the object's function list from LoadedObjectMap
229  ObjectMap::iterator OI = LoadedObjectMap.find(ObjData);
230  if (OI == LoadedObjectMap.end())
231    return;
232  MethodAddressVector& Functions = OI->second;
233
234  // Walk the function list, unregistering each function
235  for (MethodAddressVector::iterator FI = Functions.begin(),
236                                     FE = Functions.end();
237       FI != FE;
238       ++FI) {
239    void* FnStart = const_cast<void*>(*FI);
240    MethodIDMap::iterator MI = MethodIDs.find(FnStart);
241    if (MI != MethodIDs.end()) {
242      Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START,
243                                &MI->second);
244      MethodIDs.erase(MI);
245    }
246  }
247
248  // Erase the object from LoadedObjectMap
249  LoadedObjectMap.erase(OI);
250}
251
252}  // anonymous namespace.
253
254namespace llvm {
255JITEventListener *JITEventListener::createIntelJITEventListener() {
256  return new IntelJITEventListener(new IntelJITEventsWrapper);
257}
258
259// for testing
260JITEventListener *JITEventListener::createIntelJITEventListener(
261                                      IntelJITEventsWrapper* TestImpl) {
262  return new IntelJITEventListener(TestImpl);
263}
264
265} // namespace llvm
266
267