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