xref: /src/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1ac9a064cSDimitry Andric //===--- VTuneSupportPlugin.cpp -- Support for VTune profiler --*- C++ -*--===//
2ac9a064cSDimitry Andric //
3ac9a064cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ac9a064cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5ac9a064cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ac9a064cSDimitry Andric //
7ac9a064cSDimitry Andric //===----------------------------------------------------------------------===//
8ac9a064cSDimitry Andric //
9ac9a064cSDimitry Andric // Handles support for registering code with VIntel Tune's Amplfiier JIT API.
10ac9a064cSDimitry Andric //
11ac9a064cSDimitry Andric //===----------------------------------------------------------------------===//
12ac9a064cSDimitry Andric #include "llvm/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.h"
13ac9a064cSDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFContext.h"
14ac9a064cSDimitry Andric #include "llvm/ExecutionEngine/Orc/Debugging/DebugInfoSupport.h"
15ac9a064cSDimitry Andric 
16ac9a064cSDimitry Andric using namespace llvm;
17ac9a064cSDimitry Andric using namespace llvm::orc;
18ac9a064cSDimitry Andric using namespace llvm::jitlink;
19ac9a064cSDimitry Andric 
20ac9a064cSDimitry Andric static constexpr StringRef RegisterVTuneImplName = "llvm_orc_registerVTuneImpl";
21ac9a064cSDimitry Andric static constexpr StringRef UnregisterVTuneImplName =
22ac9a064cSDimitry Andric     "llvm_orc_unregisterVTuneImpl";
23ac9a064cSDimitry Andric static constexpr StringRef RegisterTestVTuneImplName =
24ac9a064cSDimitry Andric     "llvm_orc_test_registerVTuneImpl";
25ac9a064cSDimitry Andric 
getMethodBatch(LinkGraph & G,bool EmitDebugInfo)26ac9a064cSDimitry Andric static VTuneMethodBatch getMethodBatch(LinkGraph &G, bool EmitDebugInfo) {
27ac9a064cSDimitry Andric   VTuneMethodBatch Batch;
28ac9a064cSDimitry Andric   std::unique_ptr<DWARFContext> DC;
29ac9a064cSDimitry Andric   StringMap<std::unique_ptr<MemoryBuffer>> DCBacking;
30ac9a064cSDimitry Andric   if (EmitDebugInfo) {
31ac9a064cSDimitry Andric     auto EDC = createDWARFContext(G);
32ac9a064cSDimitry Andric     if (!EDC) {
33ac9a064cSDimitry Andric       EmitDebugInfo = false;
34ac9a064cSDimitry Andric     } else {
35ac9a064cSDimitry Andric       DC = std::move(EDC->first);
36ac9a064cSDimitry Andric       DCBacking = std::move(EDC->second);
37ac9a064cSDimitry Andric     }
38ac9a064cSDimitry Andric   }
39ac9a064cSDimitry Andric 
40ac9a064cSDimitry Andric   auto GetStringIdx = [Deduplicator = StringMap<uint32_t>(),
41ac9a064cSDimitry Andric                        &Batch](StringRef S) mutable {
42ac9a064cSDimitry Andric     auto I = Deduplicator.find(S);
43ac9a064cSDimitry Andric     if (I != Deduplicator.end())
44ac9a064cSDimitry Andric       return I->second;
45ac9a064cSDimitry Andric 
46ac9a064cSDimitry Andric     Batch.Strings.push_back(S.str());
47ac9a064cSDimitry Andric     return Deduplicator[S] = Batch.Strings.size();
48ac9a064cSDimitry Andric   };
49ac9a064cSDimitry Andric   for (auto Sym : G.defined_symbols()) {
50ac9a064cSDimitry Andric     if (!Sym->isCallable())
51ac9a064cSDimitry Andric       continue;
52ac9a064cSDimitry Andric 
53ac9a064cSDimitry Andric     Batch.Methods.push_back(VTuneMethodInfo());
54ac9a064cSDimitry Andric     auto &Method = Batch.Methods.back();
55ac9a064cSDimitry Andric     Method.MethodID = 0;
56ac9a064cSDimitry Andric     Method.ParentMI = 0;
57ac9a064cSDimitry Andric     Method.LoadAddr = Sym->getAddress();
58ac9a064cSDimitry Andric     Method.LoadSize = Sym->getSize();
59ac9a064cSDimitry Andric     Method.NameSI = GetStringIdx(Sym->getName());
60ac9a064cSDimitry Andric     Method.ClassFileSI = 0;
61ac9a064cSDimitry Andric     Method.SourceFileSI = 0;
62ac9a064cSDimitry Andric 
63ac9a064cSDimitry Andric     if (!EmitDebugInfo)
64ac9a064cSDimitry Andric       continue;
65ac9a064cSDimitry Andric 
66ac9a064cSDimitry Andric     auto &Section = Sym->getBlock().getSection();
67ac9a064cSDimitry Andric     auto Addr = Sym->getAddress();
68ac9a064cSDimitry Andric     auto SAddr =
69ac9a064cSDimitry Andric         object::SectionedAddress{Addr.getValue(), Section.getOrdinal()};
70ac9a064cSDimitry Andric     DILineInfoTable LinesInfo = DC->getLineInfoForAddressRange(
71ac9a064cSDimitry Andric         SAddr, Sym->getSize(),
72ac9a064cSDimitry Andric         DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath);
73ac9a064cSDimitry Andric     Method.SourceFileSI = Batch.Strings.size();
74ac9a064cSDimitry Andric     Batch.Strings.push_back(DC->getLineInfoForAddress(SAddr).FileName);
75ac9a064cSDimitry Andric     for (auto &LInfo : LinesInfo) {
76ac9a064cSDimitry Andric       Method.LineTable.push_back(
77ac9a064cSDimitry Andric           std::pair<unsigned, unsigned>{/*unsigned*/ Sym->getOffset(),
78ac9a064cSDimitry Andric                                         /*DILineInfo*/ LInfo.second.Line});
79ac9a064cSDimitry Andric     }
80ac9a064cSDimitry Andric   }
81ac9a064cSDimitry Andric   return Batch;
82ac9a064cSDimitry Andric }
83ac9a064cSDimitry Andric 
modifyPassConfig(MaterializationResponsibility & MR,LinkGraph & G,PassConfiguration & Config)84ac9a064cSDimitry Andric void VTuneSupportPlugin::modifyPassConfig(MaterializationResponsibility &MR,
85ac9a064cSDimitry Andric                                           LinkGraph &G,
86ac9a064cSDimitry Andric                                           PassConfiguration &Config) {
87ac9a064cSDimitry Andric   Config.PostFixupPasses.push_back([this, MR = &MR](LinkGraph &G) {
88ac9a064cSDimitry Andric     // the object file is generated but not linked yet
89ac9a064cSDimitry Andric     auto Batch = getMethodBatch(G, EmitDebugInfo);
90ac9a064cSDimitry Andric     if (Batch.Methods.empty()) {
91ac9a064cSDimitry Andric       return Error::success();
92ac9a064cSDimitry Andric     }
93ac9a064cSDimitry Andric     {
94ac9a064cSDimitry Andric       std::lock_guard<std::mutex> Lock(PluginMutex);
95ac9a064cSDimitry Andric       uint64_t Allocated = Batch.Methods.size();
96ac9a064cSDimitry Andric       uint64_t Start = NextMethodID;
97ac9a064cSDimitry Andric       NextMethodID += Allocated;
98ac9a064cSDimitry Andric       for (size_t i = Start; i < NextMethodID; ++i) {
99ac9a064cSDimitry Andric         Batch.Methods[i - Start].MethodID = i;
100ac9a064cSDimitry Andric       }
101ac9a064cSDimitry Andric       this->PendingMethodIDs[MR] = {Start, Allocated};
102ac9a064cSDimitry Andric     }
103ac9a064cSDimitry Andric     G.allocActions().push_back(
104ac9a064cSDimitry Andric         {cantFail(shared::WrapperFunctionCall::Create<
105ac9a064cSDimitry Andric                   shared::SPSArgList<shared::SPSVTuneMethodBatch>>(
106ac9a064cSDimitry Andric              RegisterVTuneImplAddr, Batch)),
107ac9a064cSDimitry Andric          {}});
108ac9a064cSDimitry Andric     return Error::success();
109ac9a064cSDimitry Andric   });
110ac9a064cSDimitry Andric }
111ac9a064cSDimitry Andric 
notifyEmitted(MaterializationResponsibility & MR)112ac9a064cSDimitry Andric Error VTuneSupportPlugin::notifyEmitted(MaterializationResponsibility &MR) {
113ac9a064cSDimitry Andric   if (auto Err = MR.withResourceKeyDo([this, MR = &MR](ResourceKey K) {
114ac9a064cSDimitry Andric         std::lock_guard<std::mutex> Lock(PluginMutex);
115ac9a064cSDimitry Andric         auto I = PendingMethodIDs.find(MR);
116ac9a064cSDimitry Andric         if (I == PendingMethodIDs.end())
117ac9a064cSDimitry Andric           return;
118ac9a064cSDimitry Andric 
119ac9a064cSDimitry Andric         LoadedMethodIDs[K].push_back(I->second);
120ac9a064cSDimitry Andric         PendingMethodIDs.erase(I);
121ac9a064cSDimitry Andric       })) {
122ac9a064cSDimitry Andric     return Err;
123ac9a064cSDimitry Andric   }
124ac9a064cSDimitry Andric   return Error::success();
125ac9a064cSDimitry Andric }
126ac9a064cSDimitry Andric 
notifyFailed(MaterializationResponsibility & MR)127ac9a064cSDimitry Andric Error VTuneSupportPlugin::notifyFailed(MaterializationResponsibility &MR) {
128ac9a064cSDimitry Andric   std::lock_guard<std::mutex> Lock(PluginMutex);
129ac9a064cSDimitry Andric   PendingMethodIDs.erase(&MR);
130ac9a064cSDimitry Andric   return Error::success();
131ac9a064cSDimitry Andric }
132ac9a064cSDimitry Andric 
notifyRemovingResources(JITDylib & JD,ResourceKey K)133ac9a064cSDimitry Andric Error VTuneSupportPlugin::notifyRemovingResources(JITDylib &JD, ResourceKey K) {
134ac9a064cSDimitry Andric   // Unregistration not required if not provided
135ac9a064cSDimitry Andric   if (!UnregisterVTuneImplAddr) {
136ac9a064cSDimitry Andric     return Error::success();
137ac9a064cSDimitry Andric   }
138ac9a064cSDimitry Andric   VTuneUnloadedMethodIDs UnloadedIDs;
139ac9a064cSDimitry Andric   {
140ac9a064cSDimitry Andric     std::lock_guard<std::mutex> Lock(PluginMutex);
141ac9a064cSDimitry Andric     auto I = LoadedMethodIDs.find(K);
142ac9a064cSDimitry Andric     if (I == LoadedMethodIDs.end())
143ac9a064cSDimitry Andric       return Error::success();
144ac9a064cSDimitry Andric 
145ac9a064cSDimitry Andric     UnloadedIDs = std::move(I->second);
146ac9a064cSDimitry Andric     LoadedMethodIDs.erase(I);
147ac9a064cSDimitry Andric   }
148ac9a064cSDimitry Andric   if (auto Err = EPC.callSPSWrapper<void(shared::SPSVTuneUnloadedMethodIDs)>(
149ac9a064cSDimitry Andric           UnregisterVTuneImplAddr, UnloadedIDs))
150ac9a064cSDimitry Andric     return Err;
151ac9a064cSDimitry Andric 
152ac9a064cSDimitry Andric   return Error::success();
153ac9a064cSDimitry Andric }
154ac9a064cSDimitry Andric 
notifyTransferringResources(JITDylib & JD,ResourceKey DstKey,ResourceKey SrcKey)155ac9a064cSDimitry Andric void VTuneSupportPlugin::notifyTransferringResources(JITDylib &JD,
156ac9a064cSDimitry Andric                                                      ResourceKey DstKey,
157ac9a064cSDimitry Andric                                                      ResourceKey SrcKey) {
158ac9a064cSDimitry Andric   std::lock_guard<std::mutex> Lock(PluginMutex);
159ac9a064cSDimitry Andric   auto I = LoadedMethodIDs.find(SrcKey);
160ac9a064cSDimitry Andric   if (I == LoadedMethodIDs.end())
161ac9a064cSDimitry Andric     return;
162ac9a064cSDimitry Andric 
163ac9a064cSDimitry Andric   auto &Dest = LoadedMethodIDs[DstKey];
164ac9a064cSDimitry Andric   Dest.insert(Dest.end(), I->second.begin(), I->second.end());
165ac9a064cSDimitry Andric   LoadedMethodIDs.erase(SrcKey);
166ac9a064cSDimitry Andric }
167ac9a064cSDimitry Andric 
168ac9a064cSDimitry Andric Expected<std::unique_ptr<VTuneSupportPlugin>>
Create(ExecutorProcessControl & EPC,JITDylib & JD,bool EmitDebugInfo,bool TestMode)169ac9a064cSDimitry Andric VTuneSupportPlugin::Create(ExecutorProcessControl &EPC, JITDylib &JD,
170ac9a064cSDimitry Andric                            bool EmitDebugInfo, bool TestMode) {
171ac9a064cSDimitry Andric   auto &ES = EPC.getExecutionSession();
172ac9a064cSDimitry Andric   auto RegisterImplName =
173ac9a064cSDimitry Andric       ES.intern(TestMode ? RegisterTestVTuneImplName : RegisterVTuneImplName);
174ac9a064cSDimitry Andric   auto UnregisterImplName = ES.intern(UnregisterVTuneImplName);
175ac9a064cSDimitry Andric   SymbolLookupSet SLS{RegisterImplName, UnregisterImplName};
176ac9a064cSDimitry Andric   auto Res = ES.lookup(makeJITDylibSearchOrder({&JD}), std::move(SLS));
177ac9a064cSDimitry Andric   if (!Res)
178ac9a064cSDimitry Andric     return Res.takeError();
179ac9a064cSDimitry Andric   ExecutorAddr RegisterImplAddr(
180ac9a064cSDimitry Andric       Res->find(RegisterImplName)->second.getAddress());
181ac9a064cSDimitry Andric   ExecutorAddr UnregisterImplAddr(
182ac9a064cSDimitry Andric       Res->find(UnregisterImplName)->second.getAddress());
183ac9a064cSDimitry Andric   return std::make_unique<VTuneSupportPlugin>(
184ac9a064cSDimitry Andric       EPC, RegisterImplAddr, UnregisterImplAddr, EmitDebugInfo);
185ac9a064cSDimitry Andric }
186