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(Key: S); |
43 | if (Inserted) { |
44 | Batch.Strings.push_back(x: 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(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->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( |
75 | x: DC->getLineInfoForAddress(Address: SAddr).value_or(u: DILineInfo()).FileName); |
76 | for (auto &LInfo : LinesInfo) { |
77 | Method.LineTable.push_back( |
78 | x: 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(x: [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 | x: {.Finalize: cantFail(ValOrErr: shared::WrapperFunctionCall::Create< |
106 | shared::SPSArgList<shared::SPSVTuneMethodBatch>>( |
107 | FnAddr: RegisterVTuneImplAddr, Args: Batch)), |
108 | .Dealloc: {}}); |
109 | return Error::success(); |
110 | }); |
111 | } |
112 | |
113 | Error VTuneSupportPlugin::notifyEmitted(MaterializationResponsibility &MR) { |
114 | if (auto Err = MR.withResourceKeyDo(F: [this, MR = &MR](ResourceKey K) { |
115 | std::lock_guard<std::mutex> Lock(PluginMutex); |
116 | auto I = PendingMethodIDs.find(Val: MR); |
117 | if (I == PendingMethodIDs.end()) |
118 | return; |
119 | |
120 | LoadedMethodIDs[K].push_back(Elt: 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(Val: &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(Val: 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 | WrapperFnAddr: UnregisterVTuneImplAddr, WrapperCallArgs&: 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(Val: SrcKey); |
161 | if (I == LoadedMethodIDs.end()) |
162 | return; |
163 | |
164 | auto &Dest = LoadedMethodIDs[DstKey]; |
165 | llvm::append_range(C&: Dest, R&: I->second); |
166 | LoadedMethodIDs.erase(Val: 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(SymName: TestMode ? RegisterTestVTuneImplName : RegisterVTuneImplName); |
175 | auto UnregisterImplName = ES.intern(SymName: UnregisterVTuneImplName); |
176 | SymbolLookupSet SLS{RegisterImplName, UnregisterImplName}; |
177 | auto Res = ES.lookup(SearchOrder: makeJITDylibSearchOrder(JDs: {&JD}), Symbols: std::move(SLS)); |
178 | if (!Res) |
179 | return Res.takeError(); |
180 | ExecutorAddr RegisterImplAddr( |
181 | Res->find(Val: RegisterImplName)->second.getAddress()); |
182 | ExecutorAddr UnregisterImplAddr( |
183 | Res->find(Val: UnregisterImplName)->second.getAddress()); |
184 | return std::make_unique<VTuneSupportPlugin>( |
185 | args&: EPC, args&: RegisterImplAddr, args&: UnregisterImplAddr, args&: EmitDebugInfo); |
186 | } |
187 | |