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