diff --git a/llvm/include/llvm/ExecutionEngine/Orc/VTuneSupportPlugin.h b/llvm/include/llvm/ExecutionEngine/Orc/VTuneSupportPlugin.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/ExecutionEngine/Orc/VTuneSupportPlugin.h @@ -0,0 +1,144 @@ +//===--- VTuneSupportPlugin.h -- Support for VTune profiler ---*- C++ -*---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Handles support for registering code with VIntel Tune's Amplifier JIT API. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_AMPLIFIERSUPPORTPLUGIN_H +#define LLVM_EXECUTIONENGINE_ORC_AMPLIFIERSUPPORTPLUGIN_H + +#include "llvm/ExecutionEngine/Orc/Core.h" +#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" + +#include "llvm/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h" + +namespace llvm { + +namespace orc { + +class VTuneSupportPlugin : public ObjectLinkingLayer::Plugin { +public: + VTuneSupportPlugin(ExecutorProcessControl &EPC, ExecutorAddr RegisterImplAddr, + ExecutorAddr UnregisterImplAddr, bool EmitDebugInfo) + : EPC(EPC), RegisterVTuneImplAddr(RegisterImplAddr), + UnregisterVTuneImplAddr(UnregisterImplAddr), + EmitDebugInfo(EmitDebugInfo) {} + + void modifyPassConfig(MaterializationResponsibility &MR, + jitlink::LinkGraph &G, + jitlink::PassConfiguration &Config) override; + + Error notifyEmitted(MaterializationResponsibility &MR) override; + Error notifyFailed(MaterializationResponsibility &MR) override; + Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override; + void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey, + ResourceKey SrcKey) override; + + static Expected> + Create(ExecutorProcessControl &EPC, JITDylib &JD, bool EmitDebugInfo); + +private: + ExecutorProcessControl &EPC; + ExecutorAddr RegisterVTuneImplAddr; + ExecutorAddr UnregisterVTuneImplAddr; + std::mutex PluginMutex; + uint64_t NextMethodID{0}; + DenseMap> + PendingMethodIDs; + DenseMap>> + LoadedMethodIDs; + bool EmitDebugInfo; +}; + +typedef std::vector> VTuneLineTable; + +// SI = String Index, 1-indexed into the VTuneMethodBatch::Strings table. +// SI == 0 means replace with nullptr. + +// MI = Method Index, 1-indexed into the VTuneMethodBatch::Methods table. +// MI == 0 means this is a parent method and was not inlined. + +struct VTuneMethodInfo { + VTuneLineTable LineTable; + ExecutorAddr LoadAddr; + uint64_t LoadSize; + uint64_t MethodID; + uint32_t NameSI; + uint32_t ClassFileSI; + uint32_t SourceFileSI; + uint32_t ParentMI; +}; + +typedef std::vector VTuneMethodTable; +typedef std::vector VTuneStringTable; + +struct VTuneMethodBatch { + VTuneMethodTable Methods; + VTuneStringTable Strings; +}; + +typedef std::vector> VTuneUnloadedMethodIDs; + +namespace shared { + +using SPSVTuneLineTable = SPSSequence>; +using SPSVTuneMethodInfo = + SPSTuple; +using SPSVTuneMethodTable = SPSSequence; +using SPSVTuneStringTable = SPSSequence; +using SPSVTuneMethodBatch = SPSTuple; +using SPSVTuneUnloadedMethodIDs = SPSSequence>; + +template <> class SPSSerializationTraits { +public: + static size_t size(const VTuneMethodInfo &MI) { + return SPSVTuneMethodInfo::AsArgList::size( + MI.LineTable, MI.LoadAddr, MI.LoadSize, MI.MethodID, MI.NameSI, + MI.ClassFileSI, MI.SourceFileSI, MI.ParentMI); + } + + static bool deserialize(SPSInputBuffer &IB, VTuneMethodInfo &MI) { + return SPSVTuneMethodInfo::AsArgList::deserialize( + IB, MI.LineTable, MI.LoadAddr, MI.LoadSize, MI.MethodID, MI.NameSI, + MI.ClassFileSI, MI.SourceFileSI, MI.ParentMI); + } + + static bool serialize(SPSOutputBuffer &OB, const VTuneMethodInfo &MI) { + return SPSVTuneMethodInfo::AsArgList::serialize( + OB, MI.LineTable, MI.LoadAddr, MI.LoadSize, MI.MethodID, MI.NameSI, + MI.ClassFileSI, MI.SourceFileSI, MI.ParentMI); + } +}; + +template <> +class SPSSerializationTraits { +public: + static size_t size(const VTuneMethodBatch &MB) { + return SPSVTuneMethodBatch::AsArgList::size(MB.Methods, MB.Strings); + } + + static bool deserialize(SPSInputBuffer &IB, VTuneMethodBatch &MB) { + return SPSVTuneMethodBatch::AsArgList::deserialize(IB, MB.Methods, + MB.Strings); + } + + static bool serialize(SPSOutputBuffer &OB, const VTuneMethodBatch &MB) { + return SPSVTuneMethodBatch::AsArgList::serialize(OB, MB.Methods, + MB.Strings); + } +}; + +} // end namespace shared + +} // end namespace orc + +} // end namespace llvm + +#endif diff --git a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt --- a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt +++ b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt @@ -46,6 +46,7 @@ ExecutorProcessControl.cpp TaskDispatch.cpp ThreadSafeModule.cpp + VTuneSupportPlugin.cpp ADDITIONAL_HEADER_DIRS ${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc diff --git a/llvm/lib/ExecutionEngine/Orc/VTuneSupportPlugin.cpp b/llvm/lib/ExecutionEngine/Orc/VTuneSupportPlugin.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/ExecutionEngine/Orc/VTuneSupportPlugin.cpp @@ -0,0 +1,162 @@ +//===--- VTuneSupportPlugin.cpp -- Support for VTune profiler --*- C++ -*--===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Handles support for registering code with VIntel Tune's Amplfiier JIT API. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ExecutionEngine/Orc/VTuneSupportPlugin.h" + +#include "llvm/ExecutionEngine/Orc/DebugInfoSupport.h" + +using namespace llvm; +using namespace llvm::orc; +using namespace llvm::jitlink; + +namespace { + +constexpr StringRef RegisterVTuneImplName = "llvm_orc_registerVTuneImpl"; +constexpr StringRef UnregisterVTuneImplName = "llvm_orc_unregisterVTuneImpl"; + +static VTuneMethodBatch getMethodBatch(LinkGraph &G, bool EmitDebugInfo) { + VTuneMethodBatch Batch; + auto GetStringIdx = [Deduplicator = StringMap(), + &Batch](StringRef S) mutable { + auto I = Deduplicator.find(S); + if (I != Deduplicator.end()) { + return I->second; + } + Batch.Strings.push_back(S.str()); + return Deduplicator[S] = Batch.Strings.size(); + }; + for (auto Sym : G.defined_symbols()) { + if (!Sym->isCallable()) { + continue; + } + + Batch.Methods.push_back(VTuneMethodInfo()); + auto &Method = Batch.Methods.back(); + Method.MethodID = 0; + Method.ParentMI = 0; + Method.LoadAddr = Sym->getAddress(); + Method.LoadSize = Sym->getSize(); + Method.NameSI = GetStringIdx(Sym->getName()); + Method.ClassFileSI = 0; + Method.SourceFileSI = 0; + + if (!EmitDebugInfo) { + continue; + } + + // TODO: Emit debug info + } + return Batch; +} + +} // namespace + +void VTuneSupportPlugin::modifyPassConfig(MaterializationResponsibility &MR, + LinkGraph &G, + PassConfiguration &Config) { + Config.PostFixupPasses.push_back([this, MR = &MR](LinkGraph &G) { + auto Batch = getMethodBatch(G, EmitDebugInfo); + if (Batch.Methods.empty()) { + // Nothing to do. + return Error::success(); + } + { + std::lock_guard Lock(PluginMutex); + uint64_t Allocated = Batch.Methods.size(); + uint64_t Start = NextMethodID; + NextMethodID += Allocated; + for (auto &M : Batch.Methods) { + M.MethodID = Start++; + } + this->PendingMethodIDs[MR] = {Start, Allocated}; + } + G.allocActions().push_back( + {cantFail(shared::WrapperFunctionCall::Create< + shared::SPSArgList>( + RegisterVTuneImplAddr, Batch)), + {}}); + return Error::success(); + }); +} + +Error VTuneSupportPlugin::notifyEmitted(MaterializationResponsibility &MR) { + if (auto Err = MR.withResourceKeyDo([this, MR = &MR](ResourceKey K) { + std::lock_guard Lock(PluginMutex); + auto I = PendingMethodIDs.find(MR); + if (I == PendingMethodIDs.end()) { + return; + } + LoadedMethodIDs[K].push_back(I->second); + PendingMethodIDs.erase(I); + })) { + return Err; + } + return Error::success(); +} + +Error VTuneSupportPlugin::notifyFailed(MaterializationResponsibility &MR) { + std::lock_guard Lock(PluginMutex); + PendingMethodIDs.erase(&MR); + return Error::success(); +} + +Error VTuneSupportPlugin::notifyRemovingResources(JITDylib &JD, ResourceKey K) { + // Unregistration not required if not provided + if (!UnregisterVTuneImplAddr) { + return Error::success(); + } + VTuneUnloadedMethodIDs UnloadedIDs; + { + std::lock_guard Lock(PluginMutex); + auto I = LoadedMethodIDs.find(K); + if (I == LoadedMethodIDs.end()) { + return Error::success(); + } + UnloadedIDs = std::move(I->second); + LoadedMethodIDs.erase(I); + } + if (auto Err = EPC.callSPSWrapper( + UnregisterVTuneImplAddr, UnloadedIDs)) { + return Err; + } + return Error::success(); +} + +void VTuneSupportPlugin::notifyTransferringResources(JITDylib &JD, + ResourceKey DstKey, + ResourceKey SrcKey) { + std::lock_guard Lock(PluginMutex); + auto I = LoadedMethodIDs.find(SrcKey); + if (I == LoadedMethodIDs.end()) { + return; + } + auto &Dest = LoadedMethodIDs[DstKey]; + Dest.insert(Dest.end(), I->second.begin(), I->second.end()); +} + +Expected> +VTuneSupportPlugin::Create(ExecutorProcessControl &EPC, JITDylib &JD, + bool EmitDebugInfo) { + auto &ES = EPC.getExecutionSession(); + auto RegisterImplName = ES.intern(RegisterVTuneImplName); + auto UnregisterImplName = ES.intern(UnregisterVTuneImplName); + SymbolLookupSet SLS{RegisterImplName, UnregisterImplName}; + auto Res = ES.lookup(makeJITDylibSearchOrder({&JD}), std::move(SLS)); + if (!Res) + return Res.takeError(); + ExecutorAddr RegisterImplAddr( + Res->find(RegisterImplName)->second.getAddress()); + ExecutorAddr UnregisterImplAddr( + Res->find(UnregisterImplName)->second.getAddress()); + return std::make_unique( + EPC, RegisterImplAddr, UnregisterImplAddr, EmitDebugInfo); +}