1 //===-- IntelJITEventListener.cpp - Tell Intel profiler about JITed code --===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines a JITEventListener object to tell Intel(R) VTune(TM)
11 // Amplifier XE 2011 about JITted functions.
13 //===----------------------------------------------------------------------===//
15 #include "llvm/Config/config.h"
16 #include "llvm/ExecutionEngine/JITEventListener.h"
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"
34 using namespace llvm::jitprofiling;
38 class IntelJITEventListener : public JITEventListener {
39 typedef DenseMap<void*, unsigned int> MethodIDMap;
41 OwningPtr<IntelJITEventsWrapper> Wrapper;
42 MethodIDMap MethodIDs;
43 FilenameCache Filenames;
45 typedef SmallVector<const void *, 64> MethodAddressVector;
46 typedef DenseMap<const void *, MethodAddressVector> ObjectMap;
48 ObjectMap LoadedObjectMap;
51 IntelJITEventListener(IntelJITEventsWrapper* libraryWrapper) {
52 Wrapper.reset(libraryWrapper);
55 ~IntelJITEventListener() {
58 virtual void NotifyFunctionEmitted(const Function &F,
59 void *FnStart, size_t FnSize,
60 const EmittedFunctionDetails &Details);
62 virtual void NotifyFreeingMachineCode(void *OldPtr);
64 virtual void NotifyObjectEmitted(const ObjectImage &Obj);
66 virtual void NotifyFreeingObject(const ObjectImage &Obj);
69 static LineNumberInfo LineStartToIntelJITFormat(
70 uintptr_t StartAddress,
73 LineNumberInfo Result;
75 Result.Offset = Address - StartAddress;
76 Result.LineNumber = Loc.getLine();
81 static iJIT_Method_Load FunctionDescToIntelJITFormat(
82 IntelJITEventsWrapper& Wrapper,
86 iJIT_Method_Load Result;
87 memset(&Result, 0, sizeof(iJIT_Method_Load));
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;
95 Result.class_file_name = NULL;
96 Result.user_data = NULL;
97 Result.user_data_size = 0;
98 Result.env = iJDE_JittingAPI;
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,
109 reinterpret_cast<uint64_t>(FnStart),
112 std::vector<LineNumberInfo> LineInfo;
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.
118 LineInfo.reserve(Details.LineStarts.size() + 1);
120 DebugLoc FirstLoc = Details.LineStarts[0].Loc;
121 assert(!FirstLoc.isUnknown()
122 && "LineStarts should not contain unknown DebugLocs");
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));
130 LineNumberInfo FirstLine;
131 FirstLine.Offset = 0;
132 FirstLine.LineNumber = FunctionDI.getLineNumber();
133 LineInfo.push_back(FirstLine);
136 for (std::vector<EmittedFunctionDetails::LineStart>::const_iterator I =
137 Details.LineStarts.begin(), E = Details.LineStarts.end();
139 // This implementation ignores the DebugLoc filename because the Intel
140 // JIT API does not support multiple source files associated with a single
142 LineInfo.push_back(LineStartToIntelJITFormat(
143 reinterpret_cast<uintptr_t>(FnStart),
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));
157 FunctionMessage.line_number_size = LineInfo.size();
158 FunctionMessage.line_number_table = &*LineInfo.begin();
160 FunctionMessage.line_number_size = 0;
161 FunctionMessage.line_number_table = 0;
164 Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED,
166 MethodIDs[FnStart] = FunctionMessage.method_id;
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);
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;
182 // Use symbol info to iterate functions in the object.
184 for (object::symbol_iterator I = Obj.begin_symbols(),
185 E = Obj.end_symbols();
188 object::SymbolRef::Type SymType;
189 if (I->getType(SymType)) continue;
190 if (SymType == object::SymbolRef::ST_Function) {
194 if (I->getName(Name)) continue;
195 if (I->getAddress(Addr)) continue;
196 if (I->getSize(Size)) continue;
198 // Record this address in a local vector
199 Functions.push_back((void*)Addr);
201 // Build the function loaded notification message
202 iJIT_Method_Load FunctionMessage = FunctionDescToIntelJITFormat(*Wrapper,
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;
212 Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED,
214 MethodIDs[(void*)Addr] = FunctionMessage.method_id;
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;
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();
228 // Get the object's function list from LoadedObjectMap
229 ObjectMap::iterator OI = LoadedObjectMap.find(ObjData);
230 if (OI == LoadedObjectMap.end())
232 MethodAddressVector& Functions = OI->second;
234 // Walk the function list, unregistering each function
235 for (MethodAddressVector::iterator FI = Functions.begin(),
236 FE = Functions.end();
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,
248 // Erase the object from LoadedObjectMap
249 LoadedObjectMap.erase(OI);
252 } // anonymous namespace.
255 JITEventListener *JITEventListener::createIntelJITEventListener() {
256 return new IntelJITEventListener(new IntelJITEventsWrapper);
260 JITEventListener *JITEventListener::createIntelJITEventListener(
261 IntelJITEventsWrapper* TestImpl) {
262 return new IntelJITEventListener(TestImpl);