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