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