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/DebugInfo/DIContext.h" 26 #include "llvm/ExecutionEngine/ObjectImage.h" 27 #include "llvm/Object/ObjectFile.h" 28 #include "llvm/Support/Debug.h" 29 #include "llvm/Support/raw_ostream.h" 30 #include "llvm/Support/Errno.h" 31 #include "llvm/Support/ValueHandle.h" 32 #include "EventListenerCommon.h" 33 #include "IntelJITEventsWrapper.h" 34 35 using namespace llvm; 36 using namespace llvm::jitprofiling; 37 38 namespace { 39 40 class IntelJITEventListener : public JITEventListener { 41 typedef DenseMap<void*, unsigned int> MethodIDMap; 42 43 OwningPtr<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 52 public: 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 71 static 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 83 static 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.getLine(); 90 91 return Result; 92 } 93 94 static 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. 117 void 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 182 void 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 190 void 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 error_code ec; 198 for (object::symbol_iterator I = Obj.begin_symbols(), 199 E = Obj.end_symbols(); 200 I != E && !ec; 201 I.increment(ec)) { 202 std::vector<LineNumberInfo> LineInfo; 203 std::string SourceFileName; 204 205 object::SymbolRef::Type SymType; 206 if (I->getType(SymType)) continue; 207 if (SymType == object::SymbolRef::ST_Function) { 208 StringRef Name; 209 uint64_t Addr; 210 uint64_t Size; 211 if (I->getName(Name)) continue; 212 if (I->getAddress(Addr)) continue; 213 if (I->getSize(Size)) continue; 214 215 // Record this address in a local vector 216 Functions.push_back((void*)Addr); 217 218 // Build the function loaded notification message 219 iJIT_Method_Load FunctionMessage = FunctionDescToIntelJITFormat(*Wrapper, 220 Name.data(), 221 Addr, 222 Size); 223 if (Context) { 224 DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size); 225 DILineInfoTable::iterator Begin = Lines.begin(); 226 DILineInfoTable::iterator End = Lines.end(); 227 for (DILineInfoTable::iterator It = Begin; It != End; ++It) { 228 LineInfo.push_back(DILineInfoToIntelJITFormat((uintptr_t)Addr, 229 It->first, 230 It->second)); 231 } 232 if (LineInfo.size() == 0) { 233 FunctionMessage.source_file_name = 0; 234 FunctionMessage.line_number_size = 0; 235 FunctionMessage.line_number_table = 0; 236 } else { 237 SourceFileName = Lines.front().second.getFileName(); 238 FunctionMessage.source_file_name = (char *)SourceFileName.c_str(); 239 FunctionMessage.line_number_size = LineInfo.size(); 240 FunctionMessage.line_number_table = &*LineInfo.begin(); 241 } 242 } else { 243 FunctionMessage.source_file_name = 0; 244 FunctionMessage.line_number_size = 0; 245 FunctionMessage.line_number_table = 0; 246 } 247 248 Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, 249 &FunctionMessage); 250 MethodIDs[(void*)Addr] = FunctionMessage.method_id; 251 } 252 } 253 254 // To support object unload notification, we need to keep a list of 255 // registered function addresses for each loaded object. We will 256 // use the MethodIDs map to get the registered ID for each function. 257 LoadedObjectMap[ObjData] = Functions; 258 } 259 260 void IntelJITEventListener::NotifyFreeingObject(const ObjectImage &Obj) { 261 // Get the address of the object image for use as a unique identifier 262 const void* ObjData = Obj.getData().data(); 263 264 // Get the object's function list from LoadedObjectMap 265 ObjectMap::iterator OI = LoadedObjectMap.find(ObjData); 266 if (OI == LoadedObjectMap.end()) 267 return; 268 MethodAddressVector& Functions = OI->second; 269 270 // Walk the function list, unregistering each function 271 for (MethodAddressVector::iterator FI = Functions.begin(), 272 FE = Functions.end(); 273 FI != FE; 274 ++FI) { 275 void* FnStart = const_cast<void*>(*FI); 276 MethodIDMap::iterator MI = MethodIDs.find(FnStart); 277 if (MI != MethodIDs.end()) { 278 Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START, 279 &MI->second); 280 MethodIDs.erase(MI); 281 } 282 } 283 284 // Erase the object from LoadedObjectMap 285 LoadedObjectMap.erase(OI); 286 } 287 288 } // anonymous namespace. 289 290 namespace llvm { 291 JITEventListener *JITEventListener::createIntelJITEventListener() { 292 return new IntelJITEventListener(new IntelJITEventsWrapper); 293 } 294 295 // for testing 296 JITEventListener *JITEventListener::createIntelJITEventListener( 297 IntelJITEventsWrapper* TestImpl) { 298 return new IntelJITEventListener(TestImpl); 299 } 300 301 } // namespace llvm 302 303