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