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
20using namespace llvm;
21using namespace llvm::orc;
22
23namespace {
24class JITEventWrapper {
25public:
26 static std::unique_ptr<IntelJITEventsWrapper> Wrapper;
27};
28std::unique_ptr<IntelJITEventsWrapper> JITEventWrapper::Wrapper;
29} // namespace
30
31static 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
85static 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
94extern "C" llvm::orc::shared::CWrapperFunctionResult
95llvm_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
105extern "C" llvm::orc::shared::CWrapperFunctionResult
106llvm_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
114namespace {
115using SourceLocations = std::vector<std::pair<std::string, unsigned int>>;
116using NativeCodeMap = std::map<uint64_t, SourceLocations>;
117NativeCodeMap ReportedDebugFuncs;
118} // namespace
119
120static 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
165static 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
171static unsigned int GetNewMethodID(void) {
172 static unsigned int id = 0;
173 return ++id;
174}
175
176extern "C" llvm::orc::shared::CWrapperFunctionResult
177llvm_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
188using namespace llvm;
189using namespace llvm::orc;
190
191static Error unsupportedBatch(const VTuneMethodBatch &MB) {
192 return llvm::make_error<StringError>(Args: "unsupported for Intel VTune",
193 Args: inconvertibleErrorCode());
194}
195
196static void unsuppported(const std::vector<std::pair<uint64_t, uint64_t>> &UM) {
197
198}
199
200extern "C" llvm::orc::shared::CWrapperFunctionResult
201llvm_orc_registerVTuneImpl(const char *Data, uint64_t Size) {
202 using namespace orc::shared;
203 return WrapperFunction<SPSError(SPSVTuneMethodBatch)>::handle(
204 ArgData: Data, ArgSize: Size, Handler&: unsupportedBatch)
205 .release();
206}
207
208extern "C" llvm::orc::shared::CWrapperFunctionResult
209llvm_orc_unregisterVTuneImpl(const char *Data, uint64_t Size) {
210 using namespace orc::shared;
211 return WrapperFunction<void(SPSVTuneUnloadedMethodIDs)>::handle(ArgData: Data, ArgSize: Size,
212 Handler&: unsuppported)
213 .release();
214}
215
216extern "C" llvm::orc::shared::CWrapperFunctionResult
217llvm_orc_test_registerVTuneImpl(const char *Data, uint64_t Size) {
218 using namespace orc::shared;
219 return WrapperFunction<SPSError(SPSVTuneMethodBatch)>::handle(
220 ArgData: Data, ArgSize: Size, Handler&: unsupportedBatch)
221 .release();
222}
223
224#endif
225