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
registerJITLoaderVTuneRegisterImpl(const VTuneMethodBatch & MB)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
registerJITLoaderVTuneUnregisterImpl(const std::vector<std::pair<uint64_t,uint64_t>> & UM)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
llvm_orc_registerVTuneImpl(const char * Data,uint64_t Size)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
llvm_orc_unregisterVTuneImpl(const char * Data,uint64_t Size)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
NotifyEvent(iJIT_JVM_EVENT EventType,void * EventSpecificData)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
IsProfilingActive(void)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
GetNewMethodID(void)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
llvm_orc_test_registerVTuneImpl(const char * Data,uint64_t Size)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
unsupportedBatch(const VTuneMethodBatch & MB)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
unsuppported(const std::vector<std::pair<uint64_t,uint64_t>> & UM)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
llvm_orc_registerVTuneImpl(const char * Data,uint64_t Size)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
llvm_orc_unregisterVTuneImpl(const char * Data,uint64_t Size)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
llvm_orc_test_registerVTuneImpl(const char * Data,uint64_t Size)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