Skip to content

Commit 17efdad

Browse files
authored
[ORC][JITLink] Add Intel VTune support to JITLink (llvm#81826)
This patch adds two plugins: VTuneSupportPlugin.cpp and JITLoaderVTune.cpp. The testing is done in a manner similar to llvm-jitlistener. Currently, we only support the old version of Intel VTune API. This pull request is stacked on top of llvm#81825
1 parent bc9c6c0 commit 17efdad

File tree

9 files changed

+663
-1
lines changed

9 files changed

+663
-1
lines changed
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
//===--- VTuneSupportPlugin.h -- 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 Amplifier JIT API.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_EXECUTIONENGINE_ORC_AMPLIFIERSUPPORTPLUGIN_H
14+
#define LLVM_EXECUTIONENGINE_ORC_AMPLIFIERSUPPORTPLUGIN_H
15+
16+
#include "llvm/ExecutionEngine/Orc/Core.h"
17+
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
18+
19+
#include "llvm/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h"
20+
21+
namespace llvm {
22+
23+
namespace orc {
24+
25+
class VTuneSupportPlugin : public ObjectLinkingLayer::Plugin {
26+
public:
27+
VTuneSupportPlugin(ExecutorProcessControl &EPC, ExecutorAddr RegisterImplAddr,
28+
ExecutorAddr UnregisterImplAddr, bool EmitDebugInfo)
29+
: EPC(EPC), RegisterVTuneImplAddr(RegisterImplAddr),
30+
UnregisterVTuneImplAddr(UnregisterImplAddr),
31+
EmitDebugInfo(EmitDebugInfo) {}
32+
33+
void modifyPassConfig(MaterializationResponsibility &MR,
34+
jitlink::LinkGraph &G,
35+
jitlink::PassConfiguration &Config) override;
36+
37+
Error notifyEmitted(MaterializationResponsibility &MR) override;
38+
Error notifyFailed(MaterializationResponsibility &MR) override;
39+
Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override;
40+
void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,
41+
ResourceKey SrcKey) override;
42+
43+
static Expected<std::unique_ptr<VTuneSupportPlugin>>
44+
Create(ExecutorProcessControl &EPC, JITDylib &JD, bool EmitDebugInfo,
45+
bool TestMode = false);
46+
47+
private:
48+
ExecutorProcessControl &EPC;
49+
ExecutorAddr RegisterVTuneImplAddr;
50+
ExecutorAddr UnregisterVTuneImplAddr;
51+
std::mutex PluginMutex;
52+
uint64_t NextMethodID{0};
53+
DenseMap<MaterializationResponsibility *, std::pair<uint64_t, uint64_t>>
54+
PendingMethodIDs;
55+
DenseMap<ResourceKey, std::vector<std::pair<uint64_t, uint64_t>>>
56+
LoadedMethodIDs;
57+
bool EmitDebugInfo;
58+
};
59+
60+
typedef std::vector<std::pair<unsigned, unsigned>> VTuneLineTable;
61+
62+
// SI = String Index, 1-indexed into the VTuneMethodBatch::Strings table.
63+
// SI == 0 means replace with nullptr.
64+
65+
// MI = Method Index, 1-indexed into the VTuneMethodBatch::Methods table.
66+
// MI == 0 means this is a parent method and was not inlined.
67+
68+
struct VTuneMethodInfo {
69+
VTuneLineTable LineTable;
70+
ExecutorAddr LoadAddr;
71+
uint64_t LoadSize;
72+
uint64_t MethodID;
73+
uint32_t NameSI;
74+
uint32_t ClassFileSI;
75+
uint32_t SourceFileSI;
76+
uint32_t ParentMI;
77+
};
78+
79+
typedef std::vector<VTuneMethodInfo> VTuneMethodTable;
80+
typedef std::vector<std::string> VTuneStringTable;
81+
82+
struct VTuneMethodBatch {
83+
VTuneMethodTable Methods;
84+
VTuneStringTable Strings;
85+
};
86+
87+
typedef std::vector<std::pair<uint64_t, uint64_t>> VTuneUnloadedMethodIDs;
88+
89+
namespace shared {
90+
91+
using SPSVTuneLineTable = SPSSequence<SPSTuple<uint32_t, uint32_t>>;
92+
using SPSVTuneMethodInfo =
93+
SPSTuple<SPSVTuneLineTable, SPSExecutorAddr, uint64_t, uint64_t, uint32_t,
94+
uint32_t, uint32_t, uint32_t>;
95+
using SPSVTuneMethodTable = SPSSequence<SPSVTuneMethodInfo>;
96+
using SPSVTuneStringTable = SPSSequence<SPSString>;
97+
using SPSVTuneMethodBatch = SPSTuple<SPSVTuneMethodTable, SPSVTuneStringTable>;
98+
using SPSVTuneUnloadedMethodIDs = SPSSequence<SPSTuple<uint64_t, uint64_t>>;
99+
100+
template <> class SPSSerializationTraits<SPSVTuneMethodInfo, VTuneMethodInfo> {
101+
public:
102+
static size_t size(const VTuneMethodInfo &MI) {
103+
return SPSVTuneMethodInfo::AsArgList::size(
104+
MI.LineTable, MI.LoadAddr, MI.LoadSize, MI.MethodID, MI.NameSI,
105+
MI.ClassFileSI, MI.SourceFileSI, MI.ParentMI);
106+
}
107+
108+
static bool deserialize(SPSInputBuffer &IB, VTuneMethodInfo &MI) {
109+
return SPSVTuneMethodInfo::AsArgList::deserialize(
110+
IB, MI.LineTable, MI.LoadAddr, MI.LoadSize, MI.MethodID, MI.NameSI,
111+
MI.ClassFileSI, MI.SourceFileSI, MI.ParentMI);
112+
}
113+
114+
static bool serialize(SPSOutputBuffer &OB, const VTuneMethodInfo &MI) {
115+
return SPSVTuneMethodInfo::AsArgList::serialize(
116+
OB, MI.LineTable, MI.LoadAddr, MI.LoadSize, MI.MethodID, MI.NameSI,
117+
MI.ClassFileSI, MI.SourceFileSI, MI.ParentMI);
118+
}
119+
};
120+
121+
template <>
122+
class SPSSerializationTraits<SPSVTuneMethodBatch, VTuneMethodBatch> {
123+
public:
124+
static size_t size(const VTuneMethodBatch &MB) {
125+
return SPSVTuneMethodBatch::AsArgList::size(MB.Methods, MB.Strings);
126+
}
127+
128+
static bool deserialize(SPSInputBuffer &IB, VTuneMethodBatch &MB) {
129+
return SPSVTuneMethodBatch::AsArgList::deserialize(IB, MB.Methods,
130+
MB.Strings);
131+
}
132+
133+
static bool serialize(SPSOutputBuffer &OB, const VTuneMethodBatch &MB) {
134+
return SPSVTuneMethodBatch::AsArgList::serialize(OB, MB.Methods,
135+
MB.Strings);
136+
}
137+
};
138+
139+
} // end namespace shared
140+
141+
} // end namespace orc
142+
143+
} // end namespace llvm
144+
145+
#endif
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
2+
//===------- JITLoaderVTune.h --- Register profiler objects ------*- C++ -*-===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// Register objects for access by profilers via the perf JIT interface.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_JITLOADERVTUNE_H
15+
#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_JITLOADERVTUNE_H
16+
17+
#include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
18+
#include <cstdint>
19+
20+
extern "C" llvm::orc::shared::CWrapperFunctionResult
21+
llvm_orc_registerVTuneImpl(const char *Data, uint64_t Size);
22+
23+
extern "C" llvm::orc::shared::CWrapperFunctionResult
24+
llvm_orc_unregisterVTuneImpl(const char *Data, uint64_t Size);
25+
26+
extern "C" llvm::orc::shared::CWrapperFunctionResult
27+
llvm_orc_test_registerVTuneImpl(const char *Data, uint64_t Size);
28+
29+
#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_JITLOADERVTUNE_H
30+
31+

llvm/lib/ExecutionEngine/Orc/Debugging/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ add_llvm_component_library(LLVMOrcDebugging
88
DebuggerSupportPlugin.cpp
99
LLJITUtilsCBindings.cpp
1010
PerfSupportPlugin.cpp
11+
VTuneSupportPlugin.cpp
1112

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

0 commit comments

Comments
 (0)