Home | History | Annotate | Line # | Download | only in IntelJITEvents
      1 //===-- IntelJITEventListener.cpp - Tell Intel profiler about JITed code --===//
      2 //
      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
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 // This file defines a JITEventListener object to tell Intel(R) VTune(TM)
     10 // Amplifier XE 2011 about JITted functions.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     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"
     32 
     33 using namespace llvm;
     34 using namespace llvm::object;
     35 
     36 #define DEBUG_TYPE "amplifier-jit-event-listener"
     37 
     38 namespace {
     39 
     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;
     46 
     47 public:
     48   IntelIttnotifyInfo(IntelJITEventsWrapper &Wrapper)
     49       : ModuleObject(NULL), WrapperRef(Wrapper){};
     50   ~IntelIttnotifyInfo() { delete ModuleObject; };
     51 
     52   void setModuleName(const char *Name) { ModuleName = std::string(Name); }
     53 
     54   const char *getModuleName() { return ModuleName.c_str(); }
     55 
     56   void setModuleObject(__itt_module_object *ModuleObj) {
     57     ModuleObject = ModuleObj;
     58   }
     59 
     60   __itt_module_object *getModuleObject() { return ModuleObject; }
     61 
     62   __itt_section_info *getSectionInfoVectorBegin() {
     63     if (SectionInfoVector.size())
     64       return &SectionInfoVector[0];
     65     return NULL;
     66   }
     67 
     68   void reportSection(llvm::IttEventType EventType, const char *SectionName,
     69                      unsigned int SectionSize) {
     70     WrapperRef.iJitIttNotifyInfo(EventType, SectionName, SectionSize);
     71   }
     72 
     73   int fillSectionInformation(const ObjectFile &Obj,
     74                              const RuntimeDyld::LoadedObjectInfo &L) {
     75 
     76     int SectionCounter = 0;
     77 
     78     for (auto &Section : Obj.sections()) {
     79       uint64_t SectionLoadAddr = L.getSectionLoadAddress(Section);
     80       if (SectionLoadAddr) {
     81         object::ELFSectionRef ElfSection(Section);
     82 
     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();
     88 
     89         StringRef SectionName("");
     90         auto SectionNameOrError = ElfSection.getName();
     91         if (SectionNameOrError)
     92           SectionName = *SectionNameOrError;
     93 
     94         SectionNamesVector.push_back(SectionName.str());
     95         SectionInfo.size = ElfSection.getSize();
     96         reportSection(llvm::LoadBinarySection, SectionName.str().c_str(),
     97                       SectionInfo.size);
     98 
     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;
    105         }
    106         SectionInfoVector.push_back(SectionInfo);
    107         ++SectionCounter;
    108       }
    109     }
    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();
    115     }
    116     return SectionCounter;
    117   }
    118 };
    119 
    120 class IntelJITEventListener : public JITEventListener {
    121   typedef DenseMap<void*, unsigned int> MethodIDMap;
    122 
    123   std::unique_ptr<IntelJITEventsWrapper> Wrapper;
    124   MethodIDMap MethodIDs;
    125 
    126   typedef SmallVector<const void *, 64> MethodAddressVector;
    127   typedef DenseMap<const void *, MethodAddressVector>  ObjectMap;
    128 
    129   ObjectMap  LoadedObjectMap;
    130   std::map<ObjectKey, OwningBinary<ObjectFile>> DebugObjects;
    131 
    132   std::map<ObjectKey, std::unique_ptr<IntelIttnotifyInfo>> KeyToIttnotify;
    133 
    134 public:
    135   IntelJITEventListener(IntelJITEventsWrapper* libraryWrapper) {
    136       Wrapper.reset(libraryWrapper);
    137   }
    138 
    139   ~IntelJITEventListener() {
    140   }
    141 
    142   void notifyObjectLoaded(ObjectKey Key, const ObjectFile &Obj,
    143                           const RuntimeDyld::LoadedObjectInfo &L) override;
    144 
    145   void notifyFreeingObject(ObjectKey Key) override;
    146 };
    147 
    148 static LineNumberInfo DILineInfoToIntelJITFormat(uintptr_t StartAddress,
    149                                                  uintptr_t Address,
    150                                                  DILineInfo Line) {
    151   LineNumberInfo Result;
    152 
    153   Result.Offset = Address - StartAddress;
    154   Result.LineNumber = Line.Line;
    155 
    156   return Result;
    157 }
    158 
    159 static iJIT_Method_Load FunctionDescToIntelJITFormat(
    160     IntelJITEventsWrapper& Wrapper,
    161     const char* FnName,
    162     uintptr_t FnStart,
    163     size_t FnSize) {
    164   iJIT_Method_Load Result;
    165   memset(&Result, 0, sizeof(iJIT_Method_Load));
    166 
    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;
    171 
    172   Result.class_id = 0;
    173   Result.class_file_name = NULL;
    174   Result.user_data = NULL;
    175   Result.user_data_size = 0;
    176   Result.env = iJDE_JittingAPI;
    177 
    178   return Result;
    179 }
    180 
    181 int getBackwardCompatibilityMode() {
    182 
    183   char *BackwardCompatibilityEnv = getenv("INTEL_JIT_BACKWARD_COMPATIBILITY");
    184   int BackwardCompatibilityMode = 0;
    185   if (BackwardCompatibilityEnv) {
    186     StringRef(BackwardCompatibilityEnv)
    187         .getAsInteger(10, BackwardCompatibilityMode);
    188   }
    189   return BackwardCompatibilityMode;
    190 }
    191 
    192 void IntelJITEventListener::notifyObjectLoaded(
    193     ObjectKey Key, const ObjectFile &Obj,
    194     const RuntimeDyld::LoadedObjectInfo &L) {
    195 
    196   int BackwardCompatibilityMode = getBackwardCompatibilityMode();
    197   if (BackwardCompatibilityMode == 0) {
    198     if (Obj.isELF()) {
    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))
    204               .str()
    205               .c_str());
    206 
    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);
    223 
    224       __itt_module_load_with_sections(ModuleObject);
    225 
    226       KeyToIttnotify[Key] = std::move(ModuleIttnotify);
    227     }
    228   } else if (BackwardCompatibilityMode == 1) {
    229 
    230     OwningBinary<ObjectFile> DebugObjOwner = L.getObjectForDebug(Obj);
    231     const ObjectFile *DebugObj = DebugObjOwner.getBinary();
    232     if (!DebugObj)
    233       return;
    234 
    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;
    239 
    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;
    246 
    247       Expected<SymbolRef::Type> SymTypeOrErr = Sym.getType();
    248       if (!SymTypeOrErr) {
    249         // TODO: Actually report errors helpfully.
    250         consumeError(SymTypeOrErr.takeError());
    251         continue;
    252       }
    253       SymbolRef::Type SymType = *SymTypeOrErr;
    254       if (SymType != SymbolRef::ST_Function)
    255         continue;
    256 
    257       Expected<StringRef> Name = Sym.getName();
    258       if (!Name) {
    259         // TODO: Actually report errors helpfully.
    260         consumeError(Name.takeError());
    261         continue;
    262       }
    263 
    264       Expected<uint64_t> AddrOrErr = Sym.getAddress();
    265       if (!AddrOrErr) {
    266         // TODO: Actually report errors helpfully.
    267         consumeError(AddrOrErr.takeError());
    268         continue;
    269       }
    270       uint64_t Addr = *AddrOrErr;
    271       uint64_t Size = P.second;
    272 
    273       auto SecOrErr = Sym.getSection();
    274       if (!SecOrErr) {
    275         // TODO: Actually report errors helpfully.
    276         consumeError(SecOrErr.takeError());
    277         continue;
    278       }
    279       object::section_iterator Sec = *SecOrErr;
    280       if (Sec == Obj.section_end())
    281         continue;
    282       uint64_t Index = Sec->getIndex();
    283 
    284       // Record this address in a local vector
    285       Functions.push_back((void *)Addr);
    286 
    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) {
    295         LineInfo.push_back(
    296             DILineInfoToIntelJITFormat((uintptr_t)Addr, It->first, It->second));
    297       }
    298       if (LineInfo.size() == 0) {
    299         FunctionMessage.source_file_name = 0;
    300         FunctionMessage.line_number_size = 0;
    301         FunctionMessage.line_number_table = 0;
    302       } else {
    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.
    308 
    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;
    314 
    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();
    320       }
    321 
    322       Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED,
    323                                 &FunctionMessage);
    324       MethodIDs[(void *)Addr] = FunctionMessage.method_id;
    325     }
    326 
    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);
    332   }
    333 }
    334 
    335 void IntelJITEventListener::notifyFreeingObject(ObjectKey Key) {
    336 
    337   int BackwardCompatibilityMode = getBackwardCompatibilityMode();
    338   if (BackwardCompatibilityMode == 0) {
    339     if (KeyToIttnotify.find(Key) == KeyToIttnotify.end())
    340       return;
    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,
    349     // bail out.
    350     if (DebugObjects.find(Key) == DebugObjects.end())
    351       return;
    352 
    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();
    356 
    357     // Get the object's function list from LoadedObjectMap
    358     ObjectMap::iterator OI = LoadedObjectMap.find(ObjData);
    359     if (OI == LoadedObjectMap.end())
    360       return;
    361     MethodAddressVector &Functions = OI->second;
    362 
    363     // Walk the function list, unregistering each function
    364     for (MethodAddressVector::iterator FI = Functions.begin(),
    365                                        FE = Functions.end();
    366          FI != FE; ++FI) {
    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,
    371                                   &MI->second);
    372         MethodIDs.erase(MI);
    373       }
    374     }
    375 
    376     // Erase the object from LoadedObjectMap
    377     LoadedObjectMap.erase(OI);
    378     DebugObjects.erase(Key);
    379   }
    380 }
    381 
    382 }  // anonymous namespace.
    383 
    384 namespace llvm {
    385 JITEventListener *JITEventListener::createIntelJITEventListener() {
    386   return new IntelJITEventListener(new IntelJITEventsWrapper);
    387 }
    388 
    389 // for testing
    390 JITEventListener *JITEventListener::createIntelJITEventListener(
    391                                       IntelJITEventsWrapper* TestImpl) {
    392   return new IntelJITEventListener(TestImpl);
    393 }
    394 
    395 } // namespace llvm
    396 
    397 LLVMJITEventListenerRef LLVMCreateIntelJITEventListener(void)
    398 {
    399   return wrap(JITEventListener::createIntelJITEventListener());
    400 }
    401