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 = Deduplicator.find(Key: S);
43 if (I != Deduplicator.end())
44 return I->second;
45
46 Batch.Strings.push_back(x: 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(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->getBlock().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(x: DC->getLineInfoForAddress(Address: SAddr).FileName);
75 for (auto &LInfo : LinesInfo) {
76 Method.LineTable.push_back(
77 x: std::pair<unsigned, unsigned>{/*unsigned*/ Sym->getOffset(),
78 /*DILineInfo*/ LInfo.second.Line});
79 }
80 }
81 return Batch;
82}
83
84void VTuneSupportPlugin::modifyPassConfig(MaterializationResponsibility &MR,
85 LinkGraph &G,
86 PassConfiguration &Config) {
87 Config.PostFixupPasses.push_back(x: [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 x: {.Finalize: cantFail(ValOrErr: shared::WrapperFunctionCall::Create<
105 shared::SPSArgList<shared::SPSVTuneMethodBatch>>(
106 FnAddr: RegisterVTuneImplAddr, Args: Batch)),
107 .Dealloc: {}});
108 return Error::success();
109 });
110}
111
112Error VTuneSupportPlugin::notifyEmitted(MaterializationResponsibility &MR) {
113 if (auto Err = MR.withResourceKeyDo(F: [this, MR = &MR](ResourceKey K) {
114 std::lock_guard<std::mutex> Lock(PluginMutex);
115 auto I = PendingMethodIDs.find(Val: MR);
116 if (I == PendingMethodIDs.end())
117 return;
118
119 LoadedMethodIDs[K].push_back(Elt: I->second);
120 PendingMethodIDs.erase(I);
121 })) {
122 return Err;
123 }
124 return Error::success();
125}
126
127Error VTuneSupportPlugin::notifyFailed(MaterializationResponsibility &MR) {
128 std::lock_guard<std::mutex> Lock(PluginMutex);
129 PendingMethodIDs.erase(Val: &MR);
130 return Error::success();
131}
132
133Error 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(Val: 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 WrapperFnAddr: UnregisterVTuneImplAddr, WrapperCallArgs&: UnloadedIDs))
150 return Err;
151
152 return Error::success();
153}
154
155void VTuneSupportPlugin::notifyTransferringResources(JITDylib &JD,
156 ResourceKey DstKey,
157 ResourceKey SrcKey) {
158 std::lock_guard<std::mutex> Lock(PluginMutex);
159 auto I = LoadedMethodIDs.find(Val: SrcKey);
160 if (I == LoadedMethodIDs.end())
161 return;
162
163 auto &Dest = LoadedMethodIDs[DstKey];
164 Dest.insert(I: Dest.end(), From: I->second.begin(), To: I->second.end());
165 LoadedMethodIDs.erase(Val: SrcKey);
166}
167
168Expected<std::unique_ptr<VTuneSupportPlugin>>
169VTuneSupportPlugin::Create(ExecutorProcessControl &EPC, JITDylib &JD,
170 bool EmitDebugInfo, bool TestMode) {
171 auto &ES = EPC.getExecutionSession();
172 auto RegisterImplName =
173 ES.intern(SymName: TestMode ? RegisterTestVTuneImplName : RegisterVTuneImplName);
174 auto UnregisterImplName = ES.intern(SymName: UnregisterVTuneImplName);
175 SymbolLookupSet SLS{RegisterImplName, UnregisterImplName};
176 auto Res = ES.lookup(SearchOrder: makeJITDylibSearchOrder(JDs: {&JD}), Symbols: std::move(SLS));
177 if (!Res)
178 return Res.takeError();
179 ExecutorAddr RegisterImplAddr(
180 Res->find(Val: RegisterImplName)->second.getAddress());
181 ExecutorAddr UnregisterImplAddr(
182 Res->find(Val: UnregisterImplName)->second.getAddress());
183 return std::make_unique<VTuneSupportPlugin>(
184 args&: EPC, args&: RegisterImplAddr, args&: UnregisterImplAddr, args&: EmitDebugInfo);
185}
186