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 "IntelJITEventsWrapper.h" 17 #include "llvm/ADT/DenseMap.h" 18 #include "llvm/CodeGen/MachineFunction.h" 19 #include "llvm/DebugInfo/DIContext.h" 20 #include "llvm/DebugInfo/DWARF/DWARFContext.h" 21 #include "llvm/ExecutionEngine/JITEventListener.h" 22 #include "llvm/IR/DebugInfo.h" 23 #include "llvm/IR/Function.h" 24 #include "llvm/IR/Metadata.h" 25 #include "llvm/IR/ValueHandle.h" 26 #include "llvm/Object/ObjectFile.h" 27 #include "llvm/Object/SymbolSize.h" 28 #include "llvm/Support/Debug.h" 29 #include "llvm/Support/Errno.h" 30 #include "llvm/Support/raw_ostream.h" 31 32 using namespace llvm; 33 using namespace llvm::object; 34 35 #define DEBUG_TYPE "amplifier-jit-event-listener" 36 37 namespace { 38 39 class IntelJITEventListener : public JITEventListener { 40 typedef DenseMap<void*, unsigned int> MethodIDMap; 41 42 std::unique_ptr<IntelJITEventsWrapper> Wrapper; 43 MethodIDMap MethodIDs; 44 45 typedef SmallVector<const void *, 64> MethodAddressVector; 46 typedef DenseMap<const void *, MethodAddressVector> ObjectMap; 47 48 ObjectMap LoadedObjectMap; 49 std::map<const char*, OwningBinary<ObjectFile>> DebugObjects; 50 51 public: 52 IntelJITEventListener(IntelJITEventsWrapper* libraryWrapper) { 53 Wrapper.reset(libraryWrapper); 54 } 55 56 ~IntelJITEventListener() { 57 } 58 59 void NotifyObjectEmitted(const ObjectFile &Obj, 60 const RuntimeDyld::LoadedObjectInfo &L) override; 61 62 void NotifyFreeingObject(const ObjectFile &Obj) override; 63 }; 64 65 static LineNumberInfo DILineInfoToIntelJITFormat(uintptr_t StartAddress, 66 uintptr_t Address, 67 DILineInfo Line) { 68 LineNumberInfo Result; 69 70 Result.Offset = Address - StartAddress; 71 Result.LineNumber = Line.Line; 72 73 return Result; 74 } 75 76 static iJIT_Method_Load FunctionDescToIntelJITFormat( 77 IntelJITEventsWrapper& Wrapper, 78 const char* FnName, 79 uintptr_t FnStart, 80 size_t FnSize) { 81 iJIT_Method_Load Result; 82 memset(&Result, 0, sizeof(iJIT_Method_Load)); 83 84 Result.method_id = Wrapper.iJIT_GetNewMethodID(); 85 Result.method_name = const_cast<char*>(FnName); 86 Result.method_load_address = reinterpret_cast<void*>(FnStart); 87 Result.method_size = FnSize; 88 89 Result.class_id = 0; 90 Result.class_file_name = NULL; 91 Result.user_data = NULL; 92 Result.user_data_size = 0; 93 Result.env = iJDE_JittingAPI; 94 95 return Result; 96 } 97 98 void IntelJITEventListener::NotifyObjectEmitted( 99 const ObjectFile &Obj, 100 const RuntimeDyld::LoadedObjectInfo &L) { 101 102 OwningBinary<ObjectFile> DebugObjOwner = L.getObjectForDebug(Obj); 103 const ObjectFile &DebugObj = *DebugObjOwner.getBinary(); 104 105 // Get the address of the object image for use as a unique identifier 106 const void* ObjData = DebugObj.getData().data(); 107 DIContext* Context = new DWARFContextInMemory(DebugObj); 108 MethodAddressVector Functions; 109 110 // Use symbol info to iterate functions in the object. 111 for (const std::pair<SymbolRef, uint64_t> &P : computeSymbolSizes(DebugObj)) { 112 SymbolRef Sym = P.first; 113 std::vector<LineNumberInfo> LineInfo; 114 std::string SourceFileName; 115 116 if (Sym.getType() != SymbolRef::ST_Function) 117 continue; 118 119 ErrorOr<StringRef> Name = Sym.getName(); 120 if (!Name) 121 continue; 122 123 ErrorOr<uint64_t> AddrOrErr = Sym.getAddress(); 124 if (AddrOrErr.getError()) 125 continue; 126 uint64_t Addr = *AddrOrErr; 127 uint64_t Size = P.second; 128 129 // Record this address in a local vector 130 Functions.push_back((void*)Addr); 131 132 // Build the function loaded notification message 133 iJIT_Method_Load FunctionMessage = 134 FunctionDescToIntelJITFormat(*Wrapper, Name->data(), Addr, Size); 135 DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size); 136 DILineInfoTable::iterator Begin = Lines.begin(); 137 DILineInfoTable::iterator End = Lines.end(); 138 for (DILineInfoTable::iterator It = Begin; It != End; ++It) { 139 LineInfo.push_back( 140 DILineInfoToIntelJITFormat((uintptr_t)Addr, It->first, It->second)); 141 } 142 if (LineInfo.size() == 0) { 143 FunctionMessage.source_file_name = 0; 144 FunctionMessage.line_number_size = 0; 145 FunctionMessage.line_number_table = 0; 146 } else { 147 // Source line information for the address range is provided as 148 // a code offset for the start of the corresponding sub-range and 149 // a source line. JIT API treats offsets in LineNumberInfo structures 150 // as the end of the corresponding code region. The start of the code 151 // is taken from the previous element. Need to shift the elements. 152 153 LineNumberInfo last = LineInfo.back(); 154 last.Offset = FunctionMessage.method_size; 155 LineInfo.push_back(last); 156 for (size_t i = LineInfo.size() - 2; i > 0; --i) 157 LineInfo[i].LineNumber = LineInfo[i - 1].LineNumber; 158 159 SourceFileName = Lines.front().second.FileName; 160 FunctionMessage.source_file_name = 161 const_cast<char *>(SourceFileName.c_str()); 162 FunctionMessage.line_number_size = LineInfo.size(); 163 FunctionMessage.line_number_table = &*LineInfo.begin(); 164 } 165 166 Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, 167 &FunctionMessage); 168 MethodIDs[(void*)Addr] = FunctionMessage.method_id; 169 } 170 171 // To support object unload notification, we need to keep a list of 172 // registered function addresses for each loaded object. We will 173 // use the MethodIDs map to get the registered ID for each function. 174 LoadedObjectMap[ObjData] = Functions; 175 DebugObjects[Obj.getData().data()] = std::move(DebugObjOwner); 176 } 177 178 void IntelJITEventListener::NotifyFreeingObject(const ObjectFile &Obj) { 179 // This object may not have been registered with the listener. If it wasn't, 180 // bail out. 181 if (DebugObjects.find(Obj.getData().data()) == DebugObjects.end()) 182 return; 183 184 // Get the address of the object image for use as a unique identifier 185 const ObjectFile &DebugObj = *DebugObjects[Obj.getData().data()].getBinary(); 186 const void* ObjData = DebugObj.getData().data(); 187 188 // Get the object's function list from LoadedObjectMap 189 ObjectMap::iterator OI = LoadedObjectMap.find(ObjData); 190 if (OI == LoadedObjectMap.end()) 191 return; 192 MethodAddressVector& Functions = OI->second; 193 194 // Walk the function list, unregistering each function 195 for (MethodAddressVector::iterator FI = Functions.begin(), 196 FE = Functions.end(); 197 FI != FE; 198 ++FI) { 199 void* FnStart = const_cast<void*>(*FI); 200 MethodIDMap::iterator MI = MethodIDs.find(FnStart); 201 if (MI != MethodIDs.end()) { 202 Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START, 203 &MI->second); 204 MethodIDs.erase(MI); 205 } 206 } 207 208 // Erase the object from LoadedObjectMap 209 LoadedObjectMap.erase(OI); 210 DebugObjects.erase(Obj.getData().data()); 211 } 212 213 } // anonymous namespace. 214 215 namespace llvm { 216 JITEventListener *JITEventListener::createIntelJITEventListener() { 217 return new IntelJITEventListener(new IntelJITEventsWrapper); 218 } 219 220 // for testing 221 JITEventListener *JITEventListener::createIntelJITEventListener( 222 IntelJITEventsWrapper* TestImpl) { 223 return new IntelJITEventListener(TestImpl); 224 } 225 226 } // namespace llvm 227 228