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