blob: de02a20524b9cb15a2bfc5b8d8aafc441bf4878e [file] [log] [blame]
//===--- 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/Debugging/VTuneSupportPlugin.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/ExecutionEngine/Orc/Debugging/DebugInfoSupport.h"
using namespace llvm;
using namespace llvm::orc;
using namespace llvm::jitlink;
static constexpr StringRef RegisterVTuneImplName = "llvm_orc_registerVTuneImpl";
static constexpr StringRef UnregisterVTuneImplName =
"llvm_orc_unregisterVTuneImpl";
static constexpr StringRef RegisterTestVTuneImplName =
"llvm_orc_test_registerVTuneImpl";
static VTuneMethodBatch getMethodBatch(LinkGraph &G, bool EmitDebugInfo) {
VTuneMethodBatch Batch;
std::unique_ptr<DWARFContext> DC;
StringMap<std::unique_ptr<MemoryBuffer>> DCBacking;
if (EmitDebugInfo) {
auto EDC = createDWARFContext(G);
if (!EDC) {
EmitDebugInfo = false;
} else {
DC = std::move(EDC->first);
DCBacking = std::move(EDC->second);
}
}
auto GetStringIdx = [Deduplicator = StringMap<uint32_t>(),
&Batch](StringRef S) mutable {
auto [I, Inserted] = Deduplicator.try_emplace(S);
if (Inserted) {
Batch.Strings.push_back(S.str());
I->second = Batch.Strings.size();
}
return I->second;
};
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;
auto &Section = Sym->getBlock().getSection();
auto Addr = Sym->getAddress();
auto SAddr =
object::SectionedAddress{Addr.getValue(), Section.getOrdinal()};
DILineInfoTable LinesInfo = DC->getLineInfoForAddressRange(
SAddr, Sym->getSize(),
DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath);
Method.SourceFileSI = Batch.Strings.size();
Batch.Strings.push_back(DC->getLineInfoForAddress(SAddr).FileName);
for (auto &LInfo : LinesInfo) {
Method.LineTable.push_back(
std::pair<unsigned, unsigned>{/*unsigned*/ Sym->getOffset(),
/*DILineInfo*/ LInfo.second.Line});
}
}
return Batch;
}
void VTuneSupportPlugin::modifyPassConfig(MaterializationResponsibility &MR,
LinkGraph &G,
PassConfiguration &Config) {
Config.PostFixupPasses.push_back([this, MR = &MR](LinkGraph &G) {
// the object file is generated but not linked yet
auto Batch = getMethodBatch(G, EmitDebugInfo);
if (Batch.Methods.empty()) {
return Error::success();
}
{
std::lock_guard<std::mutex> Lock(PluginMutex);
uint64_t Allocated = Batch.Methods.size();
uint64_t Start = NextMethodID;
NextMethodID += Allocated;
for (size_t i = Start; i < NextMethodID; ++i) {
Batch.Methods[i - Start].MethodID = i;
}
this->PendingMethodIDs[MR] = {Start, Allocated};
}
G.allocActions().push_back(
{cantFail(shared::WrapperFunctionCall::Create<
shared::SPSArgList<shared::SPSVTuneMethodBatch>>(
RegisterVTuneImplAddr, Batch)),
{}});
return Error::success();
});
}
Error VTuneSupportPlugin::notifyEmitted(MaterializationResponsibility &MR) {
if (auto Err = MR.withResourceKeyDo([this, MR = &MR](ResourceKey K) {
std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> 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<void(shared::SPSVTuneUnloadedMethodIDs)>(
UnregisterVTuneImplAddr, UnloadedIDs))
return Err;
return Error::success();
}
void VTuneSupportPlugin::notifyTransferringResources(JITDylib &JD,
ResourceKey DstKey,
ResourceKey SrcKey) {
std::lock_guard<std::mutex> 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());
LoadedMethodIDs.erase(SrcKey);
}
Expected<std::unique_ptr<VTuneSupportPlugin>>
VTuneSupportPlugin::Create(ExecutorProcessControl &EPC, JITDylib &JD,
bool EmitDebugInfo, bool TestMode) {
auto &ES = EPC.getExecutionSession();
auto RegisterImplName =
ES.intern(TestMode ? RegisterTestVTuneImplName : 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<VTuneSupportPlugin>(
EPC, RegisterImplAddr, UnregisterImplAddr, EmitDebugInfo);
}