IntelJITEventListener.cpp revision 0b8c9a80f20772c3793201ab5b251d3520b9cea3
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/ExecutionEngine/ObjectImage.h" 26#include "llvm/Support/Debug.h" 27#include "llvm/Support/raw_ostream.h" 28#include "llvm/Support/Errno.h" 29#include "llvm/Support/ValueHandle.h" 30#include "EventListenerCommon.h" 31#include "IntelJITEventsWrapper.h" 32 33using namespace llvm; 34using namespace llvm::jitprofiling; 35 36namespace { 37 38class IntelJITEventListener : public JITEventListener { 39 typedef DenseMap<void*, unsigned int> MethodIDMap; 40 41 OwningPtr<IntelJITEventsWrapper> Wrapper; 42 MethodIDMap MethodIDs; 43 FilenameCache Filenames; 44 45 typedef SmallVector<const void *, 64> MethodAddressVector; 46 typedef DenseMap<const void *, MethodAddressVector> ObjectMap; 47 48 ObjectMap LoadedObjectMap; 49 50public: 51 IntelJITEventListener(IntelJITEventsWrapper* libraryWrapper) { 52 Wrapper.reset(libraryWrapper); 53 } 54 55 ~IntelJITEventListener() { 56 } 57 58 virtual void NotifyFunctionEmitted(const Function &F, 59 void *FnStart, size_t FnSize, 60 const EmittedFunctionDetails &Details); 61 62 virtual void NotifyFreeingMachineCode(void *OldPtr); 63 64 virtual void NotifyObjectEmitted(const ObjectImage &Obj); 65 66 virtual void NotifyFreeingObject(const ObjectImage &Obj); 67}; 68 69static LineNumberInfo LineStartToIntelJITFormat( 70 uintptr_t StartAddress, 71 uintptr_t Address, 72 DebugLoc Loc) { 73 LineNumberInfo Result; 74 75 Result.Offset = Address - StartAddress; 76 Result.LineNumber = Loc.getLine(); 77 78 return Result; 79} 80 81static iJIT_Method_Load FunctionDescToIntelJITFormat( 82 IntelJITEventsWrapper& Wrapper, 83 const char* FnName, 84 uintptr_t FnStart, 85 size_t FnSize) { 86 iJIT_Method_Load Result; 87 memset(&Result, 0, sizeof(iJIT_Method_Load)); 88 89 Result.method_id = Wrapper.iJIT_GetNewMethodID(); 90 Result.method_name = const_cast<char*>(FnName); 91 Result.method_load_address = reinterpret_cast<void*>(FnStart); 92 Result.method_size = FnSize; 93 94 Result.class_id = 0; 95 Result.class_file_name = NULL; 96 Result.user_data = NULL; 97 Result.user_data_size = 0; 98 Result.env = iJDE_JittingAPI; 99 100 return Result; 101} 102 103// Adds the just-emitted function to the symbol table. 104void IntelJITEventListener::NotifyFunctionEmitted( 105 const Function &F, void *FnStart, size_t FnSize, 106 const EmittedFunctionDetails &Details) { 107 iJIT_Method_Load FunctionMessage = FunctionDescToIntelJITFormat(*Wrapper, 108 F.getName().data(), 109 reinterpret_cast<uint64_t>(FnStart), 110 FnSize); 111 112 std::vector<LineNumberInfo> LineInfo; 113 114 if (!Details.LineStarts.empty()) { 115 // Now convert the line number information from the address/DebugLoc 116 // format in Details to the offset/lineno in Intel JIT API format. 117 118 LineInfo.reserve(Details.LineStarts.size() + 1); 119 120 DebugLoc FirstLoc = Details.LineStarts[0].Loc; 121 assert(!FirstLoc.isUnknown() 122 && "LineStarts should not contain unknown DebugLocs"); 123 124 MDNode *FirstLocScope = FirstLoc.getScope(F.getContext()); 125 DISubprogram FunctionDI = getDISubprogram(FirstLocScope); 126 if (FunctionDI.Verify()) { 127 FunctionMessage.source_file_name = const_cast<char*>( 128 Filenames.getFullPath(FirstLocScope)); 129 130 LineNumberInfo FirstLine; 131 FirstLine.Offset = 0; 132 FirstLine.LineNumber = FunctionDI.getLineNumber(); 133 LineInfo.push_back(FirstLine); 134 } 135 136 for (std::vector<EmittedFunctionDetails::LineStart>::const_iterator I = 137 Details.LineStarts.begin(), E = Details.LineStarts.end(); 138 I != E; ++I) { 139 // This implementation ignores the DebugLoc filename because the Intel 140 // JIT API does not support multiple source files associated with a single 141 // JIT function 142 LineInfo.push_back(LineStartToIntelJITFormat( 143 reinterpret_cast<uintptr_t>(FnStart), 144 I->Address, 145 I->Loc)); 146 147 // If we have no file name yet for the function, use the filename from 148 // the first instruction that has one 149 if (FunctionMessage.source_file_name == 0) { 150 MDNode *scope = I->Loc.getScope( 151 Details.MF->getFunction()->getContext()); 152 FunctionMessage.source_file_name = const_cast<char*>( 153 Filenames.getFullPath(scope)); 154 } 155 } 156 157 FunctionMessage.line_number_size = LineInfo.size(); 158 FunctionMessage.line_number_table = &*LineInfo.begin(); 159 } else { 160 FunctionMessage.line_number_size = 0; 161 FunctionMessage.line_number_table = 0; 162 } 163 164 Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, 165 &FunctionMessage); 166 MethodIDs[FnStart] = FunctionMessage.method_id; 167} 168 169void IntelJITEventListener::NotifyFreeingMachineCode(void *FnStart) { 170 MethodIDMap::iterator I = MethodIDs.find(FnStart); 171 if (I != MethodIDs.end()) { 172 Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START, &I->second); 173 MethodIDs.erase(I); 174 } 175} 176 177void IntelJITEventListener::NotifyObjectEmitted(const ObjectImage &Obj) { 178 // Get the address of the object image for use as a unique identifier 179 const void* ObjData = Obj.getData().data(); 180 MethodAddressVector Functions; 181 182 // Use symbol info to iterate functions in the object. 183 error_code ec; 184 for (object::symbol_iterator I = Obj.begin_symbols(), 185 E = Obj.end_symbols(); 186 I != E && !ec; 187 I.increment(ec)) { 188 object::SymbolRef::Type SymType; 189 if (I->getType(SymType)) continue; 190 if (SymType == object::SymbolRef::ST_Function) { 191 StringRef Name; 192 uint64_t Addr; 193 uint64_t Size; 194 if (I->getName(Name)) continue; 195 if (I->getAddress(Addr)) continue; 196 if (I->getSize(Size)) continue; 197 198 // Record this address in a local vector 199 Functions.push_back((void*)Addr); 200 201 // Build the function loaded notification message 202 iJIT_Method_Load FunctionMessage = FunctionDescToIntelJITFormat(*Wrapper, 203 Name.data(), 204 Addr, 205 Size); 206 207 // FIXME: Try to find line info for this function in the DWARF sections. 208 FunctionMessage.source_file_name = 0; 209 FunctionMessage.line_number_size = 0; 210 FunctionMessage.line_number_table = 0; 211 212 Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, 213 &FunctionMessage); 214 MethodIDs[(void*)Addr] = FunctionMessage.method_id; 215 } 216 } 217 218 // To support object unload notification, we need to keep a list of 219 // registered function addresses for each loaded object. We will 220 // use the MethodIDs map to get the registered ID for each function. 221 LoadedObjectMap[ObjData] = Functions; 222} 223 224void IntelJITEventListener::NotifyFreeingObject(const ObjectImage &Obj) { 225 // Get the address of the object image for use as a unique identifier 226 const void* ObjData = Obj.getData().data(); 227 228 // Get the object's function list from LoadedObjectMap 229 ObjectMap::iterator OI = LoadedObjectMap.find(ObjData); 230 if (OI == LoadedObjectMap.end()) 231 return; 232 MethodAddressVector& Functions = OI->second; 233 234 // Walk the function list, unregistering each function 235 for (MethodAddressVector::iterator FI = Functions.begin(), 236 FE = Functions.end(); 237 FI != FE; 238 ++FI) { 239 void* FnStart = const_cast<void*>(*FI); 240 MethodIDMap::iterator MI = MethodIDs.find(FnStart); 241 if (MI != MethodIDs.end()) { 242 Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START, 243 &MI->second); 244 MethodIDs.erase(MI); 245 } 246 } 247 248 // Erase the object from LoadedObjectMap 249 LoadedObjectMap.erase(OI); 250} 251 252} // anonymous namespace. 253 254namespace llvm { 255JITEventListener *JITEventListener::createIntelJITEventListener() { 256 return new IntelJITEventListener(new IntelJITEventsWrapper); 257} 258 259// for testing 260JITEventListener *JITEventListener::createIntelJITEventListener( 261 IntelJITEventsWrapper* TestImpl) { 262 return new IntelJITEventListener(TestImpl); 263} 264 265} // namespace llvm 266 267