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