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 "EventListenerCommon.h"
17 #include "IntelJITEventsWrapper.h"
18 #include "llvm/ADT/DenseMap.h"
19 #include "llvm/CodeGen/MachineFunction.h"
20 #include "llvm/DebugInfo/DIContext.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/Support/Debug.h"
28 #include "llvm/Support/Errno.h"
29 #include "llvm/Support/raw_ostream.h"
32 using namespace llvm::jitprofiling
;
33 using namespace llvm::object
;
35 #define DEBUG_TYPE "amplifier-jit-event-listener"
39 class IntelJITEventListener
: public JITEventListener
{
40 typedef DenseMap
<void*, unsigned int> MethodIDMap
;
42 std::unique_ptr
<IntelJITEventsWrapper
> Wrapper
;
43 MethodIDMap MethodIDs
;
44 FilenameCache Filenames
;
46 typedef SmallVector
<const void *, 64> MethodAddressVector
;
47 typedef DenseMap
<const void *, MethodAddressVector
> ObjectMap
;
49 ObjectMap LoadedObjectMap
;
50 std::map
<const char*, OwningBinary
<ObjectFile
>> DebugObjects
;
53 IntelJITEventListener(IntelJITEventsWrapper
* libraryWrapper
) {
54 Wrapper
.reset(libraryWrapper
);
57 ~IntelJITEventListener() {
60 void NotifyObjectEmitted(const ObjectFile
&Obj
,
61 const RuntimeDyld::LoadedObjectInfo
&L
) override
;
63 void NotifyFreeingObject(const ObjectFile
&Obj
) override
;
66 static LineNumberInfo
DILineInfoToIntelJITFormat(uintptr_t StartAddress
,
69 LineNumberInfo Result
;
71 Result
.Offset
= Address
- StartAddress
;
72 Result
.LineNumber
= Line
.Line
;
77 static iJIT_Method_Load
FunctionDescToIntelJITFormat(
78 IntelJITEventsWrapper
& Wrapper
,
82 iJIT_Method_Load Result
;
83 memset(&Result
, 0, sizeof(iJIT_Method_Load
));
85 Result
.method_id
= Wrapper
.iJIT_GetNewMethodID();
86 Result
.method_name
= const_cast<char*>(FnName
);
87 Result
.method_load_address
= reinterpret_cast<void*>(FnStart
);
88 Result
.method_size
= FnSize
;
91 Result
.class_file_name
= NULL
;
92 Result
.user_data
= NULL
;
93 Result
.user_data_size
= 0;
94 Result
.env
= iJDE_JittingAPI
;
99 void IntelJITEventListener::NotifyObjectEmitted(
100 const ObjectFile
&Obj
,
101 const RuntimeDyld::LoadedObjectInfo
&L
) {
103 OwningBinary
<ObjectFile
> DebugObjOwner
= L
.getObjectForDebug(Obj
);
104 const ObjectFile
&DebugObj
= *DebugObjOwner
.getBinary();
106 // Get the address of the object image for use as a unique identifier
107 const void* ObjData
= DebugObj
.getData().data();
108 DIContext
* Context
= DIContext::getDWARFContext(DebugObj
);
109 MethodAddressVector Functions
;
111 // Use symbol info to iterate functions in the object.
112 for (symbol_iterator I
= DebugObj
.symbol_begin(),
113 E
= DebugObj
.symbol_end();
116 std::vector
<LineNumberInfo
> LineInfo
;
117 std::string SourceFileName
;
119 SymbolRef::Type SymType
;
120 if (I
->getType(SymType
)) continue;
121 if (SymType
== SymbolRef::ST_Function
) {
125 if (I
->getName(Name
)) continue;
126 if (I
->getAddress(Addr
)) continue;
127 if (I
->getSize(Size
)) continue;
129 // Record this address in a local vector
130 Functions
.push_back((void*)Addr
);
132 // Build the function loaded notification message
133 iJIT_Method_Load FunctionMessage
= FunctionDescToIntelJITFormat(*Wrapper
,
138 DILineInfoTable Lines
= Context
->getLineInfoForAddressRange(Addr
, Size
);
139 DILineInfoTable::iterator Begin
= Lines
.begin();
140 DILineInfoTable::iterator End
= Lines
.end();
141 for (DILineInfoTable::iterator It
= Begin
; It
!= End
; ++It
) {
142 LineInfo
.push_back(DILineInfoToIntelJITFormat((uintptr_t)Addr
,
146 if (LineInfo
.size() == 0) {
147 FunctionMessage
.source_file_name
= 0;
148 FunctionMessage
.line_number_size
= 0;
149 FunctionMessage
.line_number_table
= 0;
151 // Source line information for the address range is provided as
152 // a code offset for the start of the corresponding sub-range and
153 // a source line. JIT API treats offsets in LineNumberInfo structures
154 // as the end of the corresponding code region. The start of the code
155 // is taken from the previous element. Need to shift the elements.
157 LineNumberInfo last
= LineInfo
.back();
158 last
.Offset
= FunctionMessage
.method_size
;
159 LineInfo
.push_back(last
);
160 for (size_t i
= LineInfo
.size() - 2; i
> 0; --i
)
161 LineInfo
[i
].LineNumber
= LineInfo
[i
- 1].LineNumber
;
163 SourceFileName
= Lines
.front().second
.FileName
;
164 FunctionMessage
.source_file_name
= const_cast<char *>(SourceFileName
.c_str());
165 FunctionMessage
.line_number_size
= LineInfo
.size();
166 FunctionMessage
.line_number_table
= &*LineInfo
.begin();
169 FunctionMessage
.source_file_name
= 0;
170 FunctionMessage
.line_number_size
= 0;
171 FunctionMessage
.line_number_table
= 0;
174 Wrapper
->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED
,
176 MethodIDs
[(void*)Addr
] = FunctionMessage
.method_id
;
180 // To support object unload notification, we need to keep a list of
181 // registered function addresses for each loaded object. We will
182 // use the MethodIDs map to get the registered ID for each function.
183 LoadedObjectMap
[ObjData
] = Functions
;
184 DebugObjects
[Obj
.getData().data()] = std::move(DebugObjOwner
);
187 void IntelJITEventListener::NotifyFreeingObject(const ObjectFile
&Obj
) {
188 // This object may not have been registered with the listener. If it wasn't,
190 if (DebugObjects
.find(Obj
.getData().data()) == DebugObjects
.end())
193 // Get the address of the object image for use as a unique identifier
194 const ObjectFile
&DebugObj
= *DebugObjects
[Obj
.getData().data()].getBinary();
195 const void* ObjData
= DebugObj
.getData().data();
197 // Get the object's function list from LoadedObjectMap
198 ObjectMap::iterator OI
= LoadedObjectMap
.find(ObjData
);
199 if (OI
== LoadedObjectMap
.end())
201 MethodAddressVector
& Functions
= OI
->second
;
203 // Walk the function list, unregistering each function
204 for (MethodAddressVector::iterator FI
= Functions
.begin(),
205 FE
= Functions
.end();
208 void* FnStart
= const_cast<void*>(*FI
);
209 MethodIDMap::iterator MI
= MethodIDs
.find(FnStart
);
210 if (MI
!= MethodIDs
.end()) {
211 Wrapper
->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START
,
217 // Erase the object from LoadedObjectMap
218 LoadedObjectMap
.erase(OI
);
219 DebugObjects
.erase(Obj
.getData().data());
222 } // anonymous namespace.
225 JITEventListener
*JITEventListener::createIntelJITEventListener() {
226 return new IntelJITEventListener(new IntelJITEventsWrapper
);
230 JITEventListener
*JITEventListener::createIntelJITEventListener(
231 IntelJITEventsWrapper
* TestImpl
) {
232 return new IntelJITEventListener(TestImpl
);