xref: /freebsd-src/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
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 
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 
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 
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 
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 
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>>
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