100f41216SHongyu Chen //===--- VTuneSupportPlugin.cpp -- Support for VTune profiler --*- C++ -*--===// 200f41216SHongyu Chen // 300f41216SHongyu Chen // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 400f41216SHongyu Chen // See https://llvm.org/LICENSE.txt for license information. 500f41216SHongyu Chen // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 600f41216SHongyu Chen // 700f41216SHongyu Chen //===----------------------------------------------------------------------===// 800f41216SHongyu Chen // 900f41216SHongyu Chen // Handles support for registering code with VIntel Tune's Amplfiier JIT API. 1000f41216SHongyu Chen // 1100f41216SHongyu Chen //===----------------------------------------------------------------------===// 1200f41216SHongyu Chen #include "llvm/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.h" 1300f41216SHongyu Chen #include "llvm/DebugInfo/DWARF/DWARFContext.h" 1400f41216SHongyu Chen #include "llvm/ExecutionEngine/Orc/Debugging/DebugInfoSupport.h" 1500f41216SHongyu Chen 1600f41216SHongyu Chen using namespace llvm; 1700f41216SHongyu Chen using namespace llvm::orc; 1800f41216SHongyu Chen using namespace llvm::jitlink; 1900f41216SHongyu Chen 2000f41216SHongyu Chen static constexpr StringRef RegisterVTuneImplName = "llvm_orc_registerVTuneImpl"; 2100f41216SHongyu Chen static constexpr StringRef UnregisterVTuneImplName = 2200f41216SHongyu Chen "llvm_orc_unregisterVTuneImpl"; 2300f41216SHongyu Chen static constexpr StringRef RegisterTestVTuneImplName = 2400f41216SHongyu Chen "llvm_orc_test_registerVTuneImpl"; 2500f41216SHongyu Chen 2600f41216SHongyu Chen static VTuneMethodBatch getMethodBatch(LinkGraph &G, bool EmitDebugInfo) { 2700f41216SHongyu Chen VTuneMethodBatch Batch; 2800f41216SHongyu Chen std::unique_ptr<DWARFContext> DC; 2900f41216SHongyu Chen StringMap<std::unique_ptr<MemoryBuffer>> DCBacking; 3000f41216SHongyu Chen if (EmitDebugInfo) { 3100f41216SHongyu Chen auto EDC = createDWARFContext(G); 3200f41216SHongyu Chen if (!EDC) { 3300f41216SHongyu Chen EmitDebugInfo = false; 3400f41216SHongyu Chen } else { 3500f41216SHongyu Chen DC = std::move(EDC->first); 3600f41216SHongyu Chen DCBacking = std::move(EDC->second); 3700f41216SHongyu Chen } 3800f41216SHongyu Chen } 3900f41216SHongyu Chen 4000f41216SHongyu Chen auto GetStringIdx = [Deduplicator = StringMap<uint32_t>(), 4100f41216SHongyu Chen &Batch](StringRef S) mutable { 42ede866d7SKazu Hirata auto [I, Inserted] = Deduplicator.try_emplace(S); 43ede866d7SKazu Hirata if (Inserted) { 4400f41216SHongyu Chen Batch.Strings.push_back(S.str()); 45ede866d7SKazu Hirata I->second = Batch.Strings.size(); 46ede866d7SKazu Hirata } 47ede866d7SKazu Hirata return I->second; 4800f41216SHongyu Chen }; 4900f41216SHongyu Chen for (auto Sym : G.defined_symbols()) { 5000f41216SHongyu Chen if (!Sym->isCallable()) 5100f41216SHongyu Chen continue; 5200f41216SHongyu Chen 5300f41216SHongyu Chen Batch.Methods.push_back(VTuneMethodInfo()); 5400f41216SHongyu Chen auto &Method = Batch.Methods.back(); 5500f41216SHongyu Chen Method.MethodID = 0; 5600f41216SHongyu Chen Method.ParentMI = 0; 5700f41216SHongyu Chen Method.LoadAddr = Sym->getAddress(); 5800f41216SHongyu Chen Method.LoadSize = Sym->getSize(); 59*2ccf7ed2SJared Wyles Method.NameSI = GetStringIdx(*Sym->getName()); 6000f41216SHongyu Chen Method.ClassFileSI = 0; 6100f41216SHongyu Chen Method.SourceFileSI = 0; 6200f41216SHongyu Chen 6300f41216SHongyu Chen if (!EmitDebugInfo) 6400f41216SHongyu Chen continue; 6500f41216SHongyu Chen 6600f41216SHongyu Chen auto &Section = Sym->getBlock().getSection(); 6700f41216SHongyu Chen auto Addr = Sym->getAddress(); 6800f41216SHongyu Chen auto SAddr = 6900f41216SHongyu Chen object::SectionedAddress{Addr.getValue(), Section.getOrdinal()}; 7000f41216SHongyu Chen DILineInfoTable LinesInfo = DC->getLineInfoForAddressRange( 7100f41216SHongyu Chen SAddr, Sym->getSize(), 7200f41216SHongyu Chen DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath); 7300f41216SHongyu Chen Method.SourceFileSI = Batch.Strings.size(); 7400f41216SHongyu Chen Batch.Strings.push_back(DC->getLineInfoForAddress(SAddr).FileName); 7500f41216SHongyu Chen for (auto &LInfo : LinesInfo) { 7600f41216SHongyu Chen Method.LineTable.push_back( 7700f41216SHongyu Chen std::pair<unsigned, unsigned>{/*unsigned*/ Sym->getOffset(), 7800f41216SHongyu Chen /*DILineInfo*/ LInfo.second.Line}); 7900f41216SHongyu Chen } 8000f41216SHongyu Chen } 8100f41216SHongyu Chen return Batch; 8200f41216SHongyu Chen } 8300f41216SHongyu Chen 8400f41216SHongyu Chen void VTuneSupportPlugin::modifyPassConfig(MaterializationResponsibility &MR, 8500f41216SHongyu Chen LinkGraph &G, 8600f41216SHongyu Chen PassConfiguration &Config) { 8700f41216SHongyu Chen Config.PostFixupPasses.push_back([this, MR = &MR](LinkGraph &G) { 8800f41216SHongyu Chen // the object file is generated but not linked yet 8900f41216SHongyu Chen auto Batch = getMethodBatch(G, EmitDebugInfo); 9000f41216SHongyu Chen if (Batch.Methods.empty()) { 9100f41216SHongyu Chen return Error::success(); 9200f41216SHongyu Chen } 9300f41216SHongyu Chen { 9400f41216SHongyu Chen std::lock_guard<std::mutex> Lock(PluginMutex); 9500f41216SHongyu Chen uint64_t Allocated = Batch.Methods.size(); 9600f41216SHongyu Chen uint64_t Start = NextMethodID; 9700f41216SHongyu Chen NextMethodID += Allocated; 9800f41216SHongyu Chen for (size_t i = Start; i < NextMethodID; ++i) { 9900f41216SHongyu Chen Batch.Methods[i - Start].MethodID = i; 10000f41216SHongyu Chen } 10100f41216SHongyu Chen this->PendingMethodIDs[MR] = {Start, Allocated}; 10200f41216SHongyu Chen } 10300f41216SHongyu Chen G.allocActions().push_back( 10400f41216SHongyu Chen {cantFail(shared::WrapperFunctionCall::Create< 10500f41216SHongyu Chen shared::SPSArgList<shared::SPSVTuneMethodBatch>>( 10600f41216SHongyu Chen RegisterVTuneImplAddr, Batch)), 10700f41216SHongyu Chen {}}); 10800f41216SHongyu Chen return Error::success(); 10900f41216SHongyu Chen }); 11000f41216SHongyu Chen } 11100f41216SHongyu Chen 11200f41216SHongyu Chen Error VTuneSupportPlugin::notifyEmitted(MaterializationResponsibility &MR) { 11300f41216SHongyu Chen if (auto Err = MR.withResourceKeyDo([this, MR = &MR](ResourceKey K) { 11400f41216SHongyu Chen std::lock_guard<std::mutex> Lock(PluginMutex); 11500f41216SHongyu Chen auto I = PendingMethodIDs.find(MR); 11600f41216SHongyu Chen if (I == PendingMethodIDs.end()) 11700f41216SHongyu Chen return; 11800f41216SHongyu Chen 11900f41216SHongyu Chen LoadedMethodIDs[K].push_back(I->second); 12000f41216SHongyu Chen PendingMethodIDs.erase(I); 12100f41216SHongyu Chen })) { 12200f41216SHongyu Chen return Err; 12300f41216SHongyu Chen } 12400f41216SHongyu Chen return Error::success(); 12500f41216SHongyu Chen } 12600f41216SHongyu Chen 12700f41216SHongyu Chen Error VTuneSupportPlugin::notifyFailed(MaterializationResponsibility &MR) { 12800f41216SHongyu Chen std::lock_guard<std::mutex> Lock(PluginMutex); 12900f41216SHongyu Chen PendingMethodIDs.erase(&MR); 13000f41216SHongyu Chen return Error::success(); 13100f41216SHongyu Chen } 13200f41216SHongyu Chen 13300f41216SHongyu Chen Error VTuneSupportPlugin::notifyRemovingResources(JITDylib &JD, ResourceKey K) { 13400f41216SHongyu Chen // Unregistration not required if not provided 13500f41216SHongyu Chen if (!UnregisterVTuneImplAddr) { 13600f41216SHongyu Chen return Error::success(); 13700f41216SHongyu Chen } 13800f41216SHongyu Chen VTuneUnloadedMethodIDs UnloadedIDs; 13900f41216SHongyu Chen { 14000f41216SHongyu Chen std::lock_guard<std::mutex> Lock(PluginMutex); 14100f41216SHongyu Chen auto I = LoadedMethodIDs.find(K); 14200f41216SHongyu Chen if (I == LoadedMethodIDs.end()) 14300f41216SHongyu Chen return Error::success(); 14400f41216SHongyu Chen 14500f41216SHongyu Chen UnloadedIDs = std::move(I->second); 14600f41216SHongyu Chen LoadedMethodIDs.erase(I); 14700f41216SHongyu Chen } 14800f41216SHongyu Chen if (auto Err = EPC.callSPSWrapper<void(shared::SPSVTuneUnloadedMethodIDs)>( 14900f41216SHongyu Chen UnregisterVTuneImplAddr, UnloadedIDs)) 15000f41216SHongyu Chen return Err; 15100f41216SHongyu Chen 15200f41216SHongyu Chen return Error::success(); 15300f41216SHongyu Chen } 15400f41216SHongyu Chen 15500f41216SHongyu Chen void VTuneSupportPlugin::notifyTransferringResources(JITDylib &JD, 15600f41216SHongyu Chen ResourceKey DstKey, 15700f41216SHongyu Chen ResourceKey SrcKey) { 15800f41216SHongyu Chen std::lock_guard<std::mutex> Lock(PluginMutex); 15900f41216SHongyu Chen auto I = LoadedMethodIDs.find(SrcKey); 16000f41216SHongyu Chen if (I == LoadedMethodIDs.end()) 16100f41216SHongyu Chen return; 16200f41216SHongyu Chen 16300f41216SHongyu Chen auto &Dest = LoadedMethodIDs[DstKey]; 16400f41216SHongyu Chen Dest.insert(Dest.end(), I->second.begin(), I->second.end()); 16500f41216SHongyu Chen LoadedMethodIDs.erase(SrcKey); 16600f41216SHongyu Chen } 16700f41216SHongyu Chen 16800f41216SHongyu Chen Expected<std::unique_ptr<VTuneSupportPlugin>> 16900f41216SHongyu Chen VTuneSupportPlugin::Create(ExecutorProcessControl &EPC, JITDylib &JD, 17000f41216SHongyu Chen bool EmitDebugInfo, bool TestMode) { 17100f41216SHongyu Chen auto &ES = EPC.getExecutionSession(); 17200f41216SHongyu Chen auto RegisterImplName = 17300f41216SHongyu Chen ES.intern(TestMode ? RegisterTestVTuneImplName : RegisterVTuneImplName); 17400f41216SHongyu Chen auto UnregisterImplName = ES.intern(UnregisterVTuneImplName); 17500f41216SHongyu Chen SymbolLookupSet SLS{RegisterImplName, UnregisterImplName}; 17600f41216SHongyu Chen auto Res = ES.lookup(makeJITDylibSearchOrder({&JD}), std::move(SLS)); 17700f41216SHongyu Chen if (!Res) 17800f41216SHongyu Chen return Res.takeError(); 17900f41216SHongyu Chen ExecutorAddr RegisterImplAddr( 18000f41216SHongyu Chen Res->find(RegisterImplName)->second.getAddress()); 18100f41216SHongyu Chen ExecutorAddr UnregisterImplAddr( 18200f41216SHongyu Chen Res->find(UnregisterImplName)->second.getAddress()); 18300f41216SHongyu Chen return std::make_unique<VTuneSupportPlugin>( 18400f41216SHongyu Chen EPC, RegisterImplAddr, UnregisterImplAddr, EmitDebugInfo); 18500f41216SHongyu Chen } 186