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
16using namespace llvm;
17using namespace llvm::orc;
18using namespace llvm::jitlink;
19
20static constexpr StringRef RegisterVTuneImplName = "llvm_orc_registerVTuneImpl";
21static constexpr StringRef UnregisterVTuneImplName =
22 "llvm_orc_unregisterVTuneImpl";
23static constexpr StringRef RegisterTestVTuneImplName =
24 "llvm_orc_test_registerVTuneImpl";
25
26static 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(Key: S);
43 if (Inserted) {
44 Batch.Strings.push_back(x: 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(x: 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{.Address: Addr.getValue(), .SectionIndex: Section.getOrdinal()};
70 DILineInfoTable LinesInfo = DC->getLineInfoForAddressRange(
71 Address: SAddr, Size: Sym->getSize(),
72 Specifier: DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath);
73 Method.SourceFileSI = Batch.Strings.size();
74 Batch.Strings.push_back(
75 x: DC->getLineInfoForAddress(Address: SAddr).value_or(u: DILineInfo()).FileName);
76 for (auto &LInfo : LinesInfo) {
77 Method.LineTable.push_back(
78 x: std::pair<unsigned, unsigned>{/*unsigned*/ Sym->getOffset(),
79 /*DILineInfo*/ LInfo.second.Line});
80 }
81 }
82 return Batch;
83}
84
85void VTuneSupportPlugin::modifyPassConfig(MaterializationResponsibility &MR,
86 LinkGraph &G,
87 PassConfiguration &Config) {
88 Config.PostFixupPasses.push_back(x: [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 x: {.Finalize: cantFail(ValOrErr: shared::WrapperFunctionCall::Create<
106 shared::SPSArgList<shared::SPSVTuneMethodBatch>>(
107 FnAddr: RegisterVTuneImplAddr, Args: Batch)),
108 .Dealloc: {}});
109 return Error::success();
110 });
111}
112
113Error VTuneSupportPlugin::notifyEmitted(MaterializationResponsibility &MR) {
114 if (auto Err = MR.withResourceKeyDo(F: [this, MR = &MR](ResourceKey K) {
115 std::lock_guard<std::mutex> Lock(PluginMutex);
116 auto I = PendingMethodIDs.find(Val: MR);
117 if (I == PendingMethodIDs.end())
118 return;
119
120 LoadedMethodIDs[K].push_back(Elt: I->second);
121 PendingMethodIDs.erase(I);
122 })) {
123 return Err;
124 }
125 return Error::success();
126}
127
128Error VTuneSupportPlugin::notifyFailed(MaterializationResponsibility &MR) {
129 std::lock_guard<std::mutex> Lock(PluginMutex);
130 PendingMethodIDs.erase(Val: &MR);
131 return Error::success();
132}
133
134Error 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(Val: 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 WrapperFnAddr: UnregisterVTuneImplAddr, WrapperCallArgs&: UnloadedIDs))
151 return Err;
152
153 return Error::success();
154}
155
156void VTuneSupportPlugin::notifyTransferringResources(JITDylib &JD,
157 ResourceKey DstKey,
158 ResourceKey SrcKey) {
159 std::lock_guard<std::mutex> Lock(PluginMutex);
160 auto I = LoadedMethodIDs.find(Val: SrcKey);
161 if (I == LoadedMethodIDs.end())
162 return;
163
164 auto &Dest = LoadedMethodIDs[DstKey];
165 llvm::append_range(C&: Dest, R&: I->second);
166 LoadedMethodIDs.erase(Val: SrcKey);
167}
168
169Expected<std::unique_ptr<VTuneSupportPlugin>>
170VTuneSupportPlugin::Create(ExecutorProcessControl &EPC, JITDylib &JD,
171 bool EmitDebugInfo, bool TestMode) {
172 auto &ES = EPC.getExecutionSession();
173 auto RegisterImplName =
174 ES.intern(SymName: TestMode ? RegisterTestVTuneImplName : RegisterVTuneImplName);
175 auto UnregisterImplName = ES.intern(SymName: UnregisterVTuneImplName);
176 SymbolLookupSet SLS{RegisterImplName, UnregisterImplName};
177 auto Res = ES.lookup(SearchOrder: makeJITDylibSearchOrder(JDs: {&JD}), Symbols: std::move(SLS));
178 if (!Res)
179 return Res.takeError();
180 ExecutorAddr RegisterImplAddr(
181 Res->find(Val: RegisterImplName)->second.getAddress());
182 ExecutorAddr UnregisterImplAddr(
183 Res->find(Val: UnregisterImplName)->second.getAddress());
184 return std::make_unique<VTuneSupportPlugin>(
185 args&: EPC, args&: RegisterImplAddr, args&: UnregisterImplAddr, args&: EmitDebugInfo);
186}
187