xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.cpp (revision 27bd6c32bbb49a592a0dfbec5f211a7c2fed31d6)
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(S);
43      if (I != Deduplicator.end())
44        return I->second;
45  
46      Batch.Strings.push_back(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(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{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(DC->getLineInfoForAddress(SAddr).FileName);
75      for (auto &LInfo : LinesInfo) {
76        Method.LineTable.push_back(
77            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([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          {cantFail(shared::WrapperFunctionCall::Create<
105                    shared::SPSArgList<shared::SPSVTuneMethodBatch>>(
106               RegisterVTuneImplAddr, Batch)),
107           {}});
108      return Error::success();
109    });
110  }
111  
112  Error VTuneSupportPlugin::notifyEmitted(MaterializationResponsibility &MR) {
113    if (auto Err = MR.withResourceKeyDo([this, MR = &MR](ResourceKey K) {
114          std::lock_guard<std::mutex> Lock(PluginMutex);
115          auto I = PendingMethodIDs.find(MR);
116          if (I == PendingMethodIDs.end())
117            return;
118  
119          LoadedMethodIDs[K].push_back(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(&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(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            UnregisterVTuneImplAddr, 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(SrcKey);
160    if (I == LoadedMethodIDs.end())
161      return;
162  
163    auto &Dest = LoadedMethodIDs[DstKey];
164    Dest.insert(Dest.end(), I->second.begin(), I->second.end());
165    LoadedMethodIDs.erase(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(TestMode ? RegisterTestVTuneImplName : RegisterVTuneImplName);
174    auto UnregisterImplName = ES.intern(UnregisterVTuneImplName);
175    SymbolLookupSet SLS{RegisterImplName, UnregisterImplName};
176    auto Res = ES.lookup(makeJITDylibSearchOrder({&JD}), std::move(SLS));
177    if (!Res)
178      return Res.takeError();
179    ExecutorAddr RegisterImplAddr(
180        Res->find(RegisterImplName)->second.getAddress());
181    ExecutorAddr UnregisterImplAddr(
182        Res->find(UnregisterImplName)->second.getAddress());
183    return std::make_unique<VTuneSupportPlugin>(
184        EPC, RegisterImplAddr, UnregisterImplAddr, EmitDebugInfo);
185  }
186