LLVM  3.7.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  if (Sym.getType() != SymbolRef::ST_Function)
117  continue;
118 
120  if (!Name)
121  continue;
122 
123  ErrorOr<uint64_t> AddrOrErr = Sym.getAddress();
124  if (AddrOrErr.getError())
125  continue;
126  uint64_t Addr = *AddrOrErr;
127  uint64_t Size = P.second;
128 
129  // Record this address in a local vector
130  Functions.push_back((void*)Addr);
131 
132  // Build the function loaded notification message
133  iJIT_Method_Load FunctionMessage =
134  FunctionDescToIntelJITFormat(*Wrapper, Name->data(), Addr, Size);
135  DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size);
136  DILineInfoTable::iterator Begin = Lines.begin();
137  DILineInfoTable::iterator End = Lines.end();
138  for (DILineInfoTable::iterator It = Begin; It != End; ++It) {
139  LineInfo.push_back(
140  DILineInfoToIntelJITFormat((uintptr_t)Addr, It->first, It->second));
141  }
142  if (LineInfo.size() == 0) {
143  FunctionMessage.source_file_name = 0;
144  FunctionMessage.line_number_size = 0;
145  FunctionMessage.line_number_table = 0;
146  } else {
147  // Source line information for the address range is provided as
148  // a code offset for the start of the corresponding sub-range and
149  // a source line. JIT API treats offsets in LineNumberInfo structures
150  // as the end of the corresponding code region. The start of the code
151  // is taken from the previous element. Need to shift the elements.
152 
153  LineNumberInfo last = LineInfo.back();
154  last.Offset = FunctionMessage.method_size;
155  LineInfo.push_back(last);
156  for (size_t i = LineInfo.size() - 2; i > 0; --i)
157  LineInfo[i].LineNumber = LineInfo[i - 1].LineNumber;
158 
159  SourceFileName = Lines.front().second.FileName;
160  FunctionMessage.source_file_name =
161  const_cast<char *>(SourceFileName.c_str());
162  FunctionMessage.line_number_size = LineInfo.size();
163  FunctionMessage.line_number_table = &*LineInfo.begin();
164  }
165 
167  &FunctionMessage);
168  MethodIDs[(void*)Addr] = FunctionMessage.method_id;
169  }
170 
171  // To support object unload notification, we need to keep a list of
172  // registered function addresses for each loaded object. We will
173  // use the MethodIDs map to get the registered ID for each function.
174  LoadedObjectMap[ObjData] = Functions;
175  DebugObjects[Obj.getData().data()] = std::move(DebugObjOwner);
176 }
177 
178 void IntelJITEventListener::NotifyFreeingObject(const ObjectFile &Obj) {
179  // This object may not have been registered with the listener. If it wasn't,
180  // bail out.
181  if (DebugObjects.find(Obj.getData().data()) == DebugObjects.end())
182  return;
183 
184  // Get the address of the object image for use as a unique identifier
185  const ObjectFile &DebugObj = *DebugObjects[Obj.getData().data()].getBinary();
186  const void* ObjData = DebugObj.getData().data();
187 
188  // Get the object's function list from LoadedObjectMap
189  ObjectMap::iterator OI = LoadedObjectMap.find(ObjData);
190  if (OI == LoadedObjectMap.end())
191  return;
192  MethodAddressVector& Functions = OI->second;
193 
194  // Walk the function list, unregistering each function
195  for (MethodAddressVector::iterator FI = Functions.begin(),
196  FE = Functions.end();
197  FI != FE;
198  ++FI) {
199  void* FnStart = const_cast<void*>(*FI);
200  MethodIDMap::iterator MI = MethodIDs.find(FnStart);
201  if (MI != MethodIDs.end()) {
203  &MI->second);
204  MethodIDs.erase(MI);
205  }
206  }
207 
208  // Erase the object from LoadedObjectMap
209  LoadedObjectMap.erase(OI);
210  DebugObjects.erase(Obj.getData().data());
211 }
212 
213 } // anonymous namespace.
214 
215 namespace llvm {
217  return new IntelJITEventListener(new IntelJITEventsWrapper);
218 }
219 
220 // for testing
222  IntelJITEventsWrapper* TestImpl) {
223  return new IntelJITEventListener(TestImpl);
224 }
225 
226 } // namespace llvm
227 
static JITEventListener * createIntelJITEventListener()
Information about the loaded object.
Definition: RuntimeDyld.h:59
std::error_code getError() const
Definition: ErrorOr.h:178
Represents either an error or a value T.
Definition: ErrorOr.h:82
unsigned int LineNumber
Definition: jitprofiling.h:171
unsigned int Offset
Definition: jitprofiling.h:168
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:176
unsigned int class_id
Definition: jitprofiling.h:200
DILineInfo - a format-neutral container for source line information.
Definition: DIContext.h:31
iJDEnvironmentType env
Definition: jitprofiling.h:215
pLineNumberInfo line_number_table
Definition: jitprofiling.h:197
StringRef getData() const
Definition: Binary.cpp:33
SymbolRef::Type getType() const
Definition: ObjectFile.h:330
const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
Definition: StringRef.h:107
DWARFContextInMemory is the simplest possible implementation of a DWARFContext.
Definition: DWARFContext.h:222
#define P(N)
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
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:34
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:861
std::vector< std::pair< SymbolRef, uint64_t > > computeSymbolSizes(const ObjectFile &O)
Definition: SymbolSize.cpp:47
This is a value type class that represents a single symbol in the list of symbols in the object file...
Definition: ObjectFile.h:114
unsigned int method_size
Definition: jitprofiling.h:191
virtual DILineInfoTable getLineInfoForAddressRange(uint64_t Address, uint64_t Size, DILineInfoSpecifier Specifier=DILineInfoSpecifier())=0
ErrorOr< StringRef > getName() const
Definition: ObjectFile.h:306
ErrorOr< uint64_t > getAddress() const
Returns the symbol virtual address (i.e.
Definition: ObjectFile.h:310