1//===-- llvm-jitlistener.cpp - Utility for testing MCJIT event listener ---===//
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// This program is a used by lit tests to verify the MCJIT JITEventListener
10// interface. It registers a mock JIT event listener, generates a module from
11// an input IR file and dumps the reported event information to stdout.
12//
13//===----------------------------------------------------------------------===//
14
15#include "../../lib/ExecutionEngine/IntelJITProfiling/IntelJITEventsWrapper.h"
16#include "llvm/ExecutionEngine/JITEventListener.h"
17#include "llvm/ExecutionEngine/MCJIT.h"
18#include "llvm/ExecutionEngine/SectionMemoryManager.h"
19#include "llvm/IR/LLVMContext.h"
20#include "llvm/IR/Module.h"
21#include "llvm/IRReader/IRReader.h"
22#include "llvm/Support/CommandLine.h"
23#include "llvm/Support/Debug.h"
24#include "llvm/Support/InitLLVM.h"
25#include "llvm/Support/MemoryBuffer.h"
26#include "llvm/Support/SourceMgr.h"
27#include "llvm/Support/TargetSelect.h"
28#include "llvm/Support/raw_ostream.h"
29#include "llvm/TargetParser/Host.h"
30#include "llvm/TargetParser/Triple.h"
31#include <string>
32
33using namespace llvm;
34
35namespace {
36
37typedef std::vector<std::pair<std::string, unsigned int> > SourceLocations;
38typedef std::map<uint64_t, SourceLocations> NativeCodeMap;
39
40NativeCodeMap ReportedDebugFuncs;
41
42int NotifyEvent(iJIT_JVM_EVENT EventType, void *EventSpecificData) {
43 switch (EventType) {
44 case iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED: {
45 if (!EventSpecificData) {
46 errs() <<
47 "Error: The JIT event listener did not provide a event data.";
48 return -1;
49 }
50 iJIT_Method_Load* msg = static_cast<iJIT_Method_Load*>(EventSpecificData);
51
52 ReportedDebugFuncs[msg->method_id];
53
54 outs() << "Method load [" << msg->method_id << "]: " << msg->method_name
55 << ", Size = " << msg->method_size << "\n";
56
57 for(unsigned int i = 0; i < msg->line_number_size; ++i) {
58 if (!msg->line_number_table) {
59 errs() << "A function with a non-zero line count had no line table.";
60 return -1;
61 }
62 std::pair<std::string, unsigned int> loc(
63 std::string(msg->source_file_name),
64 msg->line_number_table[i].LineNumber);
65 ReportedDebugFuncs[msg->method_id].push_back(x: loc);
66 outs() << " Line info @ " << msg->line_number_table[i].Offset
67 << ": " << msg->source_file_name
68 << ", line " << msg->line_number_table[i].LineNumber << "\n";
69 }
70 outs() << "\n";
71 }
72 break;
73 case iJVM_EVENT_TYPE_METHOD_UNLOAD_START: {
74 if (!EventSpecificData) {
75 errs() <<
76 "Error: The JIT event listener did not provide a event data.";
77 return -1;
78 }
79 unsigned int UnloadId
80 = *reinterpret_cast<unsigned int*>(EventSpecificData);
81 assert(1 == ReportedDebugFuncs.erase(UnloadId));
82 outs() << "Method unload [" << UnloadId << "]\n";
83 }
84 break;
85 default:
86 break;
87 }
88 return 0;
89}
90
91int ittNotifyInfo(IttEventType EventType, const char *Name, unsigned int Size) {
92 switch (EventType) {
93 case LoadBinaryModule: {
94 if (!Name) {
95 errs() << "Error: The IttNotify event listener did not provide a module "
96 "name.";
97 return -1;
98 }
99 outs() << "Module loaded : Name = " << Name << ", Size = " << Size << "\n";
100 } break;
101 case LoadBinarySection: {
102 if (!Name) {
103 errs() << "Error: The IttNotify event listener did not provide a section "
104 "name.";
105 return -1;
106 }
107 outs() << "Loaded section : Name = " << Name << ", Size = " << Size << "\n";
108 } break;
109 case UnloadBinaryModule: {
110 if (!Name) {
111 errs() << "Error: The IttNotify event listener did not provide a module "
112 "name.";
113 return -1;
114 }
115 outs() << "Module unloaded : Name = " << Name << ", Size = " << Size
116 << "\n";
117 } break;
118 case UnloadBinarySection: {
119 if (!Name) {
120 errs() << "Error: The IttNotify event listener did not provide a section "
121 "name.";
122 return -1;
123 }
124 outs() << "Unloaded section : Name = " << Name << ", Size = " << Size
125 << "\n";
126 } break;
127 }
128 return 0;
129}
130
131iJIT_IsProfilingActiveFlags IsProfilingActive(void) {
132 // for testing, pretend we have an Intel Parallel Amplifier XE 2011
133 // instance attached
134 return iJIT_SAMPLING_ON;
135}
136
137unsigned int GetNewMethodID(void) {
138 static unsigned int id = 0;
139 return ++id;
140}
141
142class JitEventListenerTest {
143protected:
144 void InitEE(const std::string &IRFile) {
145 // If we have a native target, initialize it to ensure it is linked in and
146 // usable by the JIT.
147 InitializeNativeTarget();
148 InitializeNativeTargetAsmPrinter();
149
150 // Parse the bitcode...
151 SMDiagnostic Err;
152 std::unique_ptr<Module> TheModule(parseIRFile(Filename: IRFile, Err, Context));
153 if (!TheModule) {
154 errs() << Err.getMessage();
155 return;
156 }
157
158 RTDyldMemoryManager *MemMgr = new SectionMemoryManager();
159 if (!MemMgr) {
160 errs() << "Unable to create memory manager.";
161 return;
162 }
163
164 // Override the triple to generate ELF on Windows since that's supported
165 Triple Tuple(TheModule->getTargetTriple());
166 if (Tuple.getTriple().empty())
167 Tuple.setTriple(sys::getProcessTriple());
168
169 if (Tuple.isOSWindows() && !Tuple.isOSBinFormatELF()) {
170 Tuple.setObjectFormat(Triple::ELF);
171 TheModule->setTargetTriple(Tuple.getTriple());
172 }
173
174 // Compile the IR
175 std::string Error;
176 TheJIT.reset(p: EngineBuilder(std::move(TheModule))
177 .setEngineKind(EngineKind::JIT)
178 .setErrorStr(&Error)
179 .setMCJITMemoryManager(std::unique_ptr<RTDyldMemoryManager>(MemMgr))
180 .create());
181 if (Error.empty() == false)
182 errs() << Error;
183 }
184
185 void DestroyEE() {
186 TheJIT.reset();
187 }
188
189 LLVMContext Context; // Global ownership
190 std::unique_ptr<ExecutionEngine> TheJIT;
191
192public:
193 void ProcessInput(const std::string &Filename) {
194 InitEE(IRFile: Filename);
195
196 std::unique_ptr<llvm::JITEventListener> Listener(
197 JITEventListener::createIntelJITEventListener(AlternativeImpl: new IntelJITEventsWrapper(
198 NotifyEvent, ittNotifyInfo, 0, IsProfilingActive, 0, 0,
199 GetNewMethodID)));
200
201 TheJIT->RegisterJITEventListener(Listener.get());
202
203 TheJIT->finalizeObject();
204
205 // Destroy the JIT engine instead of unregistering to get unload events.
206 DestroyEE();
207 }
208};
209
210
211
212} // end anonymous namespace
213
214static cl::opt<std::string>
215InputFilename(cl::Positional, cl::desc("<input IR file>"),
216 cl::Required);
217
218int main(int argc, char **argv) {
219 InitLLVM X(argc, argv);
220 cl::ParseCommandLineOptions(argc, argv, Overview: "llvm jit event listener test utility\n");
221
222 JitEventListenerTest Test;
223 Test.ProcessInput(Filename: InputFilename);
224 return 0;
225}
226

source code of llvm/tools/llvm-jitlistener/llvm-jitlistener.cpp