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