OSDN Git Service

[MCJIT] Profile the code generated by MCJIT engine using Intel VTune profiler
authorLang Hames <lhames@gmail.com>
Mon, 16 Nov 2020 08:22:20 +0000 (19:22 +1100)
committerLang Hames <lhames@gmail.com>
Mon, 16 Nov 2020 08:28:14 +0000 (19:28 +1100)
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

llvm/lib/ExecutionEngine/IntelJITEvents/CMakeLists.txt
llvm/lib/ExecutionEngine/IntelJITEvents/IntelJITEventListener.cpp
llvm/lib/ExecutionEngine/IntelJITEvents/IntelJITEventsWrapper.h
llvm/test/JitListener/lit.local.cfg
llvm/tools/llvm-jitlistener/llvm-jitlistener.cpp

index b56ec50..7f84b15 100644 (file)
@@ -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}
 
index 1ebc820..3f75012 100644 (file)
@@ -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<std::string> 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<void *>(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<void*, unsigned int> MethodIDMap;
 
@@ -48,6 +129,8 @@ class IntelJITEventListener : public JITEventListener {
   ObjectMap  LoadedObjectMap;
   std::map<ObjectKey, OwningBinary<ObjectFile>> DebugObjects;
 
+  std::map<ObjectKey, std::unique_ptr<IntelIttnotifyInfo>> 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<ObjectFile> 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<DIContext> Context = DWARFContext::create(*DebugObj);
-  MethodAddressVector Functions;
-
-  // Use symbol info to iterate functions in the object.
-  for (const std::pair<SymbolRef, uint64_t> &P : computeSymbolSizes(*DebugObj)) {
-    SymbolRef Sym = P.first;
-    std::vector<LineNumberInfo> LineInfo;
-    std::string SourceFileName;
-
-    Expected<SymbolRef::Type> SymTypeOrErr = Sym.getType();
-    if (!SymTypeOrErr) {
-      // TODO: Actually report errors helpfully.
-      consumeError(SymTypeOrErr.takeError());
-      continue;
+  int BackwardCompatibilityMode = getBackwardCompatibilityMode();
+  if (BackwardCompatibilityMode == 0) {
+    if (Obj.isELF()) {
+      std::unique_ptr<IntelIttnotifyInfo> ModuleIttnotify =
+          std::make_unique<IntelIttnotifyInfo>(*Wrapper);
+      ModuleIttnotify->setModuleName(
+          StringRef(llvm::utohexstr(
+                        MD5Hash(Obj.getMemoryBufferRef().getBuffer()), true))
+              .str()
+              .c_str());
+
+      __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<char *>(Obj.getMemoryBufferRef().getBufferStart());
+      ModuleObject->module_id =
+          __itt_id_make((void *)&(*ModuleObject), ModuleObject->module_size);
+      ModuleObject->section_array =
+          ModuleIttnotify->getSectionInfoVectorBegin();
+      ModuleIttnotify->setModuleObject(ModuleObject);
+
+      __itt_module_load_with_sections(ModuleObject);
+
+      KeyToIttnotify[Key] = std::move(ModuleIttnotify);
     }
-    SymbolRef::Type SymType = *SymTypeOrErr;
-    if (SymType != SymbolRef::ST_Function)
-      continue;
-
-    Expected<StringRef> Name = Sym.getName();
-    if (!Name) {
-      // TODO: Actually report errors helpfully.
-      consumeError(Name.takeError());
-      continue;
+  } else if (BackwardCompatibilityMode == 1) {
+
+    OwningBinary<ObjectFile> 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<DIContext> Context = DWARFContext::create(*DebugObj);
+    MethodAddressVector Functions;
+
+    // Use symbol info to iterate functions in the object.
+    for (const std::pair<SymbolRef, uint64_t> &P :
+         computeSymbolSizes(*DebugObj)) {
+      SymbolRef Sym = P.first;
+      std::vector<LineNumberInfo> LineInfo;
+      std::string SourceFileName;
+
+      Expected<SymbolRef::Type> 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<StringRef> Name = Sym.getName();
+      if (!Name) {
+        // TODO: Actually report errors helpfully.
+        consumeError(Name.takeError());
+        continue;
+      }
+
+      Expected<uint64_t> 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<char *>(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<uint64_t> 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<char *>(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();
-
-  // 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<void*>(*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);
+
+  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 address of the object image for use as a unique identifier
+    const ObjectFile &DebugObj = *DebugObjects[Key].getBinary();
+    const void *ObjData = DebugObj.getData().data();
+
+    // 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<void *>(*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.
index 68699c6..088b33b 100644 (file)
 
 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) {
index 50a54eb..1576fbe 100644 (file)
@@ -1,2 +1,3 @@
 if not config.root.llvm_use_intel_jitevents:
     config.unsupported = True
+config.environment['INTEL_JIT_BACKWARD_COMPATIBILITY'] = '1'
index 82a798d..52428dc 100644 (file)
@@ -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<llvm::JITEventListener> Listener(
         JITEventListener::createIntelJITEventListener(new IntelJITEventsWrapper(
-            NotifyEvent, 0, IsProfilingActive, 0, 0, GetNewMethodID)));
+            NotifyEvent, ittNotifyInfo, 0, IsProfilingActive, 0, 0,
+            GetNewMethodID)));
 
     TheJIT->RegisterJITEventListener(Listener.get());