IntelJITEventListener.cpp revision 303975
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"
18#include "llvm/CodeGen/MachineFunction.h"
19#include "llvm/DebugInfo/DIContext.h"
20#include "llvm/DebugInfo/DWARF/DWARFContext.h"
21#include "llvm/ExecutionEngine/JITEventListener.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"
30#include "llvm/Support/raw_ostream.h"
31
32using namespace llvm;
33using namespace llvm::object;
34
35#define DEBUG_TYPE "amplifier-jit-event-listener"
36
37namespace {
38
39class 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;
46  typedef DenseMap<const void *, MethodAddressVector>  ObjectMap;
47
48  ObjectMap  LoadedObjectMap;
49  std::map<const char*, OwningBinary<ObjectFile>> DebugObjects;
50
51public:
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
65static 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
76static iJIT_Method_Load FunctionDescToIntelJITFormat(
77    IntelJITEventsWrapper& Wrapper,
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
98void IntelJITEventListener::NotifyObjectEmitted(
99                                       const ObjectFile &Obj,
100                                       const RuntimeDyld::LoadedObjectInfo &L) {
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
119    ErrorOr<StringRef> Name = Sym.getName();
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
166    Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED,
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
178void 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()) {
202      Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START,
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
215namespace llvm {
216JITEventListener *JITEventListener::createIntelJITEventListener() {
217  return new IntelJITEventListener(new IntelJITEventsWrapper);
218}
219
220// for testing
221JITEventListener *JITEventListener::createIntelJITEventListener(
222                                      IntelJITEventsWrapper* TestImpl) {
223  return new IntelJITEventListener(TestImpl);
224}
225
226} // namespace llvm
227
228