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 Expected<SymbolRef::Type> SymTypeOrErr = Sym.getType(); 117 if (!SymTypeOrErr) { 118 // TODO: Actually report errors helpfully. 119 consumeError(SymTypeOrErr.takeError()); 120 continue; 121 } 122 SymbolRef::Type SymType = *SymTypeOrErr; 123 if (SymType != SymbolRef::ST_Function) 124 continue; 125 126 Expected<StringRef> Name = Sym.getName(); 127 if (!Name) { 128 // TODO: Actually report errors helpfully. 129 consumeError(Name.takeError()); 130 continue; 131 } 132 133 Expected<uint64_t> AddrOrErr = Sym.getAddress(); 134 if (!AddrOrErr) { 135 // TODO: Actually report errors helpfully. 136 consumeError(AddrOrErr.takeError()); 137 continue; 138 } 139 uint64_t Addr = *AddrOrErr; 140 uint64_t Size = P.second; 141 142 // Record this address in a local vector 143 Functions.push_back((void*)Addr); 144 145 // Build the function loaded notification message 146 iJIT_Method_Load FunctionMessage = 147 FunctionDescToIntelJITFormat(*Wrapper, Name->data(), Addr, Size); 148 DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size); 149 DILineInfoTable::iterator Begin = Lines.begin(); 150 DILineInfoTable::iterator End = Lines.end(); 151 for (DILineInfoTable::iterator It = Begin; It != End; ++It) { 152 LineInfo.push_back( 153 DILineInfoToIntelJITFormat((uintptr_t)Addr, It->first, It->second)); 154 } 155 if (LineInfo.size() == 0) { 156 FunctionMessage.source_file_name = 0; 157 FunctionMessage.line_number_size = 0; 158 FunctionMessage.line_number_table = 0; 159 } else { 160 // Source line information for the address range is provided as 161 // a code offset for the start of the corresponding sub-range and 162 // a source line. JIT API treats offsets in LineNumberInfo structures 163 // as the end of the corresponding code region. The start of the code 164 // is taken from the previous element. Need to shift the elements. 165 166 LineNumberInfo last = LineInfo.back(); 167 last.Offset = FunctionMessage.method_size; 168 LineInfo.push_back(last); 169 for (size_t i = LineInfo.size() - 2; i > 0; --i) 170 LineInfo[i].LineNumber = LineInfo[i - 1].LineNumber; 171 172 SourceFileName = Lines.front().second.FileName; 173 FunctionMessage.source_file_name = 174 const_cast<char *>(SourceFileName.c_str()); 175 FunctionMessage.line_number_size = LineInfo.size(); 176 FunctionMessage.line_number_table = &*LineInfo.begin(); 177 } 178 179 Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, 180 &FunctionMessage); 181 MethodIDs[(void*)Addr] = FunctionMessage.method_id; 182 } 183 184 // To support object unload notification, we need to keep a list of 185 // registered function addresses for each loaded object. We will 186 // use the MethodIDs map to get the registered ID for each function. 187 LoadedObjectMap[ObjData] = Functions; 188 DebugObjects[Obj.getData().data()] = std::move(DebugObjOwner); 189 } 190 191 void IntelJITEventListener::NotifyFreeingObject(const ObjectFile &Obj) { 192 // This object may not have been registered with the listener. If it wasn't, 193 // bail out. 194 if (DebugObjects.find(Obj.getData().data()) == DebugObjects.end()) 195 return; 196 197 // Get the address of the object image for use as a unique identifier 198 const ObjectFile &DebugObj = *DebugObjects[Obj.getData().data()].getBinary(); 199 const void* ObjData = DebugObj.getData().data(); 200 201 // Get the object's function list from LoadedObjectMap 202 ObjectMap::iterator OI = LoadedObjectMap.find(ObjData); 203 if (OI == LoadedObjectMap.end()) 204 return; 205 MethodAddressVector& Functions = OI->second; 206 207 // Walk the function list, unregistering each function 208 for (MethodAddressVector::iterator FI = Functions.begin(), 209 FE = Functions.end(); 210 FI != FE; 211 ++FI) { 212 void* FnStart = const_cast<void*>(*FI); 213 MethodIDMap::iterator MI = MethodIDs.find(FnStart); 214 if (MI != MethodIDs.end()) { 215 Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START, 216 &MI->second); 217 MethodIDs.erase(MI); 218 } 219 } 220 221 // Erase the object from LoadedObjectMap 222 LoadedObjectMap.erase(OI); 223 DebugObjects.erase(Obj.getData().data()); 224 } 225 226 } // anonymous namespace. 227 228 namespace llvm { 229 JITEventListener *JITEventListener::createIntelJITEventListener() { 230 return new IntelJITEventListener(new IntelJITEventsWrapper); 231 } 232 233 // for testing 234 JITEventListener *JITEventListener::createIntelJITEventListener( 235 IntelJITEventsWrapper* TestImpl) { 236 return new IntelJITEventListener(TestImpl); 237 } 238 239 } // namespace llvm 240 241