Skip to content

Commit 00f4121

Browse files
author
Hongyu Chen
authored
[ORC][JITLink] Add Intel VTune support to JITLink (#83957)
[ORC] Re-land #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.
1 parent 9f96db8 commit 00f4121

File tree

10 files changed

+691
-1
lines changed

10 files changed

+691
-1
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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_DEBUGGING_VTUNESUPPORT_H
14+
#define LLVM_EXECUTIONENGINE_ORC_DEBUGGING_VTUNESUPPORT_H
15+
16+
#include "llvm/ADT/DenseMap.h"
17+
#include "llvm/ADT/SmallVector.h"
18+
#include "llvm/ExecutionEngine/Orc/Core.h"
19+
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
20+
#include "llvm/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h"
21+
#include "llvm/ExecutionEngine/Orc/Shared/VTuneSharedStructs.h"
22+
23+
namespace llvm {
24+
25+
namespace orc {
26+
27+
class VTuneSupportPlugin : public ObjectLinkingLayer::Plugin {
28+
public:
29+
VTuneSupportPlugin(ExecutorProcessControl &EPC, ExecutorAddr RegisterImplAddr,
30+
ExecutorAddr UnregisterImplAddr, bool EmitDebugInfo)
31+
: EPC(EPC), RegisterVTuneImplAddr(RegisterImplAddr),
32+
UnregisterVTuneImplAddr(UnregisterImplAddr),
33+
EmitDebugInfo(EmitDebugInfo) {}
34+
35+
void modifyPassConfig(MaterializationResponsibility &MR,
36+
jitlink::LinkGraph &G,
37+
jitlink::PassConfiguration &Config) override;
38+
39+
Error notifyEmitted(MaterializationResponsibility &MR) override;
40+
Error notifyFailed(MaterializationResponsibility &MR) override;
41+
Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override;
42+
void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,
43+
ResourceKey SrcKey) override;
44+
45+
static Expected<std::unique_ptr<VTuneSupportPlugin>>
46+
Create(ExecutorProcessControl &EPC, JITDylib &JD, bool EmitDebugInfo,
47+
bool TestMode = false);
48+
49+
private:
50+
ExecutorProcessControl &EPC;
51+
ExecutorAddr RegisterVTuneImplAddr;
52+
ExecutorAddr UnregisterVTuneImplAddr;
53+
std::mutex PluginMutex;
54+
uint64_t NextMethodID = 0;
55+
DenseMap<MaterializationResponsibility *, std::pair<uint64_t, uint64_t>>
56+
PendingMethodIDs;
57+
DenseMap<ResourceKey, SmallVector<std::pair<uint64_t, uint64_t>>>
58+
LoadedMethodIDs;
59+
bool EmitDebugInfo;
60+
};
61+
62+
} // end namespace orc
63+
64+
} // end namespace llvm
65+
66+
#endif
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
//===-------------------- VTuneSharedStructs.h ------------------*- 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+
// Structs and serialization to share VTune-related information
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_VTUNESHAREDSTRUCTS_H
14+
#define LLVM_EXECUTIONENGINE_ORC_SHARED_VTUNESHAREDSTRUCTS_H
15+
16+
namespace llvm {
17+
namespace orc {
18+
19+
using VTuneLineTable = std::vector<std::pair<unsigned, unsigned>>;
20+
21+
// SI = String Index, 1-indexed into the VTuneMethodBatch::Strings table.
22+
// SI == 0 means replace with nullptr.
23+
24+
// MI = Method Index, 1-indexed into the VTuneMethodBatch::Methods table.
25+
// MI == 0 means this is a parent method and was not inlined.
26+
27+
struct VTuneMethodInfo {
28+
VTuneLineTable LineTable;
29+
ExecutorAddr LoadAddr;
30+
uint64_t LoadSize;
31+
uint64_t MethodID;
32+
uint32_t NameSI;
33+
uint32_t ClassFileSI;
34+
uint32_t SourceFileSI;
35+
uint32_t ParentMI;
36+
};
37+
38+
using VTuneMethodTable = std::vector<VTuneMethodInfo>;
39+
using VTuneStringTable = std::vector<std::string>;
40+
41+
struct VTuneMethodBatch {
42+
VTuneMethodTable Methods;
43+
VTuneStringTable Strings;
44+
};
45+
46+
using VTuneUnloadedMethodIDs = SmallVector<std::pair<uint64_t, uint64_t>>;
47+
48+
namespace shared {
49+
50+
using SPSVTuneLineTable = SPSSequence<SPSTuple<uint32_t, uint32_t>>;
51+
using SPSVTuneMethodInfo =
52+
SPSTuple<SPSVTuneLineTable, SPSExecutorAddr, uint64_t, uint64_t, uint32_t,
53+
uint32_t, uint32_t, uint32_t>;
54+
using SPSVTuneMethodTable = SPSSequence<SPSVTuneMethodInfo>;
55+
using SPSVTuneStringTable = SPSSequence<SPSString>;
56+
using SPSVTuneMethodBatch = SPSTuple<SPSVTuneMethodTable, SPSVTuneStringTable>;
57+
using SPSVTuneUnloadedMethodIDs = SPSSequence<SPSTuple<uint64_t, uint64_t>>;
58+
59+
template <> class SPSSerializationTraits<SPSVTuneMethodInfo, VTuneMethodInfo> {
60+
public:
61+
static size_t size(const VTuneMethodInfo &MI) {
62+
return SPSVTuneMethodInfo::AsArgList::size(
63+
MI.LineTable, MI.LoadAddr, MI.LoadSize, MI.MethodID, MI.NameSI,
64+
MI.ClassFileSI, MI.SourceFileSI, MI.ParentMI);
65+
}
66+
67+
static bool deserialize(SPSInputBuffer &IB, VTuneMethodInfo &MI) {
68+
return SPSVTuneMethodInfo::AsArgList::deserialize(
69+
IB, MI.LineTable, MI.LoadAddr, MI.LoadSize, MI.MethodID, MI.NameSI,
70+
MI.ClassFileSI, MI.SourceFileSI, MI.ParentMI);
71+
}
72+
73+
static bool serialize(SPSOutputBuffer &OB, const VTuneMethodInfo &MI) {
74+
return SPSVTuneMethodInfo::AsArgList::serialize(
75+
OB, MI.LineTable, MI.LoadAddr, MI.LoadSize, MI.MethodID, MI.NameSI,
76+
MI.ClassFileSI, MI.SourceFileSI, MI.ParentMI);
77+
}
78+
};
79+
80+
template <>
81+
class SPSSerializationTraits<SPSVTuneMethodBatch, VTuneMethodBatch> {
82+
public:
83+
static size_t size(const VTuneMethodBatch &MB) {
84+
return SPSVTuneMethodBatch::AsArgList::size(MB.Methods, MB.Strings);
85+
}
86+
87+
static bool deserialize(SPSInputBuffer &IB, VTuneMethodBatch &MB) {
88+
return SPSVTuneMethodBatch::AsArgList::deserialize(IB, MB.Methods,
89+
MB.Strings);
90+
}
91+
92+
static bool serialize(SPSOutputBuffer &OB, const VTuneMethodBatch &MB) {
93+
return SPSVTuneMethodBatch::AsArgList::serialize(OB, MB.Methods,
94+
MB.Strings);
95+
}
96+
};
97+
98+
} // end namespace shared
99+
} // end namespace orc
100+
} // end namespace llvm
101+
102+
#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: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
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+
static constexpr StringRef RegisterVTuneImplName = "llvm_orc_registerVTuneImpl";
21+
static constexpr StringRef UnregisterVTuneImplName =
22+
"llvm_orc_unregisterVTuneImpl";
23+
static constexpr StringRef RegisterTestVTuneImplName =
24+
"llvm_orc_test_registerVTuneImpl";
25+
26+
static VTuneMethodBatch getMethodBatch(LinkGraph &G, bool EmitDebugInfo) {
27+
VTuneMethodBatch Batch;
28+
std::unique_ptr<DWARFContext> DC;
29+
StringMap<std::unique_ptr<MemoryBuffer>> DCBacking;
30+
if (EmitDebugInfo) {
31+
auto EDC = createDWARFContext(G);
32+
if (!EDC) {
33+
EmitDebugInfo = false;
34+
} else {
35+
DC = std::move(EDC->first);
36+
DCBacking = std::move(EDC->second);
37+
}
38+
}
39+
40+
auto GetStringIdx = [Deduplicator = StringMap<uint32_t>(),
41+
&Batch](StringRef S) mutable {
42+
auto I = Deduplicator.find(S);
43+
if (I != Deduplicator.end())
44+
return I->second;
45+
46+
Batch.Strings.push_back(S.str());
47+
return Deduplicator[S] = Batch.Strings.size();
48+
};
49+
for (auto Sym : G.defined_symbols()) {
50+
if (!Sym->isCallable())
51+
continue;
52+
53+
Batch.Methods.push_back(VTuneMethodInfo());
54+
auto &Method = Batch.Methods.back();
55+
Method.MethodID = 0;
56+
Method.ParentMI = 0;
57+
Method.LoadAddr = Sym->getAddress();
58+
Method.LoadSize = Sym->getSize();
59+
Method.NameSI = GetStringIdx(Sym->getName());
60+
Method.ClassFileSI = 0;
61+
Method.SourceFileSI = 0;
62+
63+
if (!EmitDebugInfo)
64+
continue;
65+
66+
auto &Section = Sym->getBlock().getSection();
67+
auto Addr = Sym->getAddress();
68+
auto SAddr =
69+
object::SectionedAddress{Addr.getValue(), Section.getOrdinal()};
70+
DILineInfoTable LinesInfo = DC->getLineInfoForAddressRange(
71+
SAddr, Sym->getSize(),
72+
DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath);
73+
Method.SourceFileSI = Batch.Strings.size();
74+
Batch.Strings.push_back(DC->getLineInfoForAddress(SAddr).FileName);
75+
for (auto &LInfo : LinesInfo) {
76+
Method.LineTable.push_back(
77+
std::pair<unsigned, unsigned>{/*unsigned*/ Sym->getOffset(),
78+
/*DILineInfo*/ LInfo.second.Line});
79+
}
80+
}
81+
return Batch;
82+
}
83+
84+
void VTuneSupportPlugin::modifyPassConfig(MaterializationResponsibility &MR,
85+
LinkGraph &G,
86+
PassConfiguration &Config) {
87+
Config.PostFixupPasses.push_back([this, MR = &MR](LinkGraph &G) {
88+
// the object file is generated but not linked yet
89+
auto Batch = getMethodBatch(G, EmitDebugInfo);
90+
if (Batch.Methods.empty()) {
91+
return Error::success();
92+
}
93+
{
94+
std::lock_guard<std::mutex> Lock(PluginMutex);
95+
uint64_t Allocated = Batch.Methods.size();
96+
uint64_t Start = NextMethodID;
97+
NextMethodID += Allocated;
98+
for (size_t i = Start; i < NextMethodID; ++i) {
99+
Batch.Methods[i - Start].MethodID = i;
100+
}
101+
this->PendingMethodIDs[MR] = {Start, Allocated};
102+
}
103+
G.allocActions().push_back(
104+
{cantFail(shared::WrapperFunctionCall::Create<
105+
shared::SPSArgList<shared::SPSVTuneMethodBatch>>(
106+
RegisterVTuneImplAddr, Batch)),
107+
{}});
108+
return Error::success();
109+
});
110+
}
111+
112+
Error VTuneSupportPlugin::notifyEmitted(MaterializationResponsibility &MR) {
113+
if (auto Err = MR.withResourceKeyDo([this, MR = &MR](ResourceKey K) {
114+
std::lock_guard<std::mutex> Lock(PluginMutex);
115+
auto I = PendingMethodIDs.find(MR);
116+
if (I == PendingMethodIDs.end())
117+
return;
118+
119+
LoadedMethodIDs[K].push_back(I->second);
120+
PendingMethodIDs.erase(I);
121+
})) {
122+
return Err;
123+
}
124+
return Error::success();
125+
}
126+
127+
Error VTuneSupportPlugin::notifyFailed(MaterializationResponsibility &MR) {
128+
std::lock_guard<std::mutex> Lock(PluginMutex);
129+
PendingMethodIDs.erase(&MR);
130+
return Error::success();
131+
}
132+
133+
Error VTuneSupportPlugin::notifyRemovingResources(JITDylib &JD, ResourceKey K) {
134+
// Unregistration not required if not provided
135+
if (!UnregisterVTuneImplAddr) {
136+
return Error::success();
137+
}
138+
VTuneUnloadedMethodIDs UnloadedIDs;
139+
{
140+
std::lock_guard<std::mutex> Lock(PluginMutex);
141+
auto I = LoadedMethodIDs.find(K);
142+
if (I == LoadedMethodIDs.end())
143+
return Error::success();
144+
145+
UnloadedIDs = std::move(I->second);
146+
LoadedMethodIDs.erase(I);
147+
}
148+
if (auto Err = EPC.callSPSWrapper<void(shared::SPSVTuneUnloadedMethodIDs)>(
149+
UnregisterVTuneImplAddr, UnloadedIDs))
150+
return Err;
151+
152+
return Error::success();
153+
}
154+
155+
void VTuneSupportPlugin::notifyTransferringResources(JITDylib &JD,
156+
ResourceKey DstKey,
157+
ResourceKey SrcKey) {
158+
std::lock_guard<std::mutex> Lock(PluginMutex);
159+
auto I = LoadedMethodIDs.find(SrcKey);
160+
if (I == LoadedMethodIDs.end())
161+
return;
162+
163+
auto &Dest = LoadedMethodIDs[DstKey];
164+
Dest.insert(Dest.end(), I->second.begin(), I->second.end());
165+
LoadedMethodIDs.erase(SrcKey);
166+
}
167+
168+
Expected<std::unique_ptr<VTuneSupportPlugin>>
169+
VTuneSupportPlugin::Create(ExecutorProcessControl &EPC, JITDylib &JD,
170+
bool EmitDebugInfo, bool TestMode) {
171+
auto &ES = EPC.getExecutionSession();
172+
auto RegisterImplName =
173+
ES.intern(TestMode ? RegisterTestVTuneImplName : RegisterVTuneImplName);
174+
auto UnregisterImplName = ES.intern(UnregisterVTuneImplName);
175+
SymbolLookupSet SLS{RegisterImplName, UnregisterImplName};
176+
auto Res = ES.lookup(makeJITDylibSearchOrder({&JD}), std::move(SLS));
177+
if (!Res)
178+
return Res.takeError();
179+
ExecutorAddr RegisterImplAddr(
180+
Res->find(RegisterImplName)->second.getAddress());
181+
ExecutorAddr UnregisterImplAddr(
182+
Res->find(UnregisterImplName)->second.getAddress());
183+
return std::make_unique<VTuneSupportPlugin>(
184+
EPC, RegisterImplAddr, UnregisterImplAddr, EmitDebugInfo);
185+
}

0 commit comments

Comments
 (0)