xref: /freebsd-src/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/JITLoaderVTune.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric //===------- JITLoaderVTune.cpp - Register profiler objects -----*- C++ -*-===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric //
9*0fca6ea1SDimitry Andric // Register objects for access by profilers via the VTune JIT interface.
10*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
11*0fca6ea1SDimitry Andric 
12*0fca6ea1SDimitry Andric #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderVTune.h"
13*0fca6ea1SDimitry Andric #include "llvm/ExecutionEngine/Orc/Shared/VTuneSharedStructs.h"
14*0fca6ea1SDimitry Andric #include <map>
15*0fca6ea1SDimitry Andric 
16*0fca6ea1SDimitry Andric #if LLVM_USE_INTEL_JITEVENTS
17*0fca6ea1SDimitry Andric #include "IntelJITEventsWrapper.h"
18*0fca6ea1SDimitry Andric #include "ittnotify.h"
19*0fca6ea1SDimitry Andric 
20*0fca6ea1SDimitry Andric using namespace llvm;
21*0fca6ea1SDimitry Andric using namespace llvm::orc;
22*0fca6ea1SDimitry Andric 
23*0fca6ea1SDimitry Andric namespace {
24*0fca6ea1SDimitry Andric class JITEventWrapper {
25*0fca6ea1SDimitry Andric public:
26*0fca6ea1SDimitry Andric   static std::unique_ptr<IntelJITEventsWrapper> Wrapper;
27*0fca6ea1SDimitry Andric };
28*0fca6ea1SDimitry Andric std::unique_ptr<IntelJITEventsWrapper> JITEventWrapper::Wrapper;
29*0fca6ea1SDimitry Andric } // namespace
30*0fca6ea1SDimitry Andric 
31*0fca6ea1SDimitry Andric static Error registerJITLoaderVTuneRegisterImpl(const VTuneMethodBatch &MB) {
32*0fca6ea1SDimitry Andric   const size_t StringsSize = MB.Strings.size();
33*0fca6ea1SDimitry Andric 
34*0fca6ea1SDimitry Andric   for (const auto &MethodInfo : MB.Methods) {
35*0fca6ea1SDimitry Andric     iJIT_Method_Load MethodMessage;
36*0fca6ea1SDimitry Andric     memset(&MethodMessage, 0, sizeof(iJIT_Method_Load));
37*0fca6ea1SDimitry Andric 
38*0fca6ea1SDimitry Andric     MethodMessage.method_id = MethodInfo.MethodID;
39*0fca6ea1SDimitry Andric     if (MethodInfo.NameSI != 0 && MethodInfo.NameSI < StringsSize) {
40*0fca6ea1SDimitry Andric       MethodMessage.method_name =
41*0fca6ea1SDimitry Andric           const_cast<char *>(MB.Strings.at(MethodInfo.NameSI).data());
42*0fca6ea1SDimitry Andric     } else {
43*0fca6ea1SDimitry Andric       MethodMessage.method_name = NULL;
44*0fca6ea1SDimitry Andric     }
45*0fca6ea1SDimitry Andric     if (MethodInfo.ClassFileSI != 0 && MethodInfo.ClassFileSI < StringsSize) {
46*0fca6ea1SDimitry Andric       MethodMessage.class_file_name =
47*0fca6ea1SDimitry Andric           const_cast<char *>(MB.Strings.at(MethodInfo.ClassFileSI).data());
48*0fca6ea1SDimitry Andric     } else {
49*0fca6ea1SDimitry Andric       MethodMessage.class_file_name = NULL;
50*0fca6ea1SDimitry Andric     }
51*0fca6ea1SDimitry Andric     if (MethodInfo.SourceFileSI != 0 && MethodInfo.SourceFileSI < StringsSize) {
52*0fca6ea1SDimitry Andric       MethodMessage.source_file_name =
53*0fca6ea1SDimitry Andric           const_cast<char *>(MB.Strings.at(MethodInfo.SourceFileSI).data());
54*0fca6ea1SDimitry Andric     } else {
55*0fca6ea1SDimitry Andric       MethodMessage.source_file_name = NULL;
56*0fca6ea1SDimitry Andric     }
57*0fca6ea1SDimitry Andric 
58*0fca6ea1SDimitry Andric     MethodMessage.method_load_address = MethodInfo.LoadAddr.toPtr<void *>();
59*0fca6ea1SDimitry Andric     MethodMessage.method_size = MethodInfo.LoadSize;
60*0fca6ea1SDimitry Andric     MethodMessage.class_id = 0;
61*0fca6ea1SDimitry Andric 
62*0fca6ea1SDimitry Andric     MethodMessage.user_data = NULL;
63*0fca6ea1SDimitry Andric     MethodMessage.user_data_size = 0;
64*0fca6ea1SDimitry Andric     MethodMessage.env = iJDE_JittingAPI;
65*0fca6ea1SDimitry Andric 
66*0fca6ea1SDimitry Andric     std::vector<LineNumberInfo> LineInfo;
67*0fca6ea1SDimitry Andric     for (const auto &LInfo : MethodInfo.LineTable) {
68*0fca6ea1SDimitry Andric       LineInfo.push_back(LineNumberInfo{LInfo.first, LInfo.second});
69*0fca6ea1SDimitry Andric     }
70*0fca6ea1SDimitry Andric 
71*0fca6ea1SDimitry Andric     if (LineInfo.size() == 0) {
72*0fca6ea1SDimitry Andric       MethodMessage.line_number_size = 0;
73*0fca6ea1SDimitry Andric       MethodMessage.line_number_table = 0;
74*0fca6ea1SDimitry Andric     } else {
75*0fca6ea1SDimitry Andric       MethodMessage.line_number_size = LineInfo.size();
76*0fca6ea1SDimitry Andric       MethodMessage.line_number_table = &*LineInfo.begin();
77*0fca6ea1SDimitry Andric     }
78*0fca6ea1SDimitry Andric     JITEventWrapper::Wrapper->iJIT_NotifyEvent(
79*0fca6ea1SDimitry Andric         iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &MethodMessage);
80*0fca6ea1SDimitry Andric   }
81*0fca6ea1SDimitry Andric 
82*0fca6ea1SDimitry Andric   return Error::success();
83*0fca6ea1SDimitry Andric }
84*0fca6ea1SDimitry Andric 
85*0fca6ea1SDimitry Andric static void registerJITLoaderVTuneUnregisterImpl(
86*0fca6ea1SDimitry Andric     const std::vector<std::pair<uint64_t, uint64_t>> &UM) {
87*0fca6ea1SDimitry Andric   for (auto &Method : UM) {
88*0fca6ea1SDimitry Andric     JITEventWrapper::Wrapper->iJIT_NotifyEvent(
89*0fca6ea1SDimitry Andric         iJVM_EVENT_TYPE_METHOD_UNLOAD_START,
90*0fca6ea1SDimitry Andric         const_cast<uint64_t *>(&Method.first));
91*0fca6ea1SDimitry Andric   }
92*0fca6ea1SDimitry Andric }
93*0fca6ea1SDimitry Andric 
94*0fca6ea1SDimitry Andric extern "C" llvm::orc::shared::CWrapperFunctionResult
95*0fca6ea1SDimitry Andric llvm_orc_registerVTuneImpl(const char *Data, uint64_t Size) {
96*0fca6ea1SDimitry Andric   using namespace orc::shared;
97*0fca6ea1SDimitry Andric   if (!JITEventWrapper::Wrapper)
98*0fca6ea1SDimitry Andric     JITEventWrapper::Wrapper.reset(new IntelJITEventsWrapper);
99*0fca6ea1SDimitry Andric 
100*0fca6ea1SDimitry Andric   return WrapperFunction<SPSError(SPSVTuneMethodBatch)>::handle(
101*0fca6ea1SDimitry Andric              Data, Size, registerJITLoaderVTuneRegisterImpl)
102*0fca6ea1SDimitry Andric       .release();
103*0fca6ea1SDimitry Andric }
104*0fca6ea1SDimitry Andric 
105*0fca6ea1SDimitry Andric extern "C" llvm::orc::shared::CWrapperFunctionResult
106*0fca6ea1SDimitry Andric llvm_orc_unregisterVTuneImpl(const char *Data, uint64_t Size) {
107*0fca6ea1SDimitry Andric   using namespace orc::shared;
108*0fca6ea1SDimitry Andric   return WrapperFunction<void(SPSVTuneUnloadedMethodIDs)>::handle(
109*0fca6ea1SDimitry Andric              Data, Size, registerJITLoaderVTuneUnregisterImpl)
110*0fca6ea1SDimitry Andric       .release();
111*0fca6ea1SDimitry Andric }
112*0fca6ea1SDimitry Andric 
113*0fca6ea1SDimitry Andric // For Testing: following code comes from llvm-jitlistener.cpp in llvm tools
114*0fca6ea1SDimitry Andric namespace {
115*0fca6ea1SDimitry Andric using SourceLocations = std::vector<std::pair<std::string, unsigned int>>;
116*0fca6ea1SDimitry Andric using NativeCodeMap = std::map<uint64_t, SourceLocations>;
117*0fca6ea1SDimitry Andric NativeCodeMap ReportedDebugFuncs;
118*0fca6ea1SDimitry Andric } // namespace
119*0fca6ea1SDimitry Andric 
120*0fca6ea1SDimitry Andric static int NotifyEvent(iJIT_JVM_EVENT EventType, void *EventSpecificData) {
121*0fca6ea1SDimitry Andric   switch (EventType) {
122*0fca6ea1SDimitry Andric   case iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED: {
123*0fca6ea1SDimitry Andric     if (!EventSpecificData) {
124*0fca6ea1SDimitry Andric       errs() << "Error: The JIT event listener did not provide a event data.";
125*0fca6ea1SDimitry Andric       return -1;
126*0fca6ea1SDimitry Andric     }
127*0fca6ea1SDimitry Andric     iJIT_Method_Load *msg = static_cast<iJIT_Method_Load *>(EventSpecificData);
128*0fca6ea1SDimitry Andric 
129*0fca6ea1SDimitry Andric     ReportedDebugFuncs[msg->method_id];
130*0fca6ea1SDimitry Andric 
131*0fca6ea1SDimitry Andric     outs() << "Method load [" << msg->method_id << "]: " << msg->method_name
132*0fca6ea1SDimitry Andric            << ", Size = " << msg->method_size << "\n";
133*0fca6ea1SDimitry Andric 
134*0fca6ea1SDimitry Andric     for (unsigned int i = 0; i < msg->line_number_size; ++i) {
135*0fca6ea1SDimitry Andric       if (!msg->line_number_table) {
136*0fca6ea1SDimitry Andric         errs() << "A function with a non-zero line count had no line table.";
137*0fca6ea1SDimitry Andric         return -1;
138*0fca6ea1SDimitry Andric       }
139*0fca6ea1SDimitry Andric       std::pair<std::string, unsigned int> loc(
140*0fca6ea1SDimitry Andric           std::string(msg->source_file_name),
141*0fca6ea1SDimitry Andric           msg->line_number_table[i].LineNumber);
142*0fca6ea1SDimitry Andric       ReportedDebugFuncs[msg->method_id].push_back(loc);
143*0fca6ea1SDimitry Andric       outs() << "  Line info @ " << msg->line_number_table[i].Offset << ": "
144*0fca6ea1SDimitry Andric              << msg->source_file_name << ", line "
145*0fca6ea1SDimitry Andric              << msg->line_number_table[i].LineNumber << "\n";
146*0fca6ea1SDimitry Andric     }
147*0fca6ea1SDimitry Andric     outs() << "\n";
148*0fca6ea1SDimitry Andric   } break;
149*0fca6ea1SDimitry Andric   case iJVM_EVENT_TYPE_METHOD_UNLOAD_START: {
150*0fca6ea1SDimitry Andric     if (!EventSpecificData) {
151*0fca6ea1SDimitry Andric       errs() << "Error: The JIT event listener did not provide a event data.";
152*0fca6ea1SDimitry Andric       return -1;
153*0fca6ea1SDimitry Andric     }
154*0fca6ea1SDimitry Andric     unsigned int UnloadId =
155*0fca6ea1SDimitry Andric         *reinterpret_cast<unsigned int *>(EventSpecificData);
156*0fca6ea1SDimitry Andric     assert(1 == ReportedDebugFuncs.erase(UnloadId));
157*0fca6ea1SDimitry Andric     outs() << "Method unload [" << UnloadId << "]\n";
158*0fca6ea1SDimitry Andric   } break;
159*0fca6ea1SDimitry Andric   default:
160*0fca6ea1SDimitry Andric     break;
161*0fca6ea1SDimitry Andric   }
162*0fca6ea1SDimitry Andric   return 0;
163*0fca6ea1SDimitry Andric }
164*0fca6ea1SDimitry Andric 
165*0fca6ea1SDimitry Andric static iJIT_IsProfilingActiveFlags IsProfilingActive(void) {
166*0fca6ea1SDimitry Andric   // for testing, pretend we have an Intel Parallel Amplifier XE 2011
167*0fca6ea1SDimitry Andric   // instance attached
168*0fca6ea1SDimitry Andric   return iJIT_SAMPLING_ON;
169*0fca6ea1SDimitry Andric }
170*0fca6ea1SDimitry Andric 
171*0fca6ea1SDimitry Andric static unsigned int GetNewMethodID(void) {
172*0fca6ea1SDimitry Andric   static unsigned int id = 0;
173*0fca6ea1SDimitry Andric   return ++id;
174*0fca6ea1SDimitry Andric }
175*0fca6ea1SDimitry Andric 
176*0fca6ea1SDimitry Andric extern "C" llvm::orc::shared::CWrapperFunctionResult
177*0fca6ea1SDimitry Andric llvm_orc_test_registerVTuneImpl(const char *Data, uint64_t Size) {
178*0fca6ea1SDimitry Andric   using namespace orc::shared;
179*0fca6ea1SDimitry Andric   JITEventWrapper::Wrapper.reset(new IntelJITEventsWrapper(
180*0fca6ea1SDimitry Andric       NotifyEvent, NULL, NULL, IsProfilingActive, 0, 0, GetNewMethodID));
181*0fca6ea1SDimitry Andric   return WrapperFunction<SPSError(SPSVTuneMethodBatch)>::handle(
182*0fca6ea1SDimitry Andric              Data, Size, registerJITLoaderVTuneRegisterImpl)
183*0fca6ea1SDimitry Andric       .release();
184*0fca6ea1SDimitry Andric }
185*0fca6ea1SDimitry Andric 
186*0fca6ea1SDimitry Andric #else
187*0fca6ea1SDimitry Andric 
188*0fca6ea1SDimitry Andric using namespace llvm;
189*0fca6ea1SDimitry Andric using namespace llvm::orc;
190*0fca6ea1SDimitry Andric 
191*0fca6ea1SDimitry Andric static Error unsupportedBatch(const VTuneMethodBatch &MB) {
192*0fca6ea1SDimitry Andric   return llvm::make_error<StringError>("unsupported for Intel VTune",
193*0fca6ea1SDimitry Andric                                        inconvertibleErrorCode());
194*0fca6ea1SDimitry Andric }
195*0fca6ea1SDimitry Andric 
196*0fca6ea1SDimitry Andric static void unsuppported(const std::vector<std::pair<uint64_t, uint64_t>> &UM) {
197*0fca6ea1SDimitry Andric 
198*0fca6ea1SDimitry Andric }
199*0fca6ea1SDimitry Andric 
200*0fca6ea1SDimitry Andric extern "C" llvm::orc::shared::CWrapperFunctionResult
201*0fca6ea1SDimitry Andric llvm_orc_registerVTuneImpl(const char *Data, uint64_t Size) {
202*0fca6ea1SDimitry Andric   using namespace orc::shared;
203*0fca6ea1SDimitry Andric   return WrapperFunction<SPSError(SPSVTuneMethodBatch)>::handle(
204*0fca6ea1SDimitry Andric              Data, Size, unsupportedBatch)
205*0fca6ea1SDimitry Andric       .release();
206*0fca6ea1SDimitry Andric }
207*0fca6ea1SDimitry Andric 
208*0fca6ea1SDimitry Andric extern "C" llvm::orc::shared::CWrapperFunctionResult
209*0fca6ea1SDimitry Andric llvm_orc_unregisterVTuneImpl(const char *Data, uint64_t Size) {
210*0fca6ea1SDimitry Andric   using namespace orc::shared;
211*0fca6ea1SDimitry Andric   return WrapperFunction<void(SPSVTuneUnloadedMethodIDs)>::handle(Data, Size,
212*0fca6ea1SDimitry Andric                                                                   unsuppported)
213*0fca6ea1SDimitry Andric       .release();
214*0fca6ea1SDimitry Andric }
215*0fca6ea1SDimitry Andric 
216*0fca6ea1SDimitry Andric extern "C" llvm::orc::shared::CWrapperFunctionResult
217*0fca6ea1SDimitry Andric llvm_orc_test_registerVTuneImpl(const char *Data, uint64_t Size) {
218*0fca6ea1SDimitry Andric   using namespace orc::shared;
219*0fca6ea1SDimitry Andric   return WrapperFunction<SPSError(SPSVTuneMethodBatch)>::handle(
220*0fca6ea1SDimitry Andric              Data, Size, unsupportedBatch)
221*0fca6ea1SDimitry Andric       .release();
222*0fca6ea1SDimitry Andric }
223*0fca6ea1SDimitry Andric 
224*0fca6ea1SDimitry Andric #endif
225