1*0fca6ea1SDimitry Andric //===--- VTuneSupportPlugin.cpp -- Support for VTune profiler --*- C++ -*--===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric //
9*0fca6ea1SDimitry Andric // Handles support for registering code with VIntel Tune's Amplfiier JIT API.
10*0fca6ea1SDimitry Andric //
11*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
12*0fca6ea1SDimitry Andric #include "llvm/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.h"
13*0fca6ea1SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFContext.h"
14*0fca6ea1SDimitry Andric #include "llvm/ExecutionEngine/Orc/Debugging/DebugInfoSupport.h"
15*0fca6ea1SDimitry Andric
16*0fca6ea1SDimitry Andric using namespace llvm;
17*0fca6ea1SDimitry Andric using namespace llvm::orc;
18*0fca6ea1SDimitry Andric using namespace llvm::jitlink;
19*0fca6ea1SDimitry Andric
20*0fca6ea1SDimitry Andric static constexpr StringRef RegisterVTuneImplName = "llvm_orc_registerVTuneImpl";
21*0fca6ea1SDimitry Andric static constexpr StringRef UnregisterVTuneImplName =
22*0fca6ea1SDimitry Andric "llvm_orc_unregisterVTuneImpl";
23*0fca6ea1SDimitry Andric static constexpr StringRef RegisterTestVTuneImplName =
24*0fca6ea1SDimitry Andric "llvm_orc_test_registerVTuneImpl";
25*0fca6ea1SDimitry Andric
getMethodBatch(LinkGraph & G,bool EmitDebugInfo)26*0fca6ea1SDimitry Andric static VTuneMethodBatch getMethodBatch(LinkGraph &G, bool EmitDebugInfo) {
27*0fca6ea1SDimitry Andric VTuneMethodBatch Batch;
28*0fca6ea1SDimitry Andric std::unique_ptr<DWARFContext> DC;
29*0fca6ea1SDimitry Andric StringMap<std::unique_ptr<MemoryBuffer>> DCBacking;
30*0fca6ea1SDimitry Andric if (EmitDebugInfo) {
31*0fca6ea1SDimitry Andric auto EDC = createDWARFContext(G);
32*0fca6ea1SDimitry Andric if (!EDC) {
33*0fca6ea1SDimitry Andric EmitDebugInfo = false;
34*0fca6ea1SDimitry Andric } else {
35*0fca6ea1SDimitry Andric DC = std::move(EDC->first);
36*0fca6ea1SDimitry Andric DCBacking = std::move(EDC->second);
37*0fca6ea1SDimitry Andric }
38*0fca6ea1SDimitry Andric }
39*0fca6ea1SDimitry Andric
40*0fca6ea1SDimitry Andric auto GetStringIdx = [Deduplicator = StringMap<uint32_t>(),
41*0fca6ea1SDimitry Andric &Batch](StringRef S) mutable {
42*0fca6ea1SDimitry Andric auto I = Deduplicator.find(S);
43*0fca6ea1SDimitry Andric if (I != Deduplicator.end())
44*0fca6ea1SDimitry Andric return I->second;
45*0fca6ea1SDimitry Andric
46*0fca6ea1SDimitry Andric Batch.Strings.push_back(S.str());
47*0fca6ea1SDimitry Andric return Deduplicator[S] = Batch.Strings.size();
48*0fca6ea1SDimitry Andric };
49*0fca6ea1SDimitry Andric for (auto Sym : G.defined_symbols()) {
50*0fca6ea1SDimitry Andric if (!Sym->isCallable())
51*0fca6ea1SDimitry Andric continue;
52*0fca6ea1SDimitry Andric
53*0fca6ea1SDimitry Andric Batch.Methods.push_back(VTuneMethodInfo());
54*0fca6ea1SDimitry Andric auto &Method = Batch.Methods.back();
55*0fca6ea1SDimitry Andric Method.MethodID = 0;
56*0fca6ea1SDimitry Andric Method.ParentMI = 0;
57*0fca6ea1SDimitry Andric Method.LoadAddr = Sym->getAddress();
58*0fca6ea1SDimitry Andric Method.LoadSize = Sym->getSize();
59*0fca6ea1SDimitry Andric Method.NameSI = GetStringIdx(Sym->getName());
60*0fca6ea1SDimitry Andric Method.ClassFileSI = 0;
61*0fca6ea1SDimitry Andric Method.SourceFileSI = 0;
62*0fca6ea1SDimitry Andric
63*0fca6ea1SDimitry Andric if (!EmitDebugInfo)
64*0fca6ea1SDimitry Andric continue;
65*0fca6ea1SDimitry Andric
66*0fca6ea1SDimitry Andric auto &Section = Sym->getBlock().getSection();
67*0fca6ea1SDimitry Andric auto Addr = Sym->getAddress();
68*0fca6ea1SDimitry Andric auto SAddr =
69*0fca6ea1SDimitry Andric object::SectionedAddress{Addr.getValue(), Section.getOrdinal()};
70*0fca6ea1SDimitry Andric DILineInfoTable LinesInfo = DC->getLineInfoForAddressRange(
71*0fca6ea1SDimitry Andric SAddr, Sym->getSize(),
72*0fca6ea1SDimitry Andric DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath);
73*0fca6ea1SDimitry Andric Method.SourceFileSI = Batch.Strings.size();
74*0fca6ea1SDimitry Andric Batch.Strings.push_back(DC->getLineInfoForAddress(SAddr).FileName);
75*0fca6ea1SDimitry Andric for (auto &LInfo : LinesInfo) {
76*0fca6ea1SDimitry Andric Method.LineTable.push_back(
77*0fca6ea1SDimitry Andric std::pair<unsigned, unsigned>{/*unsigned*/ Sym->getOffset(),
78*0fca6ea1SDimitry Andric /*DILineInfo*/ LInfo.second.Line});
79*0fca6ea1SDimitry Andric }
80*0fca6ea1SDimitry Andric }
81*0fca6ea1SDimitry Andric return Batch;
82*0fca6ea1SDimitry Andric }
83*0fca6ea1SDimitry Andric
modifyPassConfig(MaterializationResponsibility & MR,LinkGraph & G,PassConfiguration & Config)84*0fca6ea1SDimitry Andric void VTuneSupportPlugin::modifyPassConfig(MaterializationResponsibility &MR,
85*0fca6ea1SDimitry Andric LinkGraph &G,
86*0fca6ea1SDimitry Andric PassConfiguration &Config) {
87*0fca6ea1SDimitry Andric Config.PostFixupPasses.push_back([this, MR = &MR](LinkGraph &G) {
88*0fca6ea1SDimitry Andric // the object file is generated but not linked yet
89*0fca6ea1SDimitry Andric auto Batch = getMethodBatch(G, EmitDebugInfo);
90*0fca6ea1SDimitry Andric if (Batch.Methods.empty()) {
91*0fca6ea1SDimitry Andric return Error::success();
92*0fca6ea1SDimitry Andric }
93*0fca6ea1SDimitry Andric {
94*0fca6ea1SDimitry Andric std::lock_guard<std::mutex> Lock(PluginMutex);
95*0fca6ea1SDimitry Andric uint64_t Allocated = Batch.Methods.size();
96*0fca6ea1SDimitry Andric uint64_t Start = NextMethodID;
97*0fca6ea1SDimitry Andric NextMethodID += Allocated;
98*0fca6ea1SDimitry Andric for (size_t i = Start; i < NextMethodID; ++i) {
99*0fca6ea1SDimitry Andric Batch.Methods[i - Start].MethodID = i;
100*0fca6ea1SDimitry Andric }
101*0fca6ea1SDimitry Andric this->PendingMethodIDs[MR] = {Start, Allocated};
102*0fca6ea1SDimitry Andric }
103*0fca6ea1SDimitry Andric G.allocActions().push_back(
104*0fca6ea1SDimitry Andric {cantFail(shared::WrapperFunctionCall::Create<
105*0fca6ea1SDimitry Andric shared::SPSArgList<shared::SPSVTuneMethodBatch>>(
106*0fca6ea1SDimitry Andric RegisterVTuneImplAddr, Batch)),
107*0fca6ea1SDimitry Andric {}});
108*0fca6ea1SDimitry Andric return Error::success();
109*0fca6ea1SDimitry Andric });
110*0fca6ea1SDimitry Andric }
111*0fca6ea1SDimitry Andric
notifyEmitted(MaterializationResponsibility & MR)112*0fca6ea1SDimitry Andric Error VTuneSupportPlugin::notifyEmitted(MaterializationResponsibility &MR) {
113*0fca6ea1SDimitry Andric if (auto Err = MR.withResourceKeyDo([this, MR = &MR](ResourceKey K) {
114*0fca6ea1SDimitry Andric std::lock_guard<std::mutex> Lock(PluginMutex);
115*0fca6ea1SDimitry Andric auto I = PendingMethodIDs.find(MR);
116*0fca6ea1SDimitry Andric if (I == PendingMethodIDs.end())
117*0fca6ea1SDimitry Andric return;
118*0fca6ea1SDimitry Andric
119*0fca6ea1SDimitry Andric LoadedMethodIDs[K].push_back(I->second);
120*0fca6ea1SDimitry Andric PendingMethodIDs.erase(I);
121*0fca6ea1SDimitry Andric })) {
122*0fca6ea1SDimitry Andric return Err;
123*0fca6ea1SDimitry Andric }
124*0fca6ea1SDimitry Andric return Error::success();
125*0fca6ea1SDimitry Andric }
126*0fca6ea1SDimitry Andric
notifyFailed(MaterializationResponsibility & MR)127*0fca6ea1SDimitry Andric Error VTuneSupportPlugin::notifyFailed(MaterializationResponsibility &MR) {
128*0fca6ea1SDimitry Andric std::lock_guard<std::mutex> Lock(PluginMutex);
129*0fca6ea1SDimitry Andric PendingMethodIDs.erase(&MR);
130*0fca6ea1SDimitry Andric return Error::success();
131*0fca6ea1SDimitry Andric }
132*0fca6ea1SDimitry Andric
notifyRemovingResources(JITDylib & JD,ResourceKey K)133*0fca6ea1SDimitry Andric Error VTuneSupportPlugin::notifyRemovingResources(JITDylib &JD, ResourceKey K) {
134*0fca6ea1SDimitry Andric // Unregistration not required if not provided
135*0fca6ea1SDimitry Andric if (!UnregisterVTuneImplAddr) {
136*0fca6ea1SDimitry Andric return Error::success();
137*0fca6ea1SDimitry Andric }
138*0fca6ea1SDimitry Andric VTuneUnloadedMethodIDs UnloadedIDs;
139*0fca6ea1SDimitry Andric {
140*0fca6ea1SDimitry Andric std::lock_guard<std::mutex> Lock(PluginMutex);
141*0fca6ea1SDimitry Andric auto I = LoadedMethodIDs.find(K);
142*0fca6ea1SDimitry Andric if (I == LoadedMethodIDs.end())
143*0fca6ea1SDimitry Andric return Error::success();
144*0fca6ea1SDimitry Andric
145*0fca6ea1SDimitry Andric UnloadedIDs = std::move(I->second);
146*0fca6ea1SDimitry Andric LoadedMethodIDs.erase(I);
147*0fca6ea1SDimitry Andric }
148*0fca6ea1SDimitry Andric if (auto Err = EPC.callSPSWrapper<void(shared::SPSVTuneUnloadedMethodIDs)>(
149*0fca6ea1SDimitry Andric UnregisterVTuneImplAddr, UnloadedIDs))
150*0fca6ea1SDimitry Andric return Err;
151*0fca6ea1SDimitry Andric
152*0fca6ea1SDimitry Andric return Error::success();
153*0fca6ea1SDimitry Andric }
154*0fca6ea1SDimitry Andric
notifyTransferringResources(JITDylib & JD,ResourceKey DstKey,ResourceKey SrcKey)155*0fca6ea1SDimitry Andric void VTuneSupportPlugin::notifyTransferringResources(JITDylib &JD,
156*0fca6ea1SDimitry Andric ResourceKey DstKey,
157*0fca6ea1SDimitry Andric ResourceKey SrcKey) {
158*0fca6ea1SDimitry Andric std::lock_guard<std::mutex> Lock(PluginMutex);
159*0fca6ea1SDimitry Andric auto I = LoadedMethodIDs.find(SrcKey);
160*0fca6ea1SDimitry Andric if (I == LoadedMethodIDs.end())
161*0fca6ea1SDimitry Andric return;
162*0fca6ea1SDimitry Andric
163*0fca6ea1SDimitry Andric auto &Dest = LoadedMethodIDs[DstKey];
164*0fca6ea1SDimitry Andric Dest.insert(Dest.end(), I->second.begin(), I->second.end());
165*0fca6ea1SDimitry Andric LoadedMethodIDs.erase(SrcKey);
166*0fca6ea1SDimitry Andric }
167*0fca6ea1SDimitry Andric
168*0fca6ea1SDimitry Andric Expected<std::unique_ptr<VTuneSupportPlugin>>
Create(ExecutorProcessControl & EPC,JITDylib & JD,bool EmitDebugInfo,bool TestMode)169*0fca6ea1SDimitry Andric VTuneSupportPlugin::Create(ExecutorProcessControl &EPC, JITDylib &JD,
170*0fca6ea1SDimitry Andric bool EmitDebugInfo, bool TestMode) {
171*0fca6ea1SDimitry Andric auto &ES = EPC.getExecutionSession();
172*0fca6ea1SDimitry Andric auto RegisterImplName =
173*0fca6ea1SDimitry Andric ES.intern(TestMode ? RegisterTestVTuneImplName : RegisterVTuneImplName);
174*0fca6ea1SDimitry Andric auto UnregisterImplName = ES.intern(UnregisterVTuneImplName);
175*0fca6ea1SDimitry Andric SymbolLookupSet SLS{RegisterImplName, UnregisterImplName};
176*0fca6ea1SDimitry Andric auto Res = ES.lookup(makeJITDylibSearchOrder({&JD}), std::move(SLS));
177*0fca6ea1SDimitry Andric if (!Res)
178*0fca6ea1SDimitry Andric return Res.takeError();
179*0fca6ea1SDimitry Andric ExecutorAddr RegisterImplAddr(
180*0fca6ea1SDimitry Andric Res->find(RegisterImplName)->second.getAddress());
181*0fca6ea1SDimitry Andric ExecutorAddr UnregisterImplAddr(
182*0fca6ea1SDimitry Andric Res->find(UnregisterImplName)->second.getAddress());
183*0fca6ea1SDimitry Andric return std::make_unique<VTuneSupportPlugin>(
184*0fca6ea1SDimitry Andric EPC, RegisterImplAddr, UnregisterImplAddr, EmitDebugInfo);
185*0fca6ea1SDimitry Andric }
186