1 //===-- IntelJITEventListener.cpp - Tell Intel profiler about JITed code --===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file defines a JITEventListener object to tell Intel(R) VTune(TM)
10 // Amplifier XE 2011 about JITted functions.
12 //===----------------------------------------------------------------------===//
14 #include "IntelJITProfiling/IntelJITEventsWrapper.h"
15 #include "ittnotify.h"
16 #include "llvm-c/ExecutionEngine.h"
17 #include "llvm/ADT/DenseMap.h"
18 #include "llvm/CodeGen/MachineFunction.h"
19 #include "llvm/Config/config.h"
20 #include "llvm/DebugInfo/DIContext.h"
21 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
22 #include "llvm/ExecutionEngine/JITEventListener.h"
23 #include "llvm/IR/DebugInfo.h"
24 #include "llvm/IR/Function.h"
25 #include "llvm/IR/Metadata.h"
26 #include "llvm/IR/ValueHandle.h"
27 #include "llvm/Object/ELFObjectFile.h"
28 #include "llvm/Object/ObjectFile.h"
29 #include "llvm/Object/SymbolSize.h"
30 #include "llvm/Support/Debug.h"
31 #include "llvm/Support/Errno.h"
32 #include "llvm/Support/raw_ostream.h"
35 using namespace llvm::object
;
37 #define DEBUG_TYPE "amplifier-jit-event-listener"
41 class IntelIttnotifyInfo
{
42 std::string ModuleName
;
43 std::vector
<std::string
> SectionNamesVector
;
44 std::vector
<__itt_section_info
> SectionInfoVector
;
45 __itt_module_object
*ModuleObject
;
46 IntelJITEventsWrapper
&WrapperRef
;
49 IntelIttnotifyInfo(IntelJITEventsWrapper
&Wrapper
)
50 : ModuleObject(NULL
), WrapperRef(Wrapper
){};
51 ~IntelIttnotifyInfo() { delete ModuleObject
; };
53 void setModuleName(const char *Name
) { ModuleName
= std::string(Name
); }
55 const char *getModuleName() { return ModuleName
.c_str(); }
57 void setModuleObject(__itt_module_object
*ModuleObj
) {
58 ModuleObject
= ModuleObj
;
61 __itt_module_object
*getModuleObject() { return ModuleObject
; }
63 __itt_section_info
*getSectionInfoVectorBegin() {
64 if (SectionInfoVector
.size())
65 return &SectionInfoVector
[0];
69 void reportSection(llvm::IttEventType EventType
, const char *SectionName
,
70 unsigned int SectionSize
) {
71 WrapperRef
.iJitIttNotifyInfo(EventType
, SectionName
, SectionSize
);
74 int fillSectionInformation(const ObjectFile
&Obj
,
75 const RuntimeDyld::LoadedObjectInfo
&L
) {
77 int SectionCounter
= 0;
79 for (auto &Section
: Obj
.sections()) {
80 uint64_t SectionLoadAddr
= L
.getSectionLoadAddress(Section
);
81 if (SectionLoadAddr
) {
82 object::ELFSectionRef
ElfSection(Section
);
84 __itt_section_info SectionInfo
;
85 memset(&SectionInfo
, 0, sizeof(SectionInfo
));
86 SectionInfo
.start_addr
= reinterpret_cast<void *>(SectionLoadAddr
);
87 SectionInfo
.file_offset
= ElfSection
.getOffset();
88 SectionInfo
.flags
= ElfSection
.getFlags();
90 StringRef
SectionName("");
91 auto SectionNameOrError
= ElfSection
.getName();
92 if (SectionNameOrError
)
93 SectionName
= *SectionNameOrError
;
95 SectionNamesVector
.push_back(SectionName
.str());
96 SectionInfo
.size
= ElfSection
.getSize();
97 reportSection(llvm::LoadBinarySection
, SectionName
.str().c_str(),
100 if (ElfSection
.isBSS()) {
101 SectionInfo
.type
= itt_section_type_bss
;
102 } else if (ElfSection
.isData()) {
103 SectionInfo
.type
= itt_section_type_data
;
104 } else if (ElfSection
.isText()) {
105 SectionInfo
.type
= itt_section_type_text
;
107 SectionInfoVector
.push_back(SectionInfo
);
111 // Hereinafter: don't change SectionNamesVector content to avoid vector
112 // reallocation - reallocation invalidates all the references, pointers, and
113 // iterators referring to the elements in the sequence.
114 for (int I
= 0; I
< SectionCounter
; ++I
) {
115 SectionInfoVector
[I
].name
= SectionNamesVector
[I
].c_str();
117 return SectionCounter
;
121 class IntelJITEventListener
: public JITEventListener
{
122 typedef DenseMap
<void*, unsigned int> MethodIDMap
;
124 std::unique_ptr
<IntelJITEventsWrapper
> Wrapper
;
125 MethodIDMap MethodIDs
;
127 typedef SmallVector
<const void *, 64> MethodAddressVector
;
128 typedef DenseMap
<const void *, MethodAddressVector
> ObjectMap
;
130 ObjectMap LoadedObjectMap
;
131 std::map
<ObjectKey
, OwningBinary
<ObjectFile
>> DebugObjects
;
133 std::map
<ObjectKey
, std::unique_ptr
<IntelIttnotifyInfo
>> KeyToIttnotify
;
136 IntelJITEventListener(IntelJITEventsWrapper
* libraryWrapper
) {
137 Wrapper
.reset(libraryWrapper
);
140 ~IntelJITEventListener() {
143 void notifyObjectLoaded(ObjectKey Key
, const ObjectFile
&Obj
,
144 const RuntimeDyld::LoadedObjectInfo
&L
) override
;
146 void notifyFreeingObject(ObjectKey Key
) override
;
149 static LineNumberInfo
DILineInfoToIntelJITFormat(uintptr_t StartAddress
,
152 LineNumberInfo Result
;
154 Result
.Offset
= Address
- StartAddress
;
155 Result
.LineNumber
= Line
.Line
;
160 static iJIT_Method_Load
FunctionDescToIntelJITFormat(
161 IntelJITEventsWrapper
& Wrapper
,
165 iJIT_Method_Load Result
;
166 memset(&Result
, 0, sizeof(iJIT_Method_Load
));
168 Result
.method_id
= Wrapper
.iJIT_GetNewMethodID();
169 Result
.method_name
= const_cast<char*>(FnName
);
170 Result
.method_load_address
= reinterpret_cast<void*>(FnStart
);
171 Result
.method_size
= FnSize
;
174 Result
.class_file_name
= NULL
;
175 Result
.user_data
= NULL
;
176 Result
.user_data_size
= 0;
177 Result
.env
= iJDE_JittingAPI
;
182 int getBackwardCompatibilityMode() {
184 char *BackwardCompatibilityEnv
= getenv("INTEL_JIT_BACKWARD_COMPATIBILITY");
185 int BackwardCompatibilityMode
= 0;
186 if (BackwardCompatibilityEnv
) {
187 StringRef(BackwardCompatibilityEnv
)
188 .getAsInteger(10, BackwardCompatibilityMode
);
190 return BackwardCompatibilityMode
;
193 void IntelJITEventListener::notifyObjectLoaded(
194 ObjectKey Key
, const ObjectFile
&Obj
,
195 const RuntimeDyld::LoadedObjectInfo
&L
) {
197 int BackwardCompatibilityMode
= getBackwardCompatibilityMode();
198 if (BackwardCompatibilityMode
== 0) {
200 std::unique_ptr
<IntelIttnotifyInfo
> ModuleIttnotify
=
201 std::make_unique
<IntelIttnotifyInfo
>(*Wrapper
);
202 ModuleIttnotify
->setModuleName(
203 StringRef(llvm::utohexstr(
204 MD5Hash(Obj
.getMemoryBufferRef().getBuffer()), true))
208 __itt_module_object
*ModuleObject
= new __itt_module_object();
209 ModuleObject
->module_name
= ModuleIttnotify
->getModuleName();
210 ModuleObject
->module_size
= Obj
.getMemoryBufferRef().getBufferSize();
211 Wrapper
->iJitIttNotifyInfo(llvm::LoadBinaryModule
,
212 ModuleObject
->module_name
,
213 ModuleObject
->module_size
);
214 ModuleObject
->module_type
= __itt_module_type_elf
;
215 ModuleObject
->section_number
=
216 ModuleIttnotify
->fillSectionInformation(Obj
, L
);
217 ModuleObject
->module_buffer
=
218 (void *)const_cast<char *>(Obj
.getMemoryBufferRef().getBufferStart());
219 ModuleObject
->module_id
=
220 __itt_id_make((void *)&(*ModuleObject
), ModuleObject
->module_size
);
221 ModuleObject
->section_array
=
222 ModuleIttnotify
->getSectionInfoVectorBegin();
223 ModuleIttnotify
->setModuleObject(ModuleObject
);
225 __itt_module_load_with_sections(ModuleObject
);
227 KeyToIttnotify
[Key
] = std::move(ModuleIttnotify
);
229 } else if (BackwardCompatibilityMode
== 1) {
231 OwningBinary
<ObjectFile
> DebugObjOwner
= L
.getObjectForDebug(Obj
);
232 const ObjectFile
*DebugObj
= DebugObjOwner
.getBinary();
236 // Get the address of the object image for use as a unique identifier
237 const void *ObjData
= DebugObj
->getData().data();
238 std::unique_ptr
<DIContext
> Context
= DWARFContext::create(*DebugObj
);
239 MethodAddressVector Functions
;
241 // Use symbol info to iterate functions in the object.
242 for (const std::pair
<SymbolRef
, uint64_t> &P
:
243 computeSymbolSizes(*DebugObj
)) {
244 SymbolRef Sym
= P
.first
;
245 std::vector
<LineNumberInfo
> LineInfo
;
246 std::string SourceFileName
;
248 Expected
<SymbolRef::Type
> SymTypeOrErr
= Sym
.getType();
250 // TODO: Actually report errors helpfully.
251 consumeError(SymTypeOrErr
.takeError());
254 SymbolRef::Type SymType
= *SymTypeOrErr
;
255 if (SymType
!= SymbolRef::ST_Function
)
258 Expected
<StringRef
> Name
= Sym
.getName();
260 // TODO: Actually report errors helpfully.
261 consumeError(Name
.takeError());
265 Expected
<uint64_t> AddrOrErr
= Sym
.getAddress();
267 // TODO: Actually report errors helpfully.
268 consumeError(AddrOrErr
.takeError());
271 uint64_t Addr
= *AddrOrErr
;
272 uint64_t Size
= P
.second
;
274 auto SecOrErr
= Sym
.getSection();
276 // TODO: Actually report errors helpfully.
277 consumeError(SecOrErr
.takeError());
280 object::section_iterator Sec
= *SecOrErr
;
281 if (Sec
== Obj
.section_end())
283 uint64_t Index
= Sec
->getIndex();
285 // Record this address in a local vector
286 Functions
.push_back((void *)Addr
);
288 // Build the function loaded notification message
289 iJIT_Method_Load FunctionMessage
=
290 FunctionDescToIntelJITFormat(*Wrapper
, Name
->data(), Addr
, Size
);
291 DILineInfoTable Lines
=
292 Context
->getLineInfoForAddressRange({Addr
, Index
}, Size
);
293 DILineInfoTable::iterator Begin
= Lines
.begin();
294 DILineInfoTable::iterator End
= Lines
.end();
295 for (DILineInfoTable::iterator It
= Begin
; It
!= End
; ++It
) {
297 DILineInfoToIntelJITFormat((uintptr_t)Addr
, It
->first
, It
->second
));
299 if (LineInfo
.size() == 0) {
300 FunctionMessage
.source_file_name
= 0;
301 FunctionMessage
.line_number_size
= 0;
302 FunctionMessage
.line_number_table
= 0;
304 // Source line information for the address range is provided as
305 // a code offset for the start of the corresponding sub-range and
306 // a source line. JIT API treats offsets in LineNumberInfo structures
307 // as the end of the corresponding code region. The start of the code
308 // is taken from the previous element. Need to shift the elements.
310 LineNumberInfo last
= LineInfo
.back();
311 last
.Offset
= FunctionMessage
.method_size
;
312 LineInfo
.push_back(last
);
313 for (size_t i
= LineInfo
.size() - 2; i
> 0; --i
)
314 LineInfo
[i
].LineNumber
= LineInfo
[i
- 1].LineNumber
;
316 SourceFileName
= Lines
.front().second
.FileName
;
317 FunctionMessage
.source_file_name
=
318 const_cast<char *>(SourceFileName
.c_str());
319 FunctionMessage
.line_number_size
= LineInfo
.size();
320 FunctionMessage
.line_number_table
= &*LineInfo
.begin();
323 Wrapper
->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED
,
325 MethodIDs
[(void *)Addr
] = FunctionMessage
.method_id
;
328 // To support object unload notification, we need to keep a list of
329 // registered function addresses for each loaded object. We will
330 // use the MethodIDs map to get the registered ID for each function.
331 LoadedObjectMap
[ObjData
] = Functions
;
332 DebugObjects
[Key
] = std::move(DebugObjOwner
);
336 void IntelJITEventListener::notifyFreeingObject(ObjectKey Key
) {
338 int BackwardCompatibilityMode
= getBackwardCompatibilityMode();
339 if (BackwardCompatibilityMode
== 0) {
340 if (KeyToIttnotify
.find(Key
) == KeyToIttnotify
.end())
342 __itt_module_unload_with_sections(KeyToIttnotify
[Key
]->getModuleObject());
343 Wrapper
->iJitIttNotifyInfo(
344 llvm::UnloadBinaryModule
,
345 KeyToIttnotify
[Key
]->getModuleObject()->module_name
,
346 KeyToIttnotify
[Key
]->getModuleObject()->module_size
);
347 KeyToIttnotify
.erase(Key
);
348 } else if (BackwardCompatibilityMode
== 1) {
349 // This object may not have been registered with the listener. If it wasn't,
351 if (DebugObjects
.find(Key
) == DebugObjects
.end())
354 // Get the address of the object image for use as a unique identifier
355 const ObjectFile
&DebugObj
= *DebugObjects
[Key
].getBinary();
356 const void *ObjData
= DebugObj
.getData().data();
358 // Get the object's function list from LoadedObjectMap
359 ObjectMap::iterator OI
= LoadedObjectMap
.find(ObjData
);
360 if (OI
== LoadedObjectMap
.end())
362 MethodAddressVector
&Functions
= OI
->second
;
364 // Walk the function list, unregistering each function
365 for (MethodAddressVector::iterator FI
= Functions
.begin(),
366 FE
= Functions
.end();
368 void *FnStart
= const_cast<void *>(*FI
);
369 MethodIDMap::iterator MI
= MethodIDs
.find(FnStart
);
370 if (MI
!= MethodIDs
.end()) {
371 Wrapper
->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START
,
377 // Erase the object from LoadedObjectMap
378 LoadedObjectMap
.erase(OI
);
379 DebugObjects
.erase(Key
);
383 } // anonymous namespace.
386 JITEventListener
*JITEventListener::createIntelJITEventListener() {
387 return new IntelJITEventListener(new IntelJITEventsWrapper
);
391 JITEventListener
*JITEventListener::createIntelJITEventListener(
392 IntelJITEventsWrapper
* TestImpl
) {
393 return new IntelJITEventListener(TestImpl
);
398 LLVMJITEventListenerRef
LLVMCreateIntelJITEventListener(void)
400 return wrap(JITEventListener::createIntelJITEventListener());