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
getMethodBatch(LinkGraph & G,bool EmitDebugInfo)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, Inserted] = Deduplicator.try_emplace(S);
43 if (Inserted) {
44 Batch.Strings.push_back(S.str());
45 I->second = Batch.Strings.size();
46 }
47 return I->second;
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->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(
75 DC->getLineInfoForAddress(SAddr).value_or(DILineInfo()).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
modifyPassConfig(MaterializationResponsibility & MR,LinkGraph & G,PassConfiguration & Config)85 void VTuneSupportPlugin::modifyPassConfig(MaterializationResponsibility &MR,
86 LinkGraph &G,
87 PassConfiguration &Config) {
88 Config.PostFixupPasses.push_back([this, MR = &MR](LinkGraph &G) {
89 // the object file is generated but not linked yet
90 auto Batch = getMethodBatch(G, EmitDebugInfo);
91 if (Batch.Methods.empty()) {
92 return Error::success();
93 }
94 {
95 std::lock_guard<std::mutex> Lock(PluginMutex);
96 uint64_t Allocated = Batch.Methods.size();
97 uint64_t Start = NextMethodID;
98 NextMethodID += Allocated;
99 for (size_t i = Start; i < NextMethodID; ++i) {
100 Batch.Methods[i - Start].MethodID = i;
101 }
102 this->PendingMethodIDs[MR] = {Start, Allocated};
103 }
104 G.allocActions().push_back(
105 {cantFail(shared::WrapperFunctionCall::Create<
106 shared::SPSArgList<shared::SPSVTuneMethodBatch>>(
107 RegisterVTuneImplAddr, Batch)),
108 {}});
109 return Error::success();
110 });
111 }
112
notifyEmitted(MaterializationResponsibility & MR)113 Error VTuneSupportPlugin::notifyEmitted(MaterializationResponsibility &MR) {
114 if (auto Err = MR.withResourceKeyDo([this, MR = &MR](ResourceKey K) {
115 std::lock_guard<std::mutex> Lock(PluginMutex);
116 auto I = PendingMethodIDs.find(MR);
117 if (I == PendingMethodIDs.end())
118 return;
119
120 LoadedMethodIDs[K].push_back(I->second);
121 PendingMethodIDs.erase(I);
122 })) {
123 return Err;
124 }
125 return Error::success();
126 }
127
notifyFailed(MaterializationResponsibility & MR)128 Error VTuneSupportPlugin::notifyFailed(MaterializationResponsibility &MR) {
129 std::lock_guard<std::mutex> Lock(PluginMutex);
130 PendingMethodIDs.erase(&MR);
131 return Error::success();
132 }
133
notifyRemovingResources(JITDylib & JD,ResourceKey K)134 Error VTuneSupportPlugin::notifyRemovingResources(JITDylib &JD, ResourceKey K) {
135 // Unregistration not required if not provided
136 if (!UnregisterVTuneImplAddr) {
137 return Error::success();
138 }
139 VTuneUnloadedMethodIDs UnloadedIDs;
140 {
141 std::lock_guard<std::mutex> Lock(PluginMutex);
142 auto I = LoadedMethodIDs.find(K);
143 if (I == LoadedMethodIDs.end())
144 return Error::success();
145
146 UnloadedIDs = std::move(I->second);
147 LoadedMethodIDs.erase(I);
148 }
149 if (auto Err = EPC.callSPSWrapper<void(shared::SPSVTuneUnloadedMethodIDs)>(
150 UnregisterVTuneImplAddr, UnloadedIDs))
151 return Err;
152
153 return Error::success();
154 }
155
notifyTransferringResources(JITDylib & JD,ResourceKey DstKey,ResourceKey SrcKey)156 void VTuneSupportPlugin::notifyTransferringResources(JITDylib &JD,
157 ResourceKey DstKey,
158 ResourceKey SrcKey) {
159 std::lock_guard<std::mutex> Lock(PluginMutex);
160 auto I = LoadedMethodIDs.find(SrcKey);
161 if (I == LoadedMethodIDs.end())
162 return;
163
164 auto &Dest = LoadedMethodIDs[DstKey];
165 llvm::append_range(Dest, I->second);
166 LoadedMethodIDs.erase(SrcKey);
167 }
168
169 Expected<std::unique_ptr<VTuneSupportPlugin>>
Create(ExecutorProcessControl & EPC,JITDylib & JD,bool EmitDebugInfo,bool TestMode)170 VTuneSupportPlugin::Create(ExecutorProcessControl &EPC, JITDylib &JD,
171 bool EmitDebugInfo, bool TestMode) {
172 auto &ES = EPC.getExecutionSession();
173 auto RegisterImplName =
174 ES.intern(TestMode ? RegisterTestVTuneImplName : RegisterVTuneImplName);
175 auto UnregisterImplName = ES.intern(UnregisterVTuneImplName);
176 SymbolLookupSet SLS{RegisterImplName, UnregisterImplName};
177 auto Res = ES.lookup(makeJITDylibSearchOrder({&JD}), std::move(SLS));
178 if (!Res)
179 return Res.takeError();
180 ExecutorAddr RegisterImplAddr(
181 Res->find(RegisterImplName)->second.getAddress());
182 ExecutorAddr UnregisterImplAddr(
183 Res->find(UnregisterImplName)->second.getAddress());
184 return std::make_unique<VTuneSupportPlugin>(
185 EPC, RegisterImplAddr, UnregisterImplAddr, EmitDebugInfo);
186 }
187