1 //===-- IntelJITEventListener.cpp - Tell Intel profiler about JITed code --===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines a JITEventListener object to tell Intel(R) VTune(TM) 10 // Amplifier XE 2011 about JITted functions. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "IntelJITEventsWrapper.h" 15 #include "ittnotify.h" 16 #include "llvm-c/ExecutionEngine.h" 17 #include "llvm/ADT/DenseMap.h" 18 #include "llvm/CodeGen/MachineFunction.h" 19 #include "llvm/Config/config.h" 20 #include "llvm/DebugInfo/DIContext.h" 21 #include "llvm/DebugInfo/DWARF/DWARFContext.h" 22 #include "llvm/ExecutionEngine/JITEventListener.h" 23 #include "llvm/IR/DebugInfo.h" 24 #include "llvm/IR/Function.h" 25 #include "llvm/IR/Metadata.h" 26 #include "llvm/IR/ValueHandle.h" 27 #include "llvm/Object/ObjectFile.h" 28 #include "llvm/Object/SymbolSize.h" 29 #include "llvm/Support/Debug.h" 30 #include "llvm/Support/Errno.h" 31 #include "llvm/Support/raw_ostream.h" 32 33 using namespace llvm; 34 using namespace llvm::object; 35 36 #define DEBUG_TYPE "amplifier-jit-event-listener" 37 38 namespace { 39 40 class IntelIttnotifyInfo { 41 std::string ModuleName; 42 std::vector<std::string> SectionNamesVector; 43 std::vector<__itt_section_info> SectionInfoVector; 44 __itt_module_object *ModuleObject; 45 IntelJITEventsWrapper &WrapperRef; 46 47 public: 48 IntelIttnotifyInfo(IntelJITEventsWrapper &Wrapper) 49 : ModuleObject(NULL), WrapperRef(Wrapper){}; 50 ~IntelIttnotifyInfo() { delete ModuleObject; }; 51 52 void setModuleName(const char *Name) { ModuleName = std::string(Name); } 53 54 const char *getModuleName() { return ModuleName.c_str(); } 55 56 void setModuleObject(__itt_module_object *ModuleObj) { 57 ModuleObject = ModuleObj; 58 } 59 60 __itt_module_object *getModuleObject() { return ModuleObject; } 61 62 __itt_section_info *getSectionInfoVectorBegin() { 63 if (SectionInfoVector.size()) 64 return &SectionInfoVector[0]; 65 return NULL; 66 } 67 68 void reportSection(llvm::IttEventType EventType, const char *SectionName, 69 unsigned int SectionSize) { 70 WrapperRef.iJitIttNotifyInfo(EventType, SectionName, SectionSize); 71 } 72 73 int fillSectionInformation(const ObjectFile &Obj, 74 const RuntimeDyld::LoadedObjectInfo &L) { 75 76 int SectionCounter = 0; 77 78 for (auto &Section : Obj.sections()) { 79 uint64_t SectionLoadAddr = L.getSectionLoadAddress(Section); 80 if (SectionLoadAddr) { 81 object::ELFSectionRef ElfSection(Section); 82 83 __itt_section_info SectionInfo; 84 memset(&SectionInfo, 0, sizeof(SectionInfo)); 85 SectionInfo.start_addr = reinterpret_cast<void *>(SectionLoadAddr); 86 SectionInfo.file_offset = ElfSection.getOffset(); 87 SectionInfo.flags = ElfSection.getFlags(); 88 89 StringRef SectionName(""); 90 auto SectionNameOrError = ElfSection.getName(); 91 if (SectionNameOrError) 92 SectionName = *SectionNameOrError; 93 94 SectionNamesVector.push_back(SectionName.str()); 95 SectionInfo.size = ElfSection.getSize(); 96 reportSection(llvm::LoadBinarySection, SectionName.str().c_str(), 97 SectionInfo.size); 98 99 if (ElfSection.isBSS()) { 100 SectionInfo.type = itt_section_type_bss; 101 } else if (ElfSection.isData()) { 102 SectionInfo.type = itt_section_type_data; 103 } else if (ElfSection.isText()) { 104 SectionInfo.type = itt_section_type_text; 105 } 106 SectionInfoVector.push_back(SectionInfo); 107 ++SectionCounter; 108 } 109 } 110 // Hereinafter: don't change SectionNamesVector content to avoid vector 111 // reallocation - reallocation invalidates all the references, pointers, and 112 // iterators referring to the elements in the sequence. 113 for (int I = 0; I < SectionCounter; ++I) { 114 SectionInfoVector[I].name = SectionNamesVector[I].c_str(); 115 } 116 return SectionCounter; 117 } 118 }; 119 120 class IntelJITEventListener : public JITEventListener { 121 typedef DenseMap<void*, unsigned int> MethodIDMap; 122 123 std::unique_ptr<IntelJITEventsWrapper> Wrapper; 124 MethodIDMap MethodIDs; 125 126 typedef SmallVector<const void *, 64> MethodAddressVector; 127 typedef DenseMap<const void *, MethodAddressVector> ObjectMap; 128 129 ObjectMap LoadedObjectMap; 130 std::map<ObjectKey, OwningBinary<ObjectFile>> DebugObjects; 131 132 std::map<ObjectKey, std::unique_ptr<IntelIttnotifyInfo>> KeyToIttnotify; 133 134 public: 135 IntelJITEventListener(IntelJITEventsWrapper* libraryWrapper) { 136 Wrapper.reset(libraryWrapper); 137 } 138 139 ~IntelJITEventListener() { 140 } 141 142 void notifyObjectLoaded(ObjectKey Key, const ObjectFile &Obj, 143 const RuntimeDyld::LoadedObjectInfo &L) override; 144 145 void notifyFreeingObject(ObjectKey Key) override; 146 }; 147 148 static LineNumberInfo DILineInfoToIntelJITFormat(uintptr_t StartAddress, 149 uintptr_t Address, 150 DILineInfo Line) { 151 LineNumberInfo Result; 152 153 Result.Offset = Address - StartAddress; 154 Result.LineNumber = Line.Line; 155 156 return Result; 157 } 158 159 static iJIT_Method_Load FunctionDescToIntelJITFormat( 160 IntelJITEventsWrapper& Wrapper, 161 const char* FnName, 162 uintptr_t FnStart, 163 size_t FnSize) { 164 iJIT_Method_Load Result; 165 memset(&Result, 0, sizeof(iJIT_Method_Load)); 166 167 Result.method_id = Wrapper.iJIT_GetNewMethodID(); 168 Result.method_name = const_cast<char*>(FnName); 169 Result.method_load_address = reinterpret_cast<void*>(FnStart); 170 Result.method_size = FnSize; 171 172 Result.class_id = 0; 173 Result.class_file_name = NULL; 174 Result.user_data = NULL; 175 Result.user_data_size = 0; 176 Result.env = iJDE_JittingAPI; 177 178 return Result; 179 } 180 181 int getBackwardCompatibilityMode() { 182 183 char *BackwardCompatibilityEnv = getenv("INTEL_JIT_BACKWARD_COMPATIBILITY"); 184 int BackwardCompatibilityMode = 0; 185 if (BackwardCompatibilityEnv) { 186 StringRef(BackwardCompatibilityEnv) 187 .getAsInteger(10, BackwardCompatibilityMode); 188 } 189 return BackwardCompatibilityMode; 190 } 191 192 void IntelJITEventListener::notifyObjectLoaded( 193 ObjectKey Key, const ObjectFile &Obj, 194 const RuntimeDyld::LoadedObjectInfo &L) { 195 196 int BackwardCompatibilityMode = getBackwardCompatibilityMode(); 197 if (BackwardCompatibilityMode == 0) { 198 if (Obj.isELF()) { 199 std::unique_ptr<IntelIttnotifyInfo> ModuleIttnotify = 200 std::make_unique<IntelIttnotifyInfo>(*Wrapper); 201 ModuleIttnotify->setModuleName( 202 StringRef(llvm::utohexstr( 203 MD5Hash(Obj.getMemoryBufferRef().getBuffer()), true)) 204 .str() 205 .c_str()); 206 207 __itt_module_object *ModuleObject = new __itt_module_object(); 208 ModuleObject->module_name = ModuleIttnotify->getModuleName(); 209 ModuleObject->module_size = Obj.getMemoryBufferRef().getBufferSize(); 210 Wrapper->iJitIttNotifyInfo(llvm::LoadBinaryModule, 211 ModuleObject->module_name, 212 ModuleObject->module_size); 213 ModuleObject->module_type = __itt_module_type_elf; 214 ModuleObject->section_number = 215 ModuleIttnotify->fillSectionInformation(Obj, L); 216 ModuleObject->module_buffer = 217 (void *)const_cast<char *>(Obj.getMemoryBufferRef().getBufferStart()); 218 ModuleObject->module_id = 219 __itt_id_make((void *)&(*ModuleObject), ModuleObject->module_size); 220 ModuleObject->section_array = 221 ModuleIttnotify->getSectionInfoVectorBegin(); 222 ModuleIttnotify->setModuleObject(ModuleObject); 223 224 __itt_module_load_with_sections(ModuleObject); 225 226 KeyToIttnotify[Key] = std::move(ModuleIttnotify); 227 } 228 } else if (BackwardCompatibilityMode == 1) { 229 230 OwningBinary<ObjectFile> DebugObjOwner = L.getObjectForDebug(Obj); 231 const ObjectFile *DebugObj = DebugObjOwner.getBinary(); 232 if (!DebugObj) 233 return; 234 235 // Get the address of the object image for use as a unique identifier 236 const void *ObjData = DebugObj->getData().data(); 237 std::unique_ptr<DIContext> Context = DWARFContext::create(*DebugObj); 238 MethodAddressVector Functions; 239 240 // Use symbol info to iterate functions in the object. 241 for (const std::pair<SymbolRef, uint64_t> &P : 242 computeSymbolSizes(*DebugObj)) { 243 SymbolRef Sym = P.first; 244 std::vector<LineNumberInfo> LineInfo; 245 std::string SourceFileName; 246 247 Expected<SymbolRef::Type> SymTypeOrErr = Sym.getType(); 248 if (!SymTypeOrErr) { 249 // TODO: Actually report errors helpfully. 250 consumeError(SymTypeOrErr.takeError()); 251 continue; 252 } 253 SymbolRef::Type SymType = *SymTypeOrErr; 254 if (SymType != SymbolRef::ST_Function) 255 continue; 256 257 Expected<StringRef> Name = Sym.getName(); 258 if (!Name) { 259 // TODO: Actually report errors helpfully. 260 consumeError(Name.takeError()); 261 continue; 262 } 263 264 Expected<uint64_t> AddrOrErr = Sym.getAddress(); 265 if (!AddrOrErr) { 266 // TODO: Actually report errors helpfully. 267 consumeError(AddrOrErr.takeError()); 268 continue; 269 } 270 uint64_t Addr = *AddrOrErr; 271 uint64_t Size = P.second; 272 273 auto SecOrErr = Sym.getSection(); 274 if (!SecOrErr) { 275 // TODO: Actually report errors helpfully. 276 consumeError(SecOrErr.takeError()); 277 continue; 278 } 279 object::section_iterator Sec = *SecOrErr; 280 if (Sec == Obj.section_end()) 281 continue; 282 uint64_t Index = Sec->getIndex(); 283 284 // Record this address in a local vector 285 Functions.push_back((void *)Addr); 286 287 // Build the function loaded notification message 288 iJIT_Method_Load FunctionMessage = 289 FunctionDescToIntelJITFormat(*Wrapper, Name->data(), Addr, Size); 290 DILineInfoTable Lines = 291 Context->getLineInfoForAddressRange({Addr, Index}, Size); 292 DILineInfoTable::iterator Begin = Lines.begin(); 293 DILineInfoTable::iterator End = Lines.end(); 294 for (DILineInfoTable::iterator It = Begin; It != End; ++It) { 295 LineInfo.push_back( 296 DILineInfoToIntelJITFormat((uintptr_t)Addr, It->first, It->second)); 297 } 298 if (LineInfo.size() == 0) { 299 FunctionMessage.source_file_name = 0; 300 FunctionMessage.line_number_size = 0; 301 FunctionMessage.line_number_table = 0; 302 } else { 303 // Source line information for the address range is provided as 304 // a code offset for the start of the corresponding sub-range and 305 // a source line. JIT API treats offsets in LineNumberInfo structures 306 // as the end of the corresponding code region. The start of the code 307 // is taken from the previous element. Need to shift the elements. 308 309 LineNumberInfo last = LineInfo.back(); 310 last.Offset = FunctionMessage.method_size; 311 LineInfo.push_back(last); 312 for (size_t i = LineInfo.size() - 2; i > 0; --i) 313 LineInfo[i].LineNumber = LineInfo[i - 1].LineNumber; 314 315 SourceFileName = Lines.front().second.FileName; 316 FunctionMessage.source_file_name = 317 const_cast<char *>(SourceFileName.c_str()); 318 FunctionMessage.line_number_size = LineInfo.size(); 319 FunctionMessage.line_number_table = &*LineInfo.begin(); 320 } 321 322 Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, 323 &FunctionMessage); 324 MethodIDs[(void *)Addr] = FunctionMessage.method_id; 325 } 326 327 // To support object unload notification, we need to keep a list of 328 // registered function addresses for each loaded object. We will 329 // use the MethodIDs map to get the registered ID for each function. 330 LoadedObjectMap[ObjData] = Functions; 331 DebugObjects[Key] = std::move(DebugObjOwner); 332 } 333 } 334 335 void IntelJITEventListener::notifyFreeingObject(ObjectKey Key) { 336 337 int BackwardCompatibilityMode = getBackwardCompatibilityMode(); 338 if (BackwardCompatibilityMode == 0) { 339 if (KeyToIttnotify.find(Key) == KeyToIttnotify.end()) 340 return; 341 __itt_module_unload_with_sections(KeyToIttnotify[Key]->getModuleObject()); 342 Wrapper->iJitIttNotifyInfo( 343 llvm::UnloadBinaryModule, 344 KeyToIttnotify[Key]->getModuleObject()->module_name, 345 KeyToIttnotify[Key]->getModuleObject()->module_size); 346 KeyToIttnotify.erase(Key); 347 } else if (BackwardCompatibilityMode == 1) { 348 // This object may not have been registered with the listener. If it wasn't, 349 // bail out. 350 if (DebugObjects.find(Key) == DebugObjects.end()) 351 return; 352 353 // Get the address of the object image for use as a unique identifier 354 const ObjectFile &DebugObj = *DebugObjects[Key].getBinary(); 355 const void *ObjData = DebugObj.getData().data(); 356 357 // Get the object's function list from LoadedObjectMap 358 ObjectMap::iterator OI = LoadedObjectMap.find(ObjData); 359 if (OI == LoadedObjectMap.end()) 360 return; 361 MethodAddressVector &Functions = OI->second; 362 363 // Walk the function list, unregistering each function 364 for (MethodAddressVector::iterator FI = Functions.begin(), 365 FE = Functions.end(); 366 FI != FE; ++FI) { 367 void *FnStart = const_cast<void *>(*FI); 368 MethodIDMap::iterator MI = MethodIDs.find(FnStart); 369 if (MI != MethodIDs.end()) { 370 Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START, 371 &MI->second); 372 MethodIDs.erase(MI); 373 } 374 } 375 376 // Erase the object from LoadedObjectMap 377 LoadedObjectMap.erase(OI); 378 DebugObjects.erase(Key); 379 } 380 } 381 382 } // anonymous namespace. 383 384 namespace llvm { 385 JITEventListener *JITEventListener::createIntelJITEventListener() { 386 return new IntelJITEventListener(new IntelJITEventsWrapper); 387 } 388 389 // for testing 390 JITEventListener *JITEventListener::createIntelJITEventListener( 391 IntelJITEventsWrapper* TestImpl) { 392 return new IntelJITEventListener(TestImpl); 393 } 394 395 } // namespace llvm 396 397 LLVMJITEventListenerRef LLVMCreateIntelJITEventListener(void) 398 { 399 return wrap(JITEventListener::createIntelJITEventListener()); 400 } 401