Home | History | Annotate | Download | only in IntelJITEvents
      1 //===-- IntelJITEventListener.cpp - Tell Intel profiler about JITed code --===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file defines a JITEventListener object to tell Intel(R) VTune(TM)
     11 // Amplifier XE 2011 about JITted functions.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #include "llvm/Config/config.h"
     16 #include "llvm/ExecutionEngine/JITEventListener.h"
     17 
     18 #define DEBUG_TYPE "amplifier-jit-event-listener"
     19 #include "llvm/DebugInfo.h"
     20 #include "llvm/IR/Function.h"
     21 #include "llvm/IR/Metadata.h"
     22 #include "llvm/ADT/DenseMap.h"
     23 #include "llvm/ADT/OwningPtr.h"
     24 #include "llvm/CodeGen/MachineFunction.h"
     25 #include "llvm/DebugInfo/DIContext.h"
     26 #include "llvm/ExecutionEngine/ObjectImage.h"
     27 #include "llvm/Object/ObjectFile.h"
     28 #include "llvm/Support/Debug.h"
     29 #include "llvm/Support/raw_ostream.h"
     30 #include "llvm/Support/Errno.h"
     31 #include "llvm/Support/ValueHandle.h"
     32 #include "EventListenerCommon.h"
     33 #include "IntelJITEventsWrapper.h"
     34 
     35 using namespace llvm;
     36 using namespace llvm::jitprofiling;
     37 
     38 namespace {
     39 
     40 class IntelJITEventListener : public JITEventListener {
     41   typedef DenseMap<void*, unsigned int> MethodIDMap;
     42 
     43   OwningPtr<IntelJITEventsWrapper> Wrapper;
     44   MethodIDMap MethodIDs;
     45   FilenameCache Filenames;
     46 
     47   typedef SmallVector<const void *, 64> MethodAddressVector;
     48   typedef DenseMap<const void *, MethodAddressVector>  ObjectMap;
     49 
     50   ObjectMap  LoadedObjectMap;
     51 
     52 public:
     53   IntelJITEventListener(IntelJITEventsWrapper* libraryWrapper) {
     54       Wrapper.reset(libraryWrapper);
     55   }
     56 
     57   ~IntelJITEventListener() {
     58   }
     59 
     60   virtual void NotifyFunctionEmitted(const Function &F,
     61                                      void *FnStart, size_t FnSize,
     62                                      const EmittedFunctionDetails &Details);
     63 
     64   virtual void NotifyFreeingMachineCode(void *OldPtr);
     65 
     66   virtual void NotifyObjectEmitted(const ObjectImage &Obj);
     67 
     68   virtual void NotifyFreeingObject(const ObjectImage &Obj);
     69 };
     70 
     71 static LineNumberInfo LineStartToIntelJITFormat(
     72     uintptr_t StartAddress,
     73     uintptr_t Address,
     74     DebugLoc Loc) {
     75   LineNumberInfo Result;
     76 
     77   Result.Offset = Address - StartAddress;
     78   Result.LineNumber = Loc.getLine();
     79 
     80   return Result;
     81 }
     82 
     83 static LineNumberInfo DILineInfoToIntelJITFormat(uintptr_t StartAddress,
     84                                                  uintptr_t Address,
     85                                                  DILineInfo Line) {
     86   LineNumberInfo Result;
     87 
     88   Result.Offset = Address - StartAddress;
     89   Result.LineNumber = Line.getLine();
     90 
     91   return Result;
     92 }
     93 
     94 static iJIT_Method_Load FunctionDescToIntelJITFormat(
     95     IntelJITEventsWrapper& Wrapper,
     96     const char* FnName,
     97     uintptr_t FnStart,
     98     size_t FnSize) {
     99   iJIT_Method_Load Result;
    100   memset(&Result, 0, sizeof(iJIT_Method_Load));
    101 
    102   Result.method_id = Wrapper.iJIT_GetNewMethodID();
    103   Result.method_name = const_cast<char*>(FnName);
    104   Result.method_load_address = reinterpret_cast<void*>(FnStart);
    105   Result.method_size = FnSize;
    106 
    107   Result.class_id = 0;
    108   Result.class_file_name = NULL;
    109   Result.user_data = NULL;
    110   Result.user_data_size = 0;
    111   Result.env = iJDE_JittingAPI;
    112 
    113   return Result;
    114 }
    115 
    116 // Adds the just-emitted function to the symbol table.
    117 void IntelJITEventListener::NotifyFunctionEmitted(
    118     const Function &F, void *FnStart, size_t FnSize,
    119     const EmittedFunctionDetails &Details) {
    120   iJIT_Method_Load FunctionMessage = FunctionDescToIntelJITFormat(*Wrapper,
    121                                       F.getName().data(),
    122                                       reinterpret_cast<uint64_t>(FnStart),
    123                                       FnSize);
    124 
    125   std::vector<LineNumberInfo> LineInfo;
    126 
    127   if (!Details.LineStarts.empty()) {
    128     // Now convert the line number information from the address/DebugLoc
    129     // format in Details to the offset/lineno in Intel JIT API format.
    130 
    131     LineInfo.reserve(Details.LineStarts.size() + 1);
    132 
    133     DebugLoc FirstLoc = Details.LineStarts[0].Loc;
    134     assert(!FirstLoc.isUnknown()
    135            && "LineStarts should not contain unknown DebugLocs");
    136 
    137     MDNode *FirstLocScope = FirstLoc.getScope(F.getContext());
    138     DISubprogram FunctionDI = getDISubprogram(FirstLocScope);
    139     if (FunctionDI.Verify()) {
    140       FunctionMessage.source_file_name = const_cast<char*>(
    141                                           Filenames.getFullPath(FirstLocScope));
    142 
    143       LineNumberInfo FirstLine;
    144       FirstLine.Offset = 0;
    145       FirstLine.LineNumber = FunctionDI.getLineNumber();
    146       LineInfo.push_back(FirstLine);
    147     }
    148 
    149     for (std::vector<EmittedFunctionDetails::LineStart>::const_iterator I =
    150           Details.LineStarts.begin(), E = Details.LineStarts.end();
    151           I != E; ++I) {
    152       // This implementation ignores the DebugLoc filename because the Intel
    153       // JIT API does not support multiple source files associated with a single
    154       // JIT function
    155       LineInfo.push_back(LineStartToIntelJITFormat(
    156                           reinterpret_cast<uintptr_t>(FnStart),
    157                           I->Address,
    158                           I->Loc));
    159 
    160       // If we have no file name yet for the function, use the filename from
    161       // the first instruction that has one
    162       if (FunctionMessage.source_file_name == 0) {
    163         MDNode *scope = I->Loc.getScope(
    164           Details.MF->getFunction()->getContext());
    165         FunctionMessage.source_file_name = const_cast<char*>(
    166                                                   Filenames.getFullPath(scope));
    167       }
    168     }
    169 
    170     FunctionMessage.line_number_size = LineInfo.size();
    171     FunctionMessage.line_number_table = &*LineInfo.begin();
    172   } else {
    173     FunctionMessage.line_number_size = 0;
    174     FunctionMessage.line_number_table = 0;
    175   }
    176 
    177   Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED,
    178                             &FunctionMessage);
    179   MethodIDs[FnStart] = FunctionMessage.method_id;
    180 }
    181 
    182 void IntelJITEventListener::NotifyFreeingMachineCode(void *FnStart) {
    183   MethodIDMap::iterator I = MethodIDs.find(FnStart);
    184   if (I != MethodIDs.end()) {
    185     Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START, &I->second);
    186     MethodIDs.erase(I);
    187   }
    188 }
    189 
    190 void IntelJITEventListener::NotifyObjectEmitted(const ObjectImage &Obj) {
    191   // Get the address of the object image for use as a unique identifier
    192   const void* ObjData = Obj.getData().data();
    193   DIContext* Context = DIContext::getDWARFContext(Obj.getObjectFile());
    194   MethodAddressVector Functions;
    195 
    196   // Use symbol info to iterate functions in the object.
    197   error_code ec;
    198   for (object::symbol_iterator I = Obj.begin_symbols(),
    199                                E = Obj.end_symbols();
    200                         I != E && !ec;
    201                         I.increment(ec)) {
    202     std::vector<LineNumberInfo> LineInfo;
    203     std::string SourceFileName;
    204 
    205     object::SymbolRef::Type SymType;
    206     if (I->getType(SymType)) continue;
    207     if (SymType == object::SymbolRef::ST_Function) {
    208       StringRef  Name;
    209       uint64_t   Addr;
    210       uint64_t   Size;
    211       if (I->getName(Name)) continue;
    212       if (I->getAddress(Addr)) continue;
    213       if (I->getSize(Size)) continue;
    214 
    215       // Record this address in a local vector
    216       Functions.push_back((void*)Addr);
    217 
    218       // Build the function loaded notification message
    219       iJIT_Method_Load FunctionMessage = FunctionDescToIntelJITFormat(*Wrapper,
    220                                            Name.data(),
    221                                            Addr,
    222                                            Size);
    223       if (Context) {
    224         DILineInfoTable  Lines = Context->getLineInfoForAddressRange(Addr, Size);
    225         DILineInfoTable::iterator  Begin = Lines.begin();
    226         DILineInfoTable::iterator  End = Lines.end();
    227         for (DILineInfoTable::iterator It = Begin; It != End; ++It) {
    228           LineInfo.push_back(DILineInfoToIntelJITFormat((uintptr_t)Addr,
    229                                                         It->first,
    230                                                         It->second));
    231         }
    232         if (LineInfo.size() == 0) {
    233           FunctionMessage.source_file_name = 0;
    234           FunctionMessage.line_number_size = 0;
    235           FunctionMessage.line_number_table = 0;
    236         } else {
    237           SourceFileName = Lines.front().second.getFileName();
    238           FunctionMessage.source_file_name = (char *)SourceFileName.c_str();
    239           FunctionMessage.line_number_size = LineInfo.size();
    240           FunctionMessage.line_number_table = &*LineInfo.begin();
    241         }
    242       } else {
    243         FunctionMessage.source_file_name = 0;
    244         FunctionMessage.line_number_size = 0;
    245         FunctionMessage.line_number_table = 0;
    246       }
    247 
    248       Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED,
    249                                 &FunctionMessage);
    250       MethodIDs[(void*)Addr] = FunctionMessage.method_id;
    251     }
    252   }
    253 
    254   // To support object unload notification, we need to keep a list of
    255   // registered function addresses for each loaded object.  We will
    256   // use the MethodIDs map to get the registered ID for each function.
    257   LoadedObjectMap[ObjData] = Functions;
    258 }
    259 
    260 void IntelJITEventListener::NotifyFreeingObject(const ObjectImage &Obj) {
    261   // Get the address of the object image for use as a unique identifier
    262   const void* ObjData = Obj.getData().data();
    263 
    264   // Get the object's function list from LoadedObjectMap
    265   ObjectMap::iterator OI = LoadedObjectMap.find(ObjData);
    266   if (OI == LoadedObjectMap.end())
    267     return;
    268   MethodAddressVector& Functions = OI->second;
    269 
    270   // Walk the function list, unregistering each function
    271   for (MethodAddressVector::iterator FI = Functions.begin(),
    272                                      FE = Functions.end();
    273        FI != FE;
    274        ++FI) {
    275     void* FnStart = const_cast<void*>(*FI);
    276     MethodIDMap::iterator MI = MethodIDs.find(FnStart);
    277     if (MI != MethodIDs.end()) {
    278       Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START,
    279                                 &MI->second);
    280       MethodIDs.erase(MI);
    281     }
    282   }
    283 
    284   // Erase the object from LoadedObjectMap
    285   LoadedObjectMap.erase(OI);
    286 }
    287 
    288 }  // anonymous namespace.
    289 
    290 namespace llvm {
    291 JITEventListener *JITEventListener::createIntelJITEventListener() {
    292   return new IntelJITEventListener(new IntelJITEventsWrapper);
    293 }
    294 
    295 // for testing
    296 JITEventListener *JITEventListener::createIntelJITEventListener(
    297                                       IntelJITEventsWrapper* TestImpl) {
    298   return new IntelJITEventListener(TestImpl);
    299 }
    300 
    301 } // namespace llvm
    302 
    303