1 //===--- VTuneSupportPlugin.cpp -- Support for VTune profiler --*- C++ -*--===// 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 // Handles support for registering code with VIntel Tune's Amplfiier JIT API. 10 // 11 //===----------------------------------------------------------------------===// 12 #include "llvm/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.h" 13 #include "llvm/DebugInfo/DWARF/DWARFContext.h" 14 #include "llvm/ExecutionEngine/Orc/Debugging/DebugInfoSupport.h" 15 16 using namespace llvm; 17 using namespace llvm::orc; 18 using namespace llvm::jitlink; 19 20 static constexpr StringRef RegisterVTuneImplName = "llvm_orc_registerVTuneImpl"; 21 static constexpr StringRef UnregisterVTuneImplName = 22 "llvm_orc_unregisterVTuneImpl"; 23 static constexpr StringRef RegisterTestVTuneImplName = 24 "llvm_orc_test_registerVTuneImpl"; 25 26 static VTuneMethodBatch getMethodBatch(LinkGraph &G, bool EmitDebugInfo) { 27 VTuneMethodBatch Batch; 28 std::unique_ptr<DWARFContext> DC; 29 StringMap<std::unique_ptr<MemoryBuffer>> DCBacking; 30 if (EmitDebugInfo) { 31 auto EDC = createDWARFContext(G); 32 if (!EDC) { 33 EmitDebugInfo = false; 34 } else { 35 DC = std::move(EDC->first); 36 DCBacking = std::move(EDC->second); 37 } 38 } 39 40 auto GetStringIdx = [Deduplicator = StringMap<uint32_t>(), 41 &Batch](StringRef S) mutable { 42 auto [I, Inserted] = Deduplicator.try_emplace(S); 43 if (Inserted) { 44 Batch.Strings.push_back(S.str()); 45 I->second = Batch.Strings.size(); 46 } 47 return I->second; 48 }; 49 for (auto Sym : G.defined_symbols()) { 50 if (!Sym->isCallable()) 51 continue; 52 53 Batch.Methods.push_back(VTuneMethodInfo()); 54 auto &Method = Batch.Methods.back(); 55 Method.MethodID = 0; 56 Method.ParentMI = 0; 57 Method.LoadAddr = Sym->getAddress(); 58 Method.LoadSize = Sym->getSize(); 59 Method.NameSI = GetStringIdx(*Sym->getName()); 60 Method.ClassFileSI = 0; 61 Method.SourceFileSI = 0; 62 63 if (!EmitDebugInfo) 64 continue; 65 66 auto &Section = Sym->getSection(); 67 auto Addr = Sym->getAddress(); 68 auto SAddr = 69 object::SectionedAddress{Addr.getValue(), Section.getOrdinal()}; 70 DILineInfoTable LinesInfo = DC->getLineInfoForAddressRange( 71 SAddr, Sym->getSize(), 72 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath); 73 Method.SourceFileSI = Batch.Strings.size(); 74 Batch.Strings.push_back( 75 DC->getLineInfoForAddress(SAddr).value_or(DILineInfo()).FileName); 76 for (auto &LInfo : LinesInfo) { 77 Method.LineTable.push_back( 78 std::pair<unsigned, unsigned>{/*unsigned*/ Sym->getOffset(), 79 /*DILineInfo*/ LInfo.second.Line}); 80 } 81 } 82 return Batch; 83 } 84 85 void VTuneSupportPlugin::modifyPassConfig(MaterializationResponsibility &MR, 86 LinkGraph &G, 87 PassConfiguration &Config) { 88 Config.PostFixupPasses.push_back([this, MR = &MR](LinkGraph &G) { 89 // the object file is generated but not linked yet 90 auto Batch = getMethodBatch(G, EmitDebugInfo); 91 if (Batch.Methods.empty()) { 92 return Error::success(); 93 } 94 { 95 std::lock_guard<std::mutex> Lock(PluginMutex); 96 uint64_t Allocated = Batch.Methods.size(); 97 uint64_t Start = NextMethodID; 98 NextMethodID += Allocated; 99 for (size_t i = Start; i < NextMethodID; ++i) { 100 Batch.Methods[i - Start].MethodID = i; 101 } 102 this->PendingMethodIDs[MR] = {Start, Allocated}; 103 } 104 G.allocActions().push_back( 105 {cantFail(shared::WrapperFunctionCall::Create< 106 shared::SPSArgList<shared::SPSVTuneMethodBatch>>( 107 RegisterVTuneImplAddr, Batch)), 108 {}}); 109 return Error::success(); 110 }); 111 } 112 113 Error VTuneSupportPlugin::notifyEmitted(MaterializationResponsibility &MR) { 114 if (auto Err = MR.withResourceKeyDo([this, MR = &MR](ResourceKey K) { 115 std::lock_guard<std::mutex> Lock(PluginMutex); 116 auto I = PendingMethodIDs.find(MR); 117 if (I == PendingMethodIDs.end()) 118 return; 119 120 LoadedMethodIDs[K].push_back(I->second); 121 PendingMethodIDs.erase(I); 122 })) { 123 return Err; 124 } 125 return Error::success(); 126 } 127 128 Error VTuneSupportPlugin::notifyFailed(MaterializationResponsibility &MR) { 129 std::lock_guard<std::mutex> Lock(PluginMutex); 130 PendingMethodIDs.erase(&MR); 131 return Error::success(); 132 } 133 134 Error VTuneSupportPlugin::notifyRemovingResources(JITDylib &JD, ResourceKey K) { 135 // Unregistration not required if not provided 136 if (!UnregisterVTuneImplAddr) { 137 return Error::success(); 138 } 139 VTuneUnloadedMethodIDs UnloadedIDs; 140 { 141 std::lock_guard<std::mutex> Lock(PluginMutex); 142 auto I = LoadedMethodIDs.find(K); 143 if (I == LoadedMethodIDs.end()) 144 return Error::success(); 145 146 UnloadedIDs = std::move(I->second); 147 LoadedMethodIDs.erase(I); 148 } 149 if (auto Err = EPC.callSPSWrapper<void(shared::SPSVTuneUnloadedMethodIDs)>( 150 UnregisterVTuneImplAddr, UnloadedIDs)) 151 return Err; 152 153 return Error::success(); 154 } 155 156 void VTuneSupportPlugin::notifyTransferringResources(JITDylib &JD, 157 ResourceKey DstKey, 158 ResourceKey SrcKey) { 159 std::lock_guard<std::mutex> Lock(PluginMutex); 160 auto I = LoadedMethodIDs.find(SrcKey); 161 if (I == LoadedMethodIDs.end()) 162 return; 163 164 auto &Dest = LoadedMethodIDs[DstKey]; 165 llvm::append_range(Dest, I->second); 166 LoadedMethodIDs.erase(SrcKey); 167 } 168 169 Expected<std::unique_ptr<VTuneSupportPlugin>> 170 VTuneSupportPlugin::Create(ExecutorProcessControl &EPC, JITDylib &JD, 171 bool EmitDebugInfo, bool TestMode) { 172 auto &ES = EPC.getExecutionSession(); 173 auto RegisterImplName = 174 ES.intern(TestMode ? RegisterTestVTuneImplName : RegisterVTuneImplName); 175 auto UnregisterImplName = ES.intern(UnregisterVTuneImplName); 176 SymbolLookupSet SLS{RegisterImplName, UnregisterImplName}; 177 auto Res = ES.lookup(makeJITDylibSearchOrder({&JD}), std::move(SLS)); 178 if (!Res) 179 return Res.takeError(); 180 ExecutorAddr RegisterImplAddr( 181 Res->find(RegisterImplName)->second.getAddress()); 182 ExecutorAddr UnregisterImplAddr( 183 Res->find(UnregisterImplName)->second.getAddress()); 184 return std::make_unique<VTuneSupportPlugin>( 185 EPC, RegisterImplAddr, UnregisterImplAddr, EmitDebugInfo); 186 } 187