Implementing basic function-level profiling support in IntelJITEventListener.
[oota-llvm.git] / lib / ExecutionEngine / IntelJITEvents / IntelJITEventListener.cpp
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/Function.h"
21 #include "llvm/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
33 using namespace llvm;
34 using namespace llvm::jitprofiling;
35
36 namespace {
37
38 class 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
50 public:
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
69 static 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
81 static 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.
104 void 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
169 void 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
177 void 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
224 void 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
254 namespace llvm {
255 JITEventListener *JITEventListener::createIntelJITEventListener() {
256   return new IntelJITEventListener(new IntelJITEventsWrapper);
257 }
258
259 // for testing
260 JITEventListener *JITEventListener::createIntelJITEventListener(
261                                       IntelJITEventsWrapper* TestImpl) {
262   return new IntelJITEventListener(TestImpl);
263 }
264
265 } // namespace llvm
266