xref: /llvm-project/llvm/tools/llvm-jitlistener/llvm-jitlistener.cpp (revision de92615d68ff3ae206d5059f35a6e4ded8b38297)
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 
NotifyEvent(iJIT_JVM_EVENT EventType,void * EventSpecificData)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(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 
ittNotifyInfo(IttEventType EventType,const char * Name,unsigned int Size)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 
IsProfilingActive(void)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 
GetNewMethodID(void)137 unsigned int GetNewMethodID(void) {
138   static unsigned int id = 0;
139   return ++id;
140 }
141 
142 class JitEventListenerTest {
143 protected:
InitEE(const std::string & IRFile)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(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(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 
DestroyEE()185   void DestroyEE() {
186     TheJIT.reset();
187   }
188 
189   LLVMContext Context; // Global ownership
190   std::unique_ptr<ExecutionEngine> TheJIT;
191 
192 public:
ProcessInput(const std::string & Filename)193   void ProcessInput(const std::string &Filename) {
194     InitEE(Filename);
195 
196     std::unique_ptr<llvm::JITEventListener> Listener(
197         JITEventListener::createIntelJITEventListener(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 
main(int argc,char ** argv)218 int main(int argc, char **argv) {
219   InitLLVM X(argc, argv);
220   cl::ParseCommandLineOptions(argc, argv, "llvm jit event listener test utility\n");
221 
222   JitEventListenerTest Test;
223   Test.ProcessInput(InputFilename);
224   return 0;
225 }
226