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(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 | |
84 | void 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 | |
112 | Error 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 | |
127 | Error VTuneSupportPlugin::notifyFailed(MaterializationResponsibility &MR) { |
128 | std::lock_guard<std::mutex> Lock(PluginMutex); |
129 | PendingMethodIDs.erase(Val: &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(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 | |
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(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 | |
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(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 | |