//===------- JITLoaderVTune.cpp - Register profiler objects -----*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Register objects for access by profilers via the VTune JIT interface. //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderVTune.h" #include "llvm/ExecutionEngine/Orc/Shared/VTuneSharedStructs.h" #include #if LLVM_USE_INTEL_JITEVENTS #include "IntelJITEventsWrapper.h" #include "ittnotify.h" using namespace llvm; using namespace llvm::orc; namespace { class JITEventWrapper { public: static std::unique_ptr Wrapper; }; std::unique_ptr JITEventWrapper::Wrapper; } // namespace static Error registerJITLoaderVTuneRegisterImpl(const VTuneMethodBatch &MB) { const size_t StringsSize = MB.Strings.size(); for (const auto &MethodInfo : MB.Methods) { iJIT_Method_Load MethodMessage; memset(&MethodMessage, 0, sizeof(iJIT_Method_Load)); MethodMessage.method_id = MethodInfo.MethodID; if (MethodInfo.NameSI != 0 && MethodInfo.NameSI < StringsSize) { MethodMessage.method_name = const_cast(MB.Strings.at(MethodInfo.NameSI).data()); } else { MethodMessage.method_name = NULL; } if (MethodInfo.ClassFileSI != 0 && MethodInfo.ClassFileSI < StringsSize) { MethodMessage.class_file_name = const_cast(MB.Strings.at(MethodInfo.ClassFileSI).data()); } else { MethodMessage.class_file_name = NULL; } if (MethodInfo.SourceFileSI != 0 && MethodInfo.SourceFileSI < StringsSize) { MethodMessage.source_file_name = const_cast(MB.Strings.at(MethodInfo.SourceFileSI).data()); } else { MethodMessage.source_file_name = NULL; } MethodMessage.method_load_address = MethodInfo.LoadAddr.toPtr(); MethodMessage.method_size = MethodInfo.LoadSize; MethodMessage.class_id = 0; MethodMessage.user_data = NULL; MethodMessage.user_data_size = 0; MethodMessage.env = iJDE_JittingAPI; std::vector LineInfo; for (const auto &LInfo : MethodInfo.LineTable) { LineInfo.push_back(LineNumberInfo{LInfo.first, LInfo.second}); } if (LineInfo.size() == 0) { MethodMessage.line_number_size = 0; MethodMessage.line_number_table = 0; } else { MethodMessage.line_number_size = LineInfo.size(); MethodMessage.line_number_table = &*LineInfo.begin(); } JITEventWrapper::Wrapper->iJIT_NotifyEvent( iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &MethodMessage); } return Error::success(); } static void registerJITLoaderVTuneUnregisterImpl( const std::vector> &UM) { for (auto &Method : UM) { JITEventWrapper::Wrapper->iJIT_NotifyEvent( iJVM_EVENT_TYPE_METHOD_UNLOAD_START, const_cast(&Method.first)); } } extern "C" llvm::orc::shared::CWrapperFunctionResult llvm_orc_registerVTuneImpl(const char *Data, uint64_t Size) { using namespace orc::shared; if (!JITEventWrapper::Wrapper) JITEventWrapper::Wrapper.reset(new IntelJITEventsWrapper); return WrapperFunction::handle( Data, Size, registerJITLoaderVTuneRegisterImpl) .release(); } extern "C" llvm::orc::shared::CWrapperFunctionResult llvm_orc_unregisterVTuneImpl(const char *Data, uint64_t Size) { using namespace orc::shared; return WrapperFunction::handle( Data, Size, registerJITLoaderVTuneUnregisterImpl) .release(); } // For Testing: following code comes from llvm-jitlistener.cpp in llvm tools namespace { using SourceLocations = std::vector>; using NativeCodeMap = std::map; NativeCodeMap ReportedDebugFuncs; } // namespace static int NotifyEvent(iJIT_JVM_EVENT EventType, void *EventSpecificData) { switch (EventType) { case iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED: { if (!EventSpecificData) { errs() << "Error: The JIT event listener did not provide a event data."; return -1; } iJIT_Method_Load *msg = static_cast(EventSpecificData); ReportedDebugFuncs[msg->method_id]; outs() << "Method load [" << msg->method_id << "]: " << msg->method_name << ", Size = " << msg->method_size << "\n"; for (unsigned int i = 0; i < msg->line_number_size; ++i) { if (!msg->line_number_table) { errs() << "A function with a non-zero line count had no line table."; return -1; } std::pair loc( std::string(msg->source_file_name), msg->line_number_table[i].LineNumber); ReportedDebugFuncs[msg->method_id].push_back(loc); outs() << " Line info @ " << msg->line_number_table[i].Offset << ": " << msg->source_file_name << ", line " << msg->line_number_table[i].LineNumber << "\n"; } outs() << "\n"; } break; case iJVM_EVENT_TYPE_METHOD_UNLOAD_START: { if (!EventSpecificData) { errs() << "Error: The JIT event listener did not provide a event data."; return -1; } unsigned int UnloadId = *reinterpret_cast(EventSpecificData); assert(1 == ReportedDebugFuncs.erase(UnloadId)); outs() << "Method unload [" << UnloadId << "]\n"; } break; default: break; } return 0; } static iJIT_IsProfilingActiveFlags IsProfilingActive(void) { // for testing, pretend we have an Intel Parallel Amplifier XE 2011 // instance attached return iJIT_SAMPLING_ON; } static unsigned int GetNewMethodID(void) { static unsigned int id = 0; return ++id; } extern "C" llvm::orc::shared::CWrapperFunctionResult llvm_orc_test_registerVTuneImpl(const char *Data, uint64_t Size) { using namespace orc::shared; JITEventWrapper::Wrapper.reset(new IntelJITEventsWrapper( NotifyEvent, NULL, NULL, IsProfilingActive, 0, 0, GetNewMethodID)); return WrapperFunction::handle( Data, Size, registerJITLoaderVTuneRegisterImpl) .release(); } #else using namespace llvm; using namespace llvm::orc; static Error unsupportedBatch(const VTuneMethodBatch &MB) { return llvm::make_error("unsupported for Intel VTune", inconvertibleErrorCode()); } static void unsuppported(const std::vector> &UM) { } extern "C" llvm::orc::shared::CWrapperFunctionResult llvm_orc_registerVTuneImpl(const char *Data, uint64_t Size) { using namespace orc::shared; return WrapperFunction::handle( Data, Size, unsupportedBatch) .release(); } extern "C" llvm::orc::shared::CWrapperFunctionResult llvm_orc_unregisterVTuneImpl(const char *Data, uint64_t Size) { using namespace orc::shared; return WrapperFunction::handle(Data, Size, unsuppported) .release(); } extern "C" llvm::orc::shared::CWrapperFunctionResult llvm_orc_test_registerVTuneImpl(const char *Data, uint64_t Size) { using namespace orc::shared; return WrapperFunction::handle( Data, Size, unsupportedBatch) .release(); } #endif