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