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 "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/ObjectFile.h"
28 #include "llvm/Object/SymbolSize.h"
29 #include "llvm/Support/Debug.h"
30 #include "llvm/Support/Errno.h"
31 #include "llvm/Support/raw_ostream.h"
34 using namespace llvm::object
;
36 #define DEBUG_TYPE "amplifier-jit-event-listener"
40 class IntelIttnotifyInfo
{
41 std::string ModuleName
;
42 std::vector
<std::string
> SectionNamesVector
;
43 std::vector
<__itt_section_info
> SectionInfoVector
;
44 __itt_module_object
*ModuleObject
;
45 IntelJITEventsWrapper
&WrapperRef
;
48 IntelIttnotifyInfo(IntelJITEventsWrapper
&Wrapper
)
49 : ModuleObject(NULL
), WrapperRef(Wrapper
){};
50 ~IntelIttnotifyInfo() { delete ModuleObject
; };
52 void setModuleName(const char *Name
) { ModuleName
= std::string(Name
); }
54 const char *getModuleName() { return ModuleName
.c_str(); }
56 void setModuleObject(__itt_module_object
*ModuleObj
) {
57 ModuleObject
= ModuleObj
;
60 __itt_module_object
*getModuleObject() { return ModuleObject
; }
62 __itt_section_info
*getSectionInfoVectorBegin() {
63 if (SectionInfoVector
.size())
64 return &SectionInfoVector
[0];
68 void reportSection(llvm::IttEventType EventType
, const char *SectionName
,
69 unsigned int SectionSize
) {
70 WrapperRef
.iJitIttNotifyInfo(EventType
, SectionName
, SectionSize
);
73 int fillSectionInformation(const ObjectFile
&Obj
,
74 const RuntimeDyld::LoadedObjectInfo
&L
) {
76 int SectionCounter
= 0;
78 for (auto &Section
: Obj
.sections()) {
79 uint64_t SectionLoadAddr
= L
.getSectionLoadAddress(Section
);
80 if (SectionLoadAddr
) {
81 object::ELFSectionRef
ElfSection(Section
);
83 __itt_section_info SectionInfo
;
84 memset(&SectionInfo
, 0, sizeof(SectionInfo
));
85 SectionInfo
.start_addr
= reinterpret_cast<void *>(SectionLoadAddr
);
86 SectionInfo
.file_offset
= ElfSection
.getOffset();
87 SectionInfo
.flags
= ElfSection
.getFlags();
89 StringRef
SectionName("");
90 auto SectionNameOrError
= ElfSection
.getName();
91 if (SectionNameOrError
)
92 SectionName
= *SectionNameOrError
;
94 SectionNamesVector
.push_back(SectionName
.str());
95 SectionInfo
.size
= ElfSection
.getSize();
96 reportSection(llvm::LoadBinarySection
, SectionName
.str().c_str(),
99 if (ElfSection
.isBSS()) {
100 SectionInfo
.type
= itt_section_type_bss
;
101 } else if (ElfSection
.isData()) {
102 SectionInfo
.type
= itt_section_type_data
;
103 } else if (ElfSection
.isText()) {
104 SectionInfo
.type
= itt_section_type_text
;
106 SectionInfoVector
.push_back(SectionInfo
);
110 // Hereinafter: don't change SectionNamesVector content to avoid vector
111 // reallocation - reallocation invalidates all the references, pointers, and
112 // iterators referring to the elements in the sequence.
113 for (int I
= 0; I
< SectionCounter
; ++I
) {
114 SectionInfoVector
[I
].name
= SectionNamesVector
[I
].c_str();
116 return SectionCounter
;
120 class IntelJITEventListener
: public JITEventListener
{
121 typedef DenseMap
<void*, unsigned int> MethodIDMap
;
123 std::unique_ptr
<IntelJITEventsWrapper
> Wrapper
;
124 MethodIDMap MethodIDs
;
126 typedef SmallVector
<const void *, 64> MethodAddressVector
;
127 typedef DenseMap
<const void *, MethodAddressVector
> ObjectMap
;
129 ObjectMap LoadedObjectMap
;
130 std::map
<ObjectKey
, OwningBinary
<ObjectFile
>> DebugObjects
;
132 std::map
<ObjectKey
, std::unique_ptr
<IntelIttnotifyInfo
>> KeyToIttnotify
;
135 IntelJITEventListener(IntelJITEventsWrapper
* libraryWrapper
) {
136 Wrapper
.reset(libraryWrapper
);
139 ~IntelJITEventListener() {
142 void notifyObjectLoaded(ObjectKey Key
, const ObjectFile
&Obj
,
143 const RuntimeDyld::LoadedObjectInfo
&L
) override
;
145 void notifyFreeingObject(ObjectKey Key
) override
;
148 static LineNumberInfo
DILineInfoToIntelJITFormat(uintptr_t StartAddress
,
151 LineNumberInfo Result
;
153 Result
.Offset
= Address
- StartAddress
;
154 Result
.LineNumber
= Line
.Line
;
159 static iJIT_Method_Load
FunctionDescToIntelJITFormat(
160 IntelJITEventsWrapper
& Wrapper
,
164 iJIT_Method_Load Result
;
165 memset(&Result
, 0, sizeof(iJIT_Method_Load
));
167 Result
.method_id
= Wrapper
.iJIT_GetNewMethodID();
168 Result
.method_name
= const_cast<char*>(FnName
);
169 Result
.method_load_address
= reinterpret_cast<void*>(FnStart
);
170 Result
.method_size
= FnSize
;
173 Result
.class_file_name
= NULL
;
174 Result
.user_data
= NULL
;
175 Result
.user_data_size
= 0;
176 Result
.env
= iJDE_JittingAPI
;
181 int getBackwardCompatibilityMode() {
183 char *BackwardCompatibilityEnv
= getenv("INTEL_JIT_BACKWARD_COMPATIBILITY");
184 int BackwardCompatibilityMode
= 0;
185 if (BackwardCompatibilityEnv
) {
186 StringRef(BackwardCompatibilityEnv
)
187 .getAsInteger(10, BackwardCompatibilityMode
);
189 return BackwardCompatibilityMode
;
192 void IntelJITEventListener::notifyObjectLoaded(
193 ObjectKey Key
, const ObjectFile
&Obj
,
194 const RuntimeDyld::LoadedObjectInfo
&L
) {
196 int BackwardCompatibilityMode
= getBackwardCompatibilityMode();
197 if (BackwardCompatibilityMode
== 0) {
199 std::unique_ptr
<IntelIttnotifyInfo
> ModuleIttnotify
=
200 std::make_unique
<IntelIttnotifyInfo
>(*Wrapper
);
201 ModuleIttnotify
->setModuleName(
202 StringRef(llvm::utohexstr(
203 MD5Hash(Obj
.getMemoryBufferRef().getBuffer()), true))
207 __itt_module_object
*ModuleObject
= new __itt_module_object();
208 ModuleObject
->module_name
= ModuleIttnotify
->getModuleName();
209 ModuleObject
->module_size
= Obj
.getMemoryBufferRef().getBufferSize();
210 Wrapper
->iJitIttNotifyInfo(llvm::LoadBinaryModule
,
211 ModuleObject
->module_name
,
212 ModuleObject
->module_size
);
213 ModuleObject
->module_type
= __itt_module_type_elf
;
214 ModuleObject
->section_number
=
215 ModuleIttnotify
->fillSectionInformation(Obj
, L
);
216 ModuleObject
->module_buffer
=
217 (void *)const_cast<char *>(Obj
.getMemoryBufferRef().getBufferStart());
218 ModuleObject
->module_id
=
219 __itt_id_make((void *)&(*ModuleObject
), ModuleObject
->module_size
);
220 ModuleObject
->section_array
=
221 ModuleIttnotify
->getSectionInfoVectorBegin();
222 ModuleIttnotify
->setModuleObject(ModuleObject
);
224 __itt_module_load_with_sections(ModuleObject
);
226 KeyToIttnotify
[Key
] = std::move(ModuleIttnotify
);
228 } else if (BackwardCompatibilityMode
== 1) {
230 OwningBinary
<ObjectFile
> DebugObjOwner
= L
.getObjectForDebug(Obj
);
231 const ObjectFile
*DebugObj
= DebugObjOwner
.getBinary();
235 // Get the address of the object image for use as a unique identifier
236 const void *ObjData
= DebugObj
->getData().data();
237 std::unique_ptr
<DIContext
> Context
= DWARFContext::create(*DebugObj
);
238 MethodAddressVector Functions
;
240 // Use symbol info to iterate functions in the object.
241 for (const std::pair
<SymbolRef
, uint64_t> &P
:
242 computeSymbolSizes(*DebugObj
)) {
243 SymbolRef Sym
= P
.first
;
244 std::vector
<LineNumberInfo
> LineInfo
;
245 std::string SourceFileName
;
247 Expected
<SymbolRef::Type
> SymTypeOrErr
= Sym
.getType();
249 // TODO: Actually report errors helpfully.
250 consumeError(SymTypeOrErr
.takeError());
253 SymbolRef::Type SymType
= *SymTypeOrErr
;
254 if (SymType
!= SymbolRef::ST_Function
)
257 Expected
<StringRef
> Name
= Sym
.getName();
259 // TODO: Actually report errors helpfully.
260 consumeError(Name
.takeError());
264 Expected
<uint64_t> AddrOrErr
= Sym
.getAddress();
266 // TODO: Actually report errors helpfully.
267 consumeError(AddrOrErr
.takeError());
270 uint64_t Addr
= *AddrOrErr
;
271 uint64_t Size
= P
.second
;
273 auto SecOrErr
= Sym
.getSection();
275 // TODO: Actually report errors helpfully.
276 consumeError(SecOrErr
.takeError());
279 object::section_iterator Sec
= *SecOrErr
;
280 if (Sec
== Obj
.section_end())
282 uint64_t Index
= Sec
->getIndex();
284 // Record this address in a local vector
285 Functions
.push_back((void *)Addr
);
287 // Build the function loaded notification message
288 iJIT_Method_Load FunctionMessage
=
289 FunctionDescToIntelJITFormat(*Wrapper
, Name
->data(), Addr
, Size
);
290 DILineInfoTable Lines
=
291 Context
->getLineInfoForAddressRange({Addr
, Index
}, Size
);
292 DILineInfoTable::iterator Begin
= Lines
.begin();
293 DILineInfoTable::iterator End
= Lines
.end();
294 for (DILineInfoTable::iterator It
= Begin
; It
!= End
; ++It
) {
296 DILineInfoToIntelJITFormat((uintptr_t)Addr
, It
->first
, It
->second
));
298 if (LineInfo
.size() == 0) {
299 FunctionMessage
.source_file_name
= 0;
300 FunctionMessage
.line_number_size
= 0;
301 FunctionMessage
.line_number_table
= 0;
303 // Source line information for the address range is provided as
304 // a code offset for the start of the corresponding sub-range and
305 // a source line. JIT API treats offsets in LineNumberInfo structures
306 // as the end of the corresponding code region. The start of the code
307 // is taken from the previous element. Need to shift the elements.
309 LineNumberInfo last
= LineInfo
.back();
310 last
.Offset
= FunctionMessage
.method_size
;
311 LineInfo
.push_back(last
);
312 for (size_t i
= LineInfo
.size() - 2; i
> 0; --i
)
313 LineInfo
[i
].LineNumber
= LineInfo
[i
- 1].LineNumber
;
315 SourceFileName
= Lines
.front().second
.FileName
;
316 FunctionMessage
.source_file_name
=
317 const_cast<char *>(SourceFileName
.c_str());
318 FunctionMessage
.line_number_size
= LineInfo
.size();
319 FunctionMessage
.line_number_table
= &*LineInfo
.begin();
322 Wrapper
->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED
,
324 MethodIDs
[(void *)Addr
] = FunctionMessage
.method_id
;
327 // To support object unload notification, we need to keep a list of
328 // registered function addresses for each loaded object. We will
329 // use the MethodIDs map to get the registered ID for each function.
330 LoadedObjectMap
[ObjData
] = Functions
;
331 DebugObjects
[Key
] = std::move(DebugObjOwner
);
335 void IntelJITEventListener::notifyFreeingObject(ObjectKey Key
) {
337 int BackwardCompatibilityMode
= getBackwardCompatibilityMode();
338 if (BackwardCompatibilityMode
== 0) {
339 if (KeyToIttnotify
.find(Key
) == KeyToIttnotify
.end())
341 __itt_module_unload_with_sections(KeyToIttnotify
[Key
]->getModuleObject());
342 Wrapper
->iJitIttNotifyInfo(
343 llvm::UnloadBinaryModule
,
344 KeyToIttnotify
[Key
]->getModuleObject()->module_name
,
345 KeyToIttnotify
[Key
]->getModuleObject()->module_size
);
346 KeyToIttnotify
.erase(Key
);
347 } else if (BackwardCompatibilityMode
== 1) {
348 // This object may not have been registered with the listener. If it wasn't,
350 if (DebugObjects
.find(Key
) == DebugObjects
.end())
353 // Get the address of the object image for use as a unique identifier
354 const ObjectFile
&DebugObj
= *DebugObjects
[Key
].getBinary();
355 const void *ObjData
= DebugObj
.getData().data();
357 // Get the object's function list from LoadedObjectMap
358 ObjectMap::iterator OI
= LoadedObjectMap
.find(ObjData
);
359 if (OI
== LoadedObjectMap
.end())
361 MethodAddressVector
&Functions
= OI
->second
;
363 // Walk the function list, unregistering each function
364 for (MethodAddressVector::iterator FI
= Functions
.begin(),
365 FE
= Functions
.end();
367 void *FnStart
= const_cast<void *>(*FI
);
368 MethodIDMap::iterator MI
= MethodIDs
.find(FnStart
);
369 if (MI
!= MethodIDs
.end()) {
370 Wrapper
->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START
,
376 // Erase the object from LoadedObjectMap
377 LoadedObjectMap
.erase(OI
);
378 DebugObjects
.erase(Key
);
382 } // anonymous namespace.
385 JITEventListener
*JITEventListener::createIntelJITEventListener() {
386 return new IntelJITEventListener(new IntelJITEventsWrapper
);
390 JITEventListener
*JITEventListener::createIntelJITEventListener(
391 IntelJITEventsWrapper
* TestImpl
) {
392 return new IntelJITEventListener(TestImpl
);
397 LLVMJITEventListenerRef
LLVMCreateIntelJITEventListener(void)
399 return wrap(JITEventListener::createIntelJITEventListener());