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