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 | |
33 | using namespace llvm; |
34 | |
35 | namespace { |
36 | |
37 | typedef std::vector<std::pair<std::string, unsigned int> > SourceLocations; |
38 | typedef std::map<uint64_t, SourceLocations> NativeCodeMap; |
39 | |
40 | NativeCodeMap ReportedDebugFuncs; |
41 | |
42 | int 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 | |
91 | int 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 | |
131 | iJIT_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 | |
137 | unsigned int GetNewMethodID(void) { |
138 | static unsigned int id = 0; |
139 | return ++id; |
140 | } |
141 | |
142 | class JitEventListenerTest { |
143 | protected: |
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 | |
192 | public: |
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 | |
214 | static cl::opt<std::string> |
215 | InputFilename(cl::Positional, cl::desc("<input IR file>" ), |
216 | cl::Required); |
217 | |
218 | int 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 | |