LLVM API Documentation

IntelJITEventListener.cpp
Go to the documentation of this file.
00001 //===-- IntelJITEventListener.cpp - Tell Intel profiler about JITed code --===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file defines a JITEventListener object to tell Intel(R) VTune(TM)
00011 // Amplifier XE 2011 about JITted functions.
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #include "llvm/Config/config.h"
00016 #include "llvm/ExecutionEngine/JITEventListener.h"
00017 
00018 #include "llvm/IR/DebugInfo.h"
00019 #include "llvm/IR/Function.h"
00020 #include "llvm/IR/Metadata.h"
00021 #include "llvm/ADT/DenseMap.h"
00022 #include "llvm/CodeGen/MachineFunction.h"
00023 #include "llvm/DebugInfo/DIContext.h"
00024 #include "llvm/ExecutionEngine/ObjectImage.h"
00025 #include "llvm/Object/ObjectFile.h"
00026 #include "llvm/Support/Debug.h"
00027 #include "llvm/Support/raw_ostream.h"
00028 #include "llvm/Support/Errno.h"
00029 #include "llvm/IR/ValueHandle.h"
00030 #include "EventListenerCommon.h"
00031 #include "IntelJITEventsWrapper.h"
00032 
00033 using namespace llvm;
00034 using namespace llvm::jitprofiling;
00035 
00036 #define DEBUG_TYPE "amplifier-jit-event-listener"
00037 
00038 namespace {
00039 
00040 class IntelJITEventListener : public JITEventListener {
00041   typedef DenseMap<void*, unsigned int> MethodIDMap;
00042 
00043   std::unique_ptr<IntelJITEventsWrapper> Wrapper;
00044   MethodIDMap MethodIDs;
00045   FilenameCache Filenames;
00046 
00047   typedef SmallVector<const void *, 64> MethodAddressVector;
00048   typedef DenseMap<const void *, MethodAddressVector>  ObjectMap;
00049 
00050   ObjectMap  LoadedObjectMap;
00051 
00052 public:
00053   IntelJITEventListener(IntelJITEventsWrapper* libraryWrapper) {
00054       Wrapper.reset(libraryWrapper);
00055   }
00056 
00057   ~IntelJITEventListener() {
00058   }
00059 
00060   virtual void NotifyFunctionEmitted(const Function &F,
00061                                      void *FnStart, size_t FnSize,
00062                                      const EmittedFunctionDetails &Details);
00063 
00064   virtual void NotifyFreeingMachineCode(void *OldPtr);
00065 
00066   virtual void NotifyObjectEmitted(const ObjectImage &Obj);
00067 
00068   virtual void NotifyFreeingObject(const ObjectImage &Obj);
00069 };
00070 
00071 static LineNumberInfo LineStartToIntelJITFormat(
00072     uintptr_t StartAddress,
00073     uintptr_t Address,
00074     DebugLoc Loc) {
00075   LineNumberInfo Result;
00076 
00077   Result.Offset = Address - StartAddress;
00078   Result.LineNumber = Loc.getLine();
00079 
00080   return Result;
00081 }
00082 
00083 static LineNumberInfo DILineInfoToIntelJITFormat(uintptr_t StartAddress,
00084                                                  uintptr_t Address,
00085                                                  DILineInfo Line) {
00086   LineNumberInfo Result;
00087 
00088   Result.Offset = Address - StartAddress;
00089   Result.LineNumber = Line.Line;
00090 
00091   return Result;
00092 }
00093 
00094 static iJIT_Method_Load FunctionDescToIntelJITFormat(
00095     IntelJITEventsWrapper& Wrapper,
00096     const char* FnName,
00097     uintptr_t FnStart,
00098     size_t FnSize) {
00099   iJIT_Method_Load Result;
00100   memset(&Result, 0, sizeof(iJIT_Method_Load));
00101 
00102   Result.method_id = Wrapper.iJIT_GetNewMethodID();
00103   Result.method_name = const_cast<char*>(FnName);
00104   Result.method_load_address = reinterpret_cast<void*>(FnStart);
00105   Result.method_size = FnSize;
00106 
00107   Result.class_id = 0;
00108   Result.class_file_name = NULL;
00109   Result.user_data = NULL;
00110   Result.user_data_size = 0;
00111   Result.env = iJDE_JittingAPI;
00112 
00113   return Result;
00114 }
00115 
00116 // Adds the just-emitted function to the symbol table.
00117 void IntelJITEventListener::NotifyFunctionEmitted(
00118     const Function &F, void *FnStart, size_t FnSize,
00119     const EmittedFunctionDetails &Details) {
00120   iJIT_Method_Load FunctionMessage = FunctionDescToIntelJITFormat(*Wrapper,
00121                                       F.getName().data(),
00122                                       reinterpret_cast<uint64_t>(FnStart),
00123                                       FnSize);
00124 
00125   std::vector<LineNumberInfo> LineInfo;
00126 
00127   if (!Details.LineStarts.empty()) {
00128     // Now convert the line number information from the address/DebugLoc
00129     // format in Details to the offset/lineno in Intel JIT API format.
00130 
00131     LineInfo.reserve(Details.LineStarts.size() + 1);
00132 
00133     DebugLoc FirstLoc = Details.LineStarts[0].Loc;
00134     assert(!FirstLoc.isUnknown()
00135            && "LineStarts should not contain unknown DebugLocs");
00136 
00137     MDNode *FirstLocScope = FirstLoc.getScope(F.getContext());
00138     DISubprogram FunctionDI = getDISubprogram(FirstLocScope);
00139     if (FunctionDI.Verify()) {
00140       FunctionMessage.source_file_name = const_cast<char*>(
00141                                           Filenames.getFullPath(FirstLocScope));
00142 
00143       LineNumberInfo FirstLine;
00144       FirstLine.Offset = 0;
00145       FirstLine.LineNumber = FunctionDI.getLineNumber();
00146       LineInfo.push_back(FirstLine);
00147     }
00148 
00149     for (std::vector<EmittedFunctionDetails::LineStart>::const_iterator I =
00150           Details.LineStarts.begin(), E = Details.LineStarts.end();
00151           I != E; ++I) {
00152       // This implementation ignores the DebugLoc filename because the Intel
00153       // JIT API does not support multiple source files associated with a single
00154       // JIT function
00155       LineInfo.push_back(LineStartToIntelJITFormat(
00156                           reinterpret_cast<uintptr_t>(FnStart),
00157                           I->Address,
00158                           I->Loc));
00159 
00160       // If we have no file name yet for the function, use the filename from
00161       // the first instruction that has one
00162       if (FunctionMessage.source_file_name == 0) {
00163         MDNode *scope = I->Loc.getScope(
00164           Details.MF->getFunction()->getContext());
00165         FunctionMessage.source_file_name = const_cast<char*>(
00166                                                   Filenames.getFullPath(scope));
00167       }
00168     }
00169 
00170     FunctionMessage.line_number_size = LineInfo.size();
00171     FunctionMessage.line_number_table = &*LineInfo.begin();
00172   } else {
00173     FunctionMessage.line_number_size = 0;
00174     FunctionMessage.line_number_table = 0;
00175   }
00176 
00177   Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED,
00178                             &FunctionMessage);
00179   MethodIDs[FnStart] = FunctionMessage.method_id;
00180 }
00181 
00182 void IntelJITEventListener::NotifyFreeingMachineCode(void *FnStart) {
00183   MethodIDMap::iterator I = MethodIDs.find(FnStart);
00184   if (I != MethodIDs.end()) {
00185     Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START, &I->second);
00186     MethodIDs.erase(I);
00187   }
00188 }
00189 
00190 void IntelJITEventListener::NotifyObjectEmitted(const ObjectImage &Obj) {
00191   // Get the address of the object image for use as a unique identifier
00192   const void* ObjData = Obj.getData().data();
00193   DIContext* Context = DIContext::getDWARFContext(*Obj.getObjectFile());
00194   MethodAddressVector Functions;
00195 
00196   // Use symbol info to iterate functions in the object.
00197   for (object::symbol_iterator I = Obj.begin_symbols(),
00198                                E = Obj.end_symbols();
00199                         I != E;
00200                         ++I) {
00201     std::vector<LineNumberInfo> LineInfo;
00202     std::string SourceFileName;
00203 
00204     object::SymbolRef::Type SymType;
00205     if (I->getType(SymType)) continue;
00206     if (SymType == object::SymbolRef::ST_Function) {
00207       StringRef  Name;
00208       uint64_t   Addr;
00209       uint64_t   Size;
00210       if (I->getName(Name)) continue;
00211       if (I->getAddress(Addr)) continue;
00212       if (I->getSize(Size)) continue;
00213 
00214       // Record this address in a local vector
00215       Functions.push_back((void*)Addr);
00216 
00217       // Build the function loaded notification message
00218       iJIT_Method_Load FunctionMessage = FunctionDescToIntelJITFormat(*Wrapper,
00219                                            Name.data(),
00220                                            Addr,
00221                                            Size);
00222       if (Context) {
00223         DILineInfoTable  Lines = Context->getLineInfoForAddressRange(Addr, Size);
00224         DILineInfoTable::iterator  Begin = Lines.begin();
00225         DILineInfoTable::iterator  End = Lines.end();
00226         for (DILineInfoTable::iterator It = Begin; It != End; ++It) {
00227           LineInfo.push_back(DILineInfoToIntelJITFormat((uintptr_t)Addr,
00228                                                         It->first,
00229                                                         It->second));
00230         }
00231         if (LineInfo.size() == 0) {
00232           FunctionMessage.source_file_name = 0;
00233           FunctionMessage.line_number_size = 0;
00234           FunctionMessage.line_number_table = 0;
00235         } else {
00236           SourceFileName = Lines.front().second.FileName;
00237           FunctionMessage.source_file_name = const_cast<char *>(SourceFileName.c_str());
00238           FunctionMessage.line_number_size = LineInfo.size();
00239           FunctionMessage.line_number_table = &*LineInfo.begin();
00240         }
00241       } else {
00242         FunctionMessage.source_file_name = 0;
00243         FunctionMessage.line_number_size = 0;
00244         FunctionMessage.line_number_table = 0;
00245       }
00246 
00247       Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED,
00248                                 &FunctionMessage);
00249       MethodIDs[(void*)Addr] = FunctionMessage.method_id;
00250     }
00251   }
00252 
00253   // To support object unload notification, we need to keep a list of
00254   // registered function addresses for each loaded object.  We will
00255   // use the MethodIDs map to get the registered ID for each function.
00256   LoadedObjectMap[ObjData] = Functions;
00257 }
00258 
00259 void IntelJITEventListener::NotifyFreeingObject(const ObjectImage &Obj) {
00260   // Get the address of the object image for use as a unique identifier
00261   const void* ObjData = Obj.getData().data();
00262 
00263   // Get the object's function list from LoadedObjectMap
00264   ObjectMap::iterator OI = LoadedObjectMap.find(ObjData);
00265   if (OI == LoadedObjectMap.end())
00266     return;
00267   MethodAddressVector& Functions = OI->second;
00268 
00269   // Walk the function list, unregistering each function
00270   for (MethodAddressVector::iterator FI = Functions.begin(),
00271                                      FE = Functions.end();
00272        FI != FE;
00273        ++FI) {
00274     void* FnStart = const_cast<void*>(*FI);
00275     MethodIDMap::iterator MI = MethodIDs.find(FnStart);
00276     if (MI != MethodIDs.end()) {
00277       Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START,
00278                                 &MI->second);
00279       MethodIDs.erase(MI);
00280     }
00281   }
00282 
00283   // Erase the object from LoadedObjectMap
00284   LoadedObjectMap.erase(OI);
00285 }
00286 
00287 }  // anonymous namespace.
00288 
00289 namespace llvm {
00290 JITEventListener *JITEventListener::createIntelJITEventListener() {
00291   return new IntelJITEventListener(new IntelJITEventsWrapper);
00292 }
00293 
00294 // for testing
00295 JITEventListener *JITEventListener::createIntelJITEventListener(
00296                                       IntelJITEventsWrapper* TestImpl) {
00297   return new IntelJITEventListener(TestImpl);
00298 }
00299 
00300 } // namespace llvm
00301