//===----------------------------------------------------------------------===//
#include "IntelJITEventsWrapper.h"
+#include "ittnotify.h"
#include "llvm-c/ExecutionEngine.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/CodeGen/MachineFunction.h"
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;
ObjectMap LoadedObjectMap;
std::map<ObjectKey, OwningBinary<ObjectFile>> DebugObjects;
+ std::map<ObjectKey, std::unique_ptr<IntelIttnotifyInfo>> KeyToIttnotify;
+
public:
IntelJITEventListener(IntelJITEventsWrapper* libraryWrapper) {
Wrapper.reset(libraryWrapper);
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.
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);
typedef unsigned int (*GetNewMethodIDPtr)(void);
NotifyEventPtr NotifyEventFunc;
+ IttnotifyInfoPtr IttnotifyInfoFunc;
RegisterCallbackExPtr RegisterCallbackExFunc;
IsProfilingActivePtr IsProfilingActiveFunc;
GetNewMethodIDPtr GetNewMethodIDFunc;
}
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.
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) {