From 460e0b8ba233c092b43321d9c7b177df8ebe5a06 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Mon, 16 Nov 2020 19:22:20 +1100 Subject: [PATCH] [MCJIT] Profile the code generated by MCJIT engine using Intel VTune profiler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Patch by Elena Kovanova. Thanks Elena! Problem: LLVM already has a feature to profile the JIT-compiled code with VTune. This is done using Intel JIT Profiling API (https://github.com/intel/ittapi). Function information is captured by VTune as soon as the function is JIT-compiled. We tried to use the same approach to report the function information generated by the MCJIT engine – read parsing the debug information for in-memory ELF module and report it using JIT API. As the results, we figured out that it did not work properly for the following cases: inline functions, the functions located in multiple source files, the functions having several bodies (address ranges). Solution: To overcome limitations described above, we have introduced new APIs as a part of Intel ITT APIs to report the entire in-memory ELF module to be further processed as regular ELF binaries with debug information. This patch 1. Switches LLVM to open source version of Intel ITT/JIT APIs (https://github.com/intel/ittapi) to keep it always up to date. 2. Adds support of profiling the code generated by MCJIT engine using Intel VTune profiler Another separate patch will get rid of obsolete Intel ITT APIs stuff, having LLVM already switched to https://github.com/intel/ittapi. Differential Revision: https://reviews.llvm.org/D86435 --- .../IntelJITEvents/CMakeLists.txt | 22 + .../IntelJITEvents/IntelJITEventListener.cpp | 382 ++++++++++++------ .../IntelJITEvents/IntelJITEventsWrapper.h | 45 ++- test/JitListener/lit.local.cfg | 1 + tools/llvm-jitlistener/llvm-jitlistener.cpp | 43 +- 5 files changed, 357 insertions(+), 136 deletions(-) diff --git a/lib/ExecutionEngine/IntelJITEvents/CMakeLists.txt b/lib/ExecutionEngine/IntelJITEvents/CMakeLists.txt index b56ec508b5a..7f84b150581 100644 --- a/lib/ExecutionEngine/IntelJITEvents/CMakeLists.txt +++ b/lib/ExecutionEngine/IntelJITEvents/CMakeLists.txt @@ -1,5 +1,26 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/.. ) +set(GIT_REPOSITORY https://github.com/intel/ittapi.git) +set(GIT_TAG v3.18.8) + +if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/ittapi) + execute_process(COMMAND ${GIT_EXECUTABLE} clone ${GIT_REPOSITORY} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + RESULT_VARIABLE GIT_CLONE_RESULT) + if(NOT GIT_CLONE_RESULT EQUAL "0") + message(FATAL_ERROR "git clone ${GIT_REPOSITORY} failed with ${GIT_CLONE_RESULT}, please clone ${GIT_REPOSITORY}") + endif() +endif() + +execute_process(COMMAND ${GIT_EXECUTABLE} checkout ${GIT_TAG} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ittapi + RESULT_VARIABLE GIT_CHECKOUT_RESULT) +if(NOT GIT_CHECKOUT_RESULT EQUAL "0") + message(FATAL_ERROR "git checkout ${GIT_TAG} failed with ${GIT_CHECKOUT_RESULT}, please checkout ${GIT_TAG} at ${CMAKE_CURRENT_SOURCE_DIR}/ittapi") +endif() + +include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/ittapi/include/ ) + if( HAVE_LIBDL ) set(LLVM_INTEL_JIT_LIBS ${CMAKE_DL_LIBS}) endif() @@ -10,6 +31,7 @@ set(LLVM_INTEL_JIT_LIBS ${LLVM_PTHREAD_LIB} ${LLVM_INTEL_JIT_LIBS}) add_llvm_component_library(LLVMIntelJITEvents IntelJITEventListener.cpp jitprofiling.c + ittapi/src/ittnotify/ittnotify_static.c LINK_LIBS ${LLVM_INTEL_JIT_LIBS} diff --git a/lib/ExecutionEngine/IntelJITEvents/IntelJITEventListener.cpp b/lib/ExecutionEngine/IntelJITEvents/IntelJITEventListener.cpp index 1ebc820a8b4..3f75012f5cf 100644 --- a/lib/ExecutionEngine/IntelJITEvents/IntelJITEventListener.cpp +++ b/lib/ExecutionEngine/IntelJITEvents/IntelJITEventListener.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "IntelJITEventsWrapper.h" +#include "ittnotify.h" #include "llvm-c/ExecutionEngine.h" #include "llvm/ADT/DenseMap.h" #include "llvm/CodeGen/MachineFunction.h" @@ -36,6 +37,86 @@ using namespace llvm::object; namespace { +class IntelIttnotifyInfo { + std::string ModuleName; + std::vector SectionNamesVector; + std::vector<__itt_section_info> SectionInfoVector; + __itt_module_object *ModuleObject; + IntelJITEventsWrapper &WrapperRef; + +public: + IntelIttnotifyInfo(IntelJITEventsWrapper &Wrapper) + : ModuleObject(NULL), WrapperRef(Wrapper){}; + ~IntelIttnotifyInfo() { delete ModuleObject; }; + + void setModuleName(const char *Name) { ModuleName = std::string(Name); } + + const char *getModuleName() { return ModuleName.c_str(); } + + void setModuleObject(__itt_module_object *ModuleObj) { + ModuleObject = ModuleObj; + } + + __itt_module_object *getModuleObject() { return ModuleObject; } + + __itt_section_info *getSectionInfoVectorBegin() { + if (SectionInfoVector.size()) + return &SectionInfoVector[0]; + return NULL; + } + + void reportSection(llvm::IttEventType EventType, const char *SectionName, + unsigned int SectionSize) { + WrapperRef.iJitIttNotifyInfo(EventType, SectionName, SectionSize); + } + + int fillSectionInformation(const ObjectFile &Obj, + const RuntimeDyld::LoadedObjectInfo &L) { + + int SectionCounter = 0; + + for (auto &Section : Obj.sections()) { + uint64_t SectionLoadAddr = L.getSectionLoadAddress(Section); + if (SectionLoadAddr) { + object::ELFSectionRef ElfSection(Section); + + __itt_section_info SectionInfo; + memset(&SectionInfo, 0, sizeof(SectionInfo)); + SectionInfo.start_addr = reinterpret_cast(SectionLoadAddr); + SectionInfo.file_offset = ElfSection.getOffset(); + SectionInfo.flags = ElfSection.getFlags(); + + StringRef SectionName(""); + auto SectionNameOrError = ElfSection.getName(); + if (SectionNameOrError) + SectionName = *SectionNameOrError; + + SectionNamesVector.push_back(SectionName.str()); + SectionInfo.size = ElfSection.getSize(); + reportSection(llvm::LoadBinarySection, SectionName.str().c_str(), + SectionInfo.size); + + if (ElfSection.isBSS()) { + SectionInfo.type = itt_section_type_bss; + } else if (ElfSection.isData()) { + SectionInfo.type = itt_section_type_data; + } else if (ElfSection.isText()) { + SectionInfo.type = itt_section_type_text; + } + SectionInfoVector.push_back(SectionInfo); + ++SectionCounter; + } + } + // Hereinafter: don't change SectionNamesVector content to avoid vector + // reallocation - reallocation invalidates all the references, pointers, and + // iterators referring to the elements in the sequence. + for (int I = 0; I < SectionCounter; ++I) { + SectionInfoVector[I].name = SectionNamesVector[I].c_str(); + } + return SectionCounter; + } +}; + class IntelJITEventListener : public JITEventListener { typedef DenseMap MethodIDMap; @@ -48,6 +129,8 @@ class IntelJITEventListener : public JITEventListener { ObjectMap LoadedObjectMap; std::map> DebugObjects; + std::map> KeyToIttnotify; + public: IntelJITEventListener(IntelJITEventsWrapper* libraryWrapper) { Wrapper.reset(libraryWrapper); @@ -95,146 +178,205 @@ static iJIT_Method_Load FunctionDescToIntelJITFormat( return Result; } +int getBackwardCompatibilityMode() { + + char *BackwardCompatibilityEnv = getenv("INTEL_JIT_BACKWARD_COMPATIBILITY"); + int BackwardCompatibilityMode = 0; + if (BackwardCompatibilityEnv) { + StringRef(BackwardCompatibilityEnv) + .getAsInteger(10, BackwardCompatibilityMode); + } + return BackwardCompatibilityMode; +} + void IntelJITEventListener::notifyObjectLoaded( ObjectKey Key, const ObjectFile &Obj, const RuntimeDyld::LoadedObjectInfo &L) { - OwningBinary DebugObjOwner = L.getObjectForDebug(Obj); - const ObjectFile *DebugObj = DebugObjOwner.getBinary(); - if (!DebugObj) - return; + int BackwardCompatibilityMode = getBackwardCompatibilityMode(); + if (BackwardCompatibilityMode == 0) { + if (Obj.isELF()) { + std::unique_ptr ModuleIttnotify = + std::make_unique(*Wrapper); + ModuleIttnotify->setModuleName( + StringRef(llvm::utohexstr( + MD5Hash(Obj.getMemoryBufferRef().getBuffer()), true)) + .str() + .c_str()); - // Get the address of the object image for use as a unique identifier - const void* ObjData = DebugObj->getData().data(); - std::unique_ptr Context = DWARFContext::create(*DebugObj); - MethodAddressVector Functions; + __itt_module_object *ModuleObject = new __itt_module_object(); + ModuleObject->module_name = ModuleIttnotify->getModuleName(); + ModuleObject->module_size = Obj.getMemoryBufferRef().getBufferSize(); + Wrapper->iJitIttNotifyInfo(llvm::LoadBinaryModule, + ModuleObject->module_name, + ModuleObject->module_size); + ModuleObject->module_type = __itt_module_type_elf; + ModuleObject->section_number = + ModuleIttnotify->fillSectionInformation(Obj, L); + ModuleObject->module_buffer = + (void *)const_cast(Obj.getMemoryBufferRef().getBufferStart()); + ModuleObject->module_id = + __itt_id_make((void *)&(*ModuleObject), ModuleObject->module_size); + ModuleObject->section_array = + ModuleIttnotify->getSectionInfoVectorBegin(); + ModuleIttnotify->setModuleObject(ModuleObject); - // Use symbol info to iterate functions in the object. - for (const std::pair &P : computeSymbolSizes(*DebugObj)) { - SymbolRef Sym = P.first; - std::vector LineInfo; - std::string SourceFileName; + __itt_module_load_with_sections(ModuleObject); - Expected SymTypeOrErr = Sym.getType(); - if (!SymTypeOrErr) { - // TODO: Actually report errors helpfully. - consumeError(SymTypeOrErr.takeError()); - continue; + KeyToIttnotify[Key] = std::move(ModuleIttnotify); } - SymbolRef::Type SymType = *SymTypeOrErr; - if (SymType != SymbolRef::ST_Function) - continue; + } else if (BackwardCompatibilityMode == 1) { - Expected Name = Sym.getName(); - if (!Name) { - // TODO: Actually report errors helpfully. - consumeError(Name.takeError()); - continue; + OwningBinary DebugObjOwner = L.getObjectForDebug(Obj); + const ObjectFile *DebugObj = DebugObjOwner.getBinary(); + if (!DebugObj) + return; + + // Get the address of the object image for use as a unique identifier + const void *ObjData = DebugObj->getData().data(); + std::unique_ptr Context = DWARFContext::create(*DebugObj); + MethodAddressVector Functions; + + // Use symbol info to iterate functions in the object. + for (const std::pair &P : + computeSymbolSizes(*DebugObj)) { + SymbolRef Sym = P.first; + std::vector LineInfo; + std::string SourceFileName; + + Expected SymTypeOrErr = Sym.getType(); + if (!SymTypeOrErr) { + // TODO: Actually report errors helpfully. + consumeError(SymTypeOrErr.takeError()); + continue; + } + SymbolRef::Type SymType = *SymTypeOrErr; + if (SymType != SymbolRef::ST_Function) + continue; + + Expected Name = Sym.getName(); + if (!Name) { + // TODO: Actually report errors helpfully. + consumeError(Name.takeError()); + continue; + } + + Expected AddrOrErr = Sym.getAddress(); + if (!AddrOrErr) { + // TODO: Actually report errors helpfully. + consumeError(AddrOrErr.takeError()); + continue; + } + uint64_t Addr = *AddrOrErr; + uint64_t Size = P.second; + + auto SecOrErr = Sym.getSection(); + if (!SecOrErr) { + // TODO: Actually report errors helpfully. + consumeError(SecOrErr.takeError()); + continue; + } + object::section_iterator Sec = *SecOrErr; + if (Sec == Obj.section_end()) + continue; + uint64_t Index = Sec->getIndex(); + + // Record this address in a local vector + Functions.push_back((void *)Addr); + + // Build the function loaded notification message + iJIT_Method_Load FunctionMessage = + FunctionDescToIntelJITFormat(*Wrapper, Name->data(), Addr, Size); + DILineInfoTable Lines = + Context->getLineInfoForAddressRange({Addr, Index}, Size); + DILineInfoTable::iterator Begin = Lines.begin(); + DILineInfoTable::iterator End = Lines.end(); + for (DILineInfoTable::iterator It = Begin; It != End; ++It) { + LineInfo.push_back( + DILineInfoToIntelJITFormat((uintptr_t)Addr, It->first, It->second)); + } + if (LineInfo.size() == 0) { + FunctionMessage.source_file_name = 0; + FunctionMessage.line_number_size = 0; + FunctionMessage.line_number_table = 0; + } else { + // Source line information for the address range is provided as + // a code offset for the start of the corresponding sub-range and + // a source line. JIT API treats offsets in LineNumberInfo structures + // as the end of the corresponding code region. The start of the code + // is taken from the previous element. Need to shift the elements. + + LineNumberInfo last = LineInfo.back(); + last.Offset = FunctionMessage.method_size; + LineInfo.push_back(last); + for (size_t i = LineInfo.size() - 2; i > 0; --i) + LineInfo[i].LineNumber = LineInfo[i - 1].LineNumber; + + SourceFileName = Lines.front().second.FileName; + FunctionMessage.source_file_name = + const_cast(SourceFileName.c_str()); + FunctionMessage.line_number_size = LineInfo.size(); + FunctionMessage.line_number_table = &*LineInfo.begin(); + } + + Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, + &FunctionMessage); + MethodIDs[(void *)Addr] = FunctionMessage.method_id; } - Expected AddrOrErr = Sym.getAddress(); - if (!AddrOrErr) { - // TODO: Actually report errors helpfully. - consumeError(AddrOrErr.takeError()); - continue; - } - uint64_t Addr = *AddrOrErr; - uint64_t Size = P.second; - - auto SecOrErr = Sym.getSection(); - if (!SecOrErr) { - // TODO: Actually report errors helpfully. - consumeError(SecOrErr.takeError()); - continue; - } - object::section_iterator Sec = *SecOrErr; - if (Sec == Obj.section_end()) - continue; - uint64_t Index = Sec->getIndex(); - - // Record this address in a local vector - Functions.push_back((void*)Addr); - - // Build the function loaded notification message - iJIT_Method_Load FunctionMessage = - FunctionDescToIntelJITFormat(*Wrapper, Name->data(), Addr, Size); - DILineInfoTable Lines = - Context->getLineInfoForAddressRange({Addr, Index}, Size); - DILineInfoTable::iterator Begin = Lines.begin(); - DILineInfoTable::iterator End = Lines.end(); - for (DILineInfoTable::iterator It = Begin; It != End; ++It) { - LineInfo.push_back( - DILineInfoToIntelJITFormat((uintptr_t)Addr, It->first, It->second)); - } - if (LineInfo.size() == 0) { - FunctionMessage.source_file_name = 0; - FunctionMessage.line_number_size = 0; - FunctionMessage.line_number_table = 0; - } else { - // Source line information for the address range is provided as - // a code offset for the start of the corresponding sub-range and - // a source line. JIT API treats offsets in LineNumberInfo structures - // as the end of the corresponding code region. The start of the code - // is taken from the previous element. Need to shift the elements. - - LineNumberInfo last = LineInfo.back(); - last.Offset = FunctionMessage.method_size; - LineInfo.push_back(last); - for (size_t i = LineInfo.size() - 2; i > 0; --i) - LineInfo[i].LineNumber = LineInfo[i - 1].LineNumber; - - SourceFileName = Lines.front().second.FileName; - FunctionMessage.source_file_name = - const_cast(SourceFileName.c_str()); - FunctionMessage.line_number_size = LineInfo.size(); - FunctionMessage.line_number_table = &*LineInfo.begin(); - } - - Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, - &FunctionMessage); - MethodIDs[(void*)Addr] = FunctionMessage.method_id; + // To support object unload notification, we need to keep a list of + // registered function addresses for each loaded object. We will + // use the MethodIDs map to get the registered ID for each function. + LoadedObjectMap[ObjData] = Functions; + DebugObjects[Key] = std::move(DebugObjOwner); } - - // To support object unload notification, we need to keep a list of - // registered function addresses for each loaded object. We will - // use the MethodIDs map to get the registered ID for each function. - LoadedObjectMap[ObjData] = Functions; - DebugObjects[Key] = std::move(DebugObjOwner); } void IntelJITEventListener::notifyFreeingObject(ObjectKey Key) { - // This object may not have been registered with the listener. If it wasn't, - // bail out. - if (DebugObjects.find(Key) == DebugObjects.end()) - return; - // Get the address of the object image for use as a unique identifier - const ObjectFile &DebugObj = *DebugObjects[Key].getBinary(); - const void* ObjData = DebugObj.getData().data(); + int BackwardCompatibilityMode = getBackwardCompatibilityMode(); + if (BackwardCompatibilityMode == 0) { + if (KeyToIttnotify.find(Key) == KeyToIttnotify.end()) + return; + __itt_module_unload_with_sections(KeyToIttnotify[Key]->getModuleObject()); + Wrapper->iJitIttNotifyInfo( + llvm::UnloadBinaryModule, + KeyToIttnotify[Key]->getModuleObject()->module_name, + KeyToIttnotify[Key]->getModuleObject()->module_size); + KeyToIttnotify.erase(Key); + } else if (BackwardCompatibilityMode == 1) { + // This object may not have been registered with the listener. If it wasn't, + // bail out. + if (DebugObjects.find(Key) == DebugObjects.end()) + return; - // Get the object's function list from LoadedObjectMap - ObjectMap::iterator OI = LoadedObjectMap.find(ObjData); - if (OI == LoadedObjectMap.end()) - return; - MethodAddressVector& Functions = OI->second; + // Get the address of the object image for use as a unique identifier + const ObjectFile &DebugObj = *DebugObjects[Key].getBinary(); + const void *ObjData = DebugObj.getData().data(); - // Walk the function list, unregistering each function - for (MethodAddressVector::iterator FI = Functions.begin(), - FE = Functions.end(); - FI != FE; - ++FI) { - void* FnStart = const_cast(*FI); - MethodIDMap::iterator MI = MethodIDs.find(FnStart); - if (MI != MethodIDs.end()) { - Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START, - &MI->second); - MethodIDs.erase(MI); + // Get the object's function list from LoadedObjectMap + ObjectMap::iterator OI = LoadedObjectMap.find(ObjData); + if (OI == LoadedObjectMap.end()) + return; + MethodAddressVector &Functions = OI->second; + + // Walk the function list, unregistering each function + for (MethodAddressVector::iterator FI = Functions.begin(), + FE = Functions.end(); + FI != FE; ++FI) { + void *FnStart = const_cast(*FI); + MethodIDMap::iterator MI = MethodIDs.find(FnStart); + if (MI != MethodIDs.end()) { + Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START, + &MI->second); + MethodIDs.erase(MI); + } } - } - // Erase the object from LoadedObjectMap - LoadedObjectMap.erase(OI); - DebugObjects.erase(Key); + // Erase the object from LoadedObjectMap + LoadedObjectMap.erase(OI); + DebugObjects.erase(Key); + } } } // anonymous namespace. diff --git a/lib/ExecutionEngine/IntelJITEvents/IntelJITEventsWrapper.h b/lib/ExecutionEngine/IntelJITEvents/IntelJITEventsWrapper.h index 68699c6a220..088b33b798a 100644 --- a/lib/ExecutionEngine/IntelJITEvents/IntelJITEventsWrapper.h +++ b/lib/ExecutionEngine/IntelJITEvents/IntelJITEventsWrapper.h @@ -21,10 +21,18 @@ namespace llvm { +typedef enum { + LoadBinaryModule, + LoadBinarySection, + UnloadBinaryModule, + UnloadBinarySection +} IttEventType; + class IntelJITEventsWrapper { // Function pointer types for testing implementation of Intel jitprofiling // library typedef int (*NotifyEventPtr)(iJIT_JVM_EVENT, void*); + typedef int (*IttnotifyInfoPtr)(IttEventType, const char *, unsigned int); typedef void (*RegisterCallbackExPtr)(void *, iJIT_ModeChangedEx ); typedef iJIT_IsProfilingActiveFlags (*IsProfilingActivePtr)(void); typedef void (*FinalizeThreadPtr)(void); @@ -32,6 +40,7 @@ class IntelJITEventsWrapper { typedef unsigned int (*GetNewMethodIDPtr)(void); NotifyEventPtr NotifyEventFunc; + IttnotifyInfoPtr IttnotifyInfoFunc; RegisterCallbackExPtr RegisterCallbackExFunc; IsProfilingActivePtr IsProfilingActiveFunc; GetNewMethodIDPtr GetNewMethodIDFunc; @@ -42,23 +51,22 @@ public: } IntelJITEventsWrapper() - : NotifyEventFunc(::iJIT_NotifyEvent), - RegisterCallbackExFunc(::iJIT_RegisterCallbackEx), - IsProfilingActiveFunc(::iJIT_IsProfilingActive), - GetNewMethodIDFunc(::iJIT_GetNewMethodID) { - } + : NotifyEventFunc(::iJIT_NotifyEvent), IttnotifyInfoFunc(0), + RegisterCallbackExFunc(::iJIT_RegisterCallbackEx), + IsProfilingActiveFunc(::iJIT_IsProfilingActive), + GetNewMethodIDFunc(::iJIT_GetNewMethodID) {} IntelJITEventsWrapper(NotifyEventPtr NotifyEventImpl, - RegisterCallbackExPtr RegisterCallbackExImpl, - IsProfilingActivePtr IsProfilingActiveImpl, - FinalizeThreadPtr FinalizeThreadImpl, - FinalizeProcessPtr FinalizeProcessImpl, - GetNewMethodIDPtr GetNewMethodIDImpl) - : NotifyEventFunc(NotifyEventImpl), - RegisterCallbackExFunc(RegisterCallbackExImpl), - IsProfilingActiveFunc(IsProfilingActiveImpl), - GetNewMethodIDFunc(GetNewMethodIDImpl) { - } + IttnotifyInfoPtr IttnotifyInfoImpl, + RegisterCallbackExPtr RegisterCallbackExImpl, + IsProfilingActivePtr IsProfilingActiveImpl, + FinalizeThreadPtr FinalizeThreadImpl, + FinalizeProcessPtr FinalizeProcessImpl, + GetNewMethodIDPtr GetNewMethodIDImpl) + : NotifyEventFunc(NotifyEventImpl), IttnotifyInfoFunc(IttnotifyInfoImpl), + RegisterCallbackExFunc(RegisterCallbackExImpl), + IsProfilingActiveFunc(IsProfilingActiveImpl), + GetNewMethodIDFunc(GetNewMethodIDImpl) {} // Sends an event announcing that a function has been emitted // return values are event-specific. See Intel documentation for details. @@ -68,6 +76,13 @@ public: return NotifyEventFunc(EventType, EventSpecificData); } + int iJitIttNotifyInfo(IttEventType EventType, const char *Name, + unsigned int Size) { + if (!IttnotifyInfoFunc) + return -1; + return IttnotifyInfoFunc(EventType, Name, Size); + } + // Registers a callback function to receive notice of profiling state changes void iJIT_RegisterCallbackEx(void *UserData, iJIT_ModeChangedEx NewModeCallBackFuncEx) { diff --git a/test/JitListener/lit.local.cfg b/test/JitListener/lit.local.cfg index 50a54ebe7ea..1576fbe9edd 100644 --- a/test/JitListener/lit.local.cfg +++ b/test/JitListener/lit.local.cfg @@ -1,2 +1,3 @@ if not config.root.llvm_use_intel_jitevents: config.unsupported = True +config.environment['INTEL_JIT_BACKWARD_COMPATIBILITY'] = '1' diff --git a/tools/llvm-jitlistener/llvm-jitlistener.cpp b/tools/llvm-jitlistener/llvm-jitlistener.cpp index 82a798d3f74..52428dc758e 100644 --- a/tools/llvm-jitlistener/llvm-jitlistener.cpp +++ b/tools/llvm-jitlistener/llvm-jitlistener.cpp @@ -88,6 +88,46 @@ int NotifyEvent(iJIT_JVM_EVENT EventType, void *EventSpecificData) { return 0; } +int ittNotifyInfo(IttEventType EventType, const char *Name, unsigned int Size) { + switch (EventType) { + case LoadBinaryModule: { + if (!Name) { + errs() << "Error: The IttNotify event listener did not provide a module " + "name."; + return -1; + } + outs() << "Module loaded : Name = " << Name << ", Size = " << Size << "\n"; + } break; + case LoadBinarySection: { + if (!Name) { + errs() << "Error: The IttNotify event listener did not provide a section " + "name."; + return -1; + } + outs() << "Loaded section : Name = " << Name << ", Size = " << Size << "\n"; + } break; + case UnloadBinaryModule: { + if (!Name) { + errs() << "Error: The IttNotify event listener did not provide a module " + "name."; + return -1; + } + outs() << "Module unloaded : Name = " << Name << ", Size = " << Size + << "\n"; + } break; + case UnloadBinarySection: { + if (!Name) { + errs() << "Error: The IttNotify event listener did not provide a section " + "name."; + return -1; + } + outs() << "Unloaded section : Name = " << Name << ", Size = " << Size + << "\n"; + } break; + } + return 0; +} + iJIT_IsProfilingActiveFlags IsProfilingActive(void) { // for testing, pretend we have an Intel Parallel Amplifier XE 2011 // instance attached @@ -155,7 +195,8 @@ public: std::unique_ptr Listener( JITEventListener::createIntelJITEventListener(new IntelJITEventsWrapper( - NotifyEvent, 0, IsProfilingActive, 0, 0, GetNewMethodID))); + NotifyEvent, ittNotifyInfo, 0, IsProfilingActive, 0, 0, + GetNewMethodID))); TheJIT->RegisterJITEventListener(Listener.get());