llvm.org GIT mirror llvm / c4c8d7b
Add PerfJITEventListener for perf profiling support. This new JIT event listener supports generating profiling data for the linux 'perf' profiling tool, allowing it to generate function and instruction level profiles. Currently this functionality is not enabled by default, but must be enabled with LLVM_USE_PERF=yes. Given that the listener has no dependencies, it might be sensible to enable by default once the initial issues have been shaken out. I followed existing precedent in registering the listener by default in lli. Should there be a decision to enable this by default on linux, that should probably be changed. Please note that until https://reviews.llvm.org/D47343 is resolved, using this functionality with mcjit rather than orcjit will not reliably work. Disregarding the previous comment, here's an example: $ cat /tmp/expensive_loop.c bool stupid_isprime(uint64_t num) { if (num == 2) return true; if (num < 1 || num % 2 == 0) return false; for(uint64_t i = 3; i < num / 2; i+= 2) { if (num % i == 0) return false; } return true; } int main(int argc, char **argv) { int numprimes = 0; for (uint64_t num = argc; num < 100000; num++) { if (stupid_isprime(num)) numprimes++; } return numprimes; } $ clang -ggdb -S -c -emit-llvm /tmp/expensive_loop.c -o /tmp/expensive_loop.ll $ perf record -o perf.data -g -k 1 ./bin/lli -jit-kind=mcjit /tmp/expensive_loop.ll 1 $ perf inject --jit -i perf.data -o perf.jit.data $ perf report -i perf.jit.data - 92.59% lli jitted-5881-2.so [.] stupid_isprime stupid_isprime main llvm::MCJIT::runFunction llvm::ExecutionEngine::runFunctionAsMain main __libc_start_main 0x4bf6258d4c544155 + 0.85% lli ld-2.27.so [.] do_lookup_x And line-level annotations also work: │ for(uint64_t i = 3; i < num / 2; i+= 2) { │1 30: movq $0x3,-0x18(%rbp) 0.03 │1 38: mov -0x18(%rbp),%rax 0.03 │ mov -0x10(%rbp),%rcx │ shr $0x1,%rcx 3.63 │ ┌──cmp %rcx,%rax │ ├──jae 6f │ │ if (num % i == 0) 0.03 │ │ mov -0x10(%rbp),%rax │ │ xor %edx,%edx 89.00 │ │ divq -0x18(%rbp) │ │ cmp $0x0,%rdx 0.22 │ │↓ jne 5f │ │ return false; │ │ movb $0x0,-0x1(%rbp) │ │↓ jmp 73 │ │ } 3.22 │1 5f:│↓ jmp 61 │ │ for(uint64_t i = 3; i < num / 2; i+= 2) { Subscribers: mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D44892 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@337789 91177308-0d34-0410-b5e6-96231b3b80d8 Andres Freund 1 year, 1 month ago
12 changed file(s) with 574 addition(s) and 1 deletion(s). Raw diff Collapse all Expand all
434434 endif( NOT CMAKE_SYSTEM_NAME MATCHES "Linux" )
435435 endif( LLVM_USE_OPROFILE )
436436
437 option(LLVM_USE_PERF
438 "Use perf JIT interface to inform perf about JIT code" OFF)
439
440 # If enabled, verify we are on a platform that supports perf.
441 if( LLVM_USE_PERF )
442 if( NOT CMAKE_SYSTEM_NAME MATCHES "Linux" )
443 message(FATAL_ERROR "perf support is available on Linux only.")
444 endif( NOT CMAKE_SYSTEM_NAME MATCHES "Linux" )
445 endif( LLVM_USE_PERF )
446
437447 set(LLVM_USE_SANITIZER "" CACHE STRING
438448 "Define the sanitizer used to build binaries and tests.")
439449 option(LLVM_OPTIMIZE_SANITIZED_BUILDS "Pass -O1 on debug sanitizer builds" ON)
647657 if (LLVM_USE_OPROFILE)
648658 set(LLVMOPTIONALCOMPONENTS ${LLVMOPTIONALCOMPONENTS} OProfileJIT)
649659 endif (LLVM_USE_OPROFILE)
660 if (LLVM_USE_PERF)
661 set(LLVMOPTIONALCOMPONENTS ${LLVMOPTIONALCOMPONENTS} PerfJITEvents)
662 endif (LLVM_USE_PERF)
650663
651664 message(STATUS "Constructing LLVMBuild project information")
652665 execute_process(
374374 tools.
375375 Defaults to ON.
376376
377 **LLVM_USE_PERF**:BOOL
378 Enable building support for Perf (linux profiling tool) JIT support. Defaults to OFF.
379
377380 **LLVM_ENABLE_ZLIB**:BOOL
378381 Enable building with zlib to support compression/uncompression in LLVM tools.
379382 Defaults to ON.
6161 /* Define if we have the oprofile JIT-support library */
6262 #cmakedefine01 LLVM_USE_OPROFILE
6363
64 /* Define if we have the perf JIT-support library */
65 #cmakedefine01 LLVM_USE_PERF
66
6467 /* Major version of the LLVM API */
6568 #define LLVM_VERSION_MAJOR ${LLVM_VERSION_MAJOR}
6669
116116 }
117117 #endif // USE_OPROFILE
118118
119 #if LLVM_USE_PERF
120 static JITEventListener *createPerfJITEventListener();
121 #else
122 static JITEventListener *createPerfJITEventListener()
123 {
124 return nullptr;
125 }
126 #endif // USE_PERF
127
119128 private:
120129 virtual void anchor();
121130 };
132141 LLVMJITEventListenerRef LLVMCreateOProfileJITEventListener(void);
133142 #endif
134143
144 #ifndef LLVM_USE_PERF
145 LLVMJITEventListenerRef LLVMCreatePerfJITEventListener(void);
146 #endif
147
135148 #endif // LLVM_EXECUTIONENGINE_JITEVENTLISTENER_H
186186 LLVMJITEventListenerRef LLVMCreateGDBRegistrationListener(void);
187187 LLVMJITEventListenerRef LLVMCreateIntelJITEventListener(void);
188188 LLVMJITEventListenerRef LLVMCreateOprofileJITEventListener(void);
189 LLVMJITEventListenerRef LLVMCreatePerfJITEventListener(void);
189190
190191 /**
191192 * @}
2929 if( LLVM_USE_INTEL_JITEVENTS )
3030 add_subdirectory(IntelJITEvents)
3131 endif( LLVM_USE_INTEL_JITEVENTS )
32
33 if( LLVM_USE_PERF )
34 add_subdirectory(PerfJITEvents)
35 endif( LLVM_USE_PERF )
1515 ;===------------------------------------------------------------------------===;
1616
1717 [common]
18 subdirectories = Interpreter MCJIT RuntimeDyld IntelJITEvents OProfileJIT Orc
18 subdirectories = Interpreter MCJIT RuntimeDyld IntelJITEvents OProfileJIT Orc PerfJITEvents
1919
2020 [component_0]
2121 type = Library
0 add_llvm_library(LLVMPerfJITEvents
1 PerfJITEventListener.cpp
2 )
3
4 add_dependencies(LLVMPerfJITEvents LLVMCodeGen)
0 ;===- ./lib/ExecutionEngine/PerfJITEvents/LLVMBuild.txt ----------------*- Conf -*--===;
1 ;
2 ; The LLVM Compiler Infrastructure
3 ;
4 ; This file is distributed under the University of Illinois Open Source
5 ; License. See LICENSE.TXT for details.
6 ;
7 ;===------------------------------------------------------------------------===;
8 ;
9 ; This is an LLVMBuild description file for the components in this subdirectory.
10 ;
11 ; For more information on the LLVMBuild system, please see:
12 ;
13 ; http://llvm.org/docs/LLVMBuild.html
14 ;
15 ;===------------------------------------------------------------------------===;
16
17 [component_0]
18 type = OptionalLibrary
19 name = PerfJITEvents
20 parent = ExecutionEngine
21 required_libraries = CodeGen Core DebugInfoDWARF ExecutionEngine Object Support
0 //===-- PerfJITEventListener.cpp - Tell Linux's perf about JITted code ----===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines a JITEventListener object that tells perf about JITted
10 // functions, including source line information.
11 //
12 // Documentation for perf jit integration is available at:
13 // https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/tools/perf/Documentation/jitdump-specification.txt
14 // https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/tools/perf/Documentation/jit-interface.txt
15 //
16 //===----------------------------------------------------------------------===//
17
18 #include "llvm/ADT/Twine.h"
19 #include "llvm/Config/config.h"
20 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
21 #include "llvm/ExecutionEngine/JITEventListener.h"
22 #include "llvm/Object/ObjectFile.h"
23 #include "llvm/Object/SymbolSize.h"
24 #include "llvm/Support/Debug.h"
25 #include "llvm/Support/Errno.h"
26 #include "llvm/Support/FileSystem.h"
27 #include "llvm/Support/MemoryBuffer.h"
28 #include "llvm/Support/Mutex.h"
29 #include "llvm/Support/MutexGuard.h"
30 #include "llvm/Support/Path.h"
31 #include "llvm/Support/Process.h"
32 #include "llvm/Support/Threading.h"
33 #include "llvm/Support/raw_ostream.h"
34
35 #include // mmap()
36 #include // getpid()
37 #include // clock_gettime(), time(), localtime_r() */
38 #include // for getpid(), read(), close()
39
40 using namespace llvm;
41 using namespace llvm::object;
42 typedef DILineInfoSpecifier::FileLineInfoKind FileLineInfoKind;
43
44 namespace {
45
46 // language identifier (XXX: should we generate something better from debug
47 // info?)
48 #define JIT_LANG "llvm-IR"
49 #define LLVM_PERF_JIT_MAGIC \
50 ((uint32_t)'J' << 24 | (uint32_t)'i' << 16 | (uint32_t)'T' << 8 | \
51 (uint32_t)'D')
52 #define LLVM_PERF_JIT_VERSION 1
53
54 // bit 0: set if the jitdump file is using an architecture-specific timestamp
55 // clock source
56 #define JITDUMP_FLAGS_ARCH_TIMESTAMP (1ULL << 0)
57
58 struct LLVMPerfJitHeader;
59
60 class PerfJITEventListener : public JITEventListener {
61 public:
62 PerfJITEventListener();
63 ~PerfJITEventListener() {
64 if (MarkerAddr)
65 CloseMarker();
66 }
67
68 void NotifyObjectEmitted(const ObjectFile &Obj,
69 const RuntimeDyld::LoadedObjectInfo &L) override;
70 void NotifyFreeingObject(const ObjectFile &Obj) override;
71
72 private:
73 bool InitDebuggingDir();
74 bool OpenMarker();
75 void CloseMarker();
76 static bool FillMachine(LLVMPerfJitHeader &hdr);
77
78 void NotifyCode(Expected &Symbol, uint64_t CodeAddr,
79 uint64_t CodeSize);
80 void NotifyDebug(uint64_t CodeAddr, DILineInfoTable Lines);
81
82 // cache lookups
83 pid_t Pid;
84
85 // base directory for output data
86 std::string JitPath;
87
88 // output data stream, closed via Dumpstream
89 int DumpFd = -1;
90
91 // output data stream
92 std::unique_ptr Dumpstream;
93
94 // prevent concurrent dumps from messing up the output file
95 sys::Mutex Mutex;
96
97 // perf mmap marker
98 void *MarkerAddr = NULL;
99
100 // perf support ready
101 bool SuccessfullyInitialized = false;
102
103 // identifier for functions, primarily to identify when moving them around
104 uint64_t CodeGeneration = 1;
105 };
106
107 // The following are POD struct definitions from the perf jit specification
108
109 enum LLVMPerfJitRecordType {
110 JIT_CODE_LOAD = 0,
111 JIT_CODE_MOVE = 1, // not emitted, code isn't moved
112 JIT_CODE_DEBUG_INFO = 2,
113 JIT_CODE_CLOSE = 3, // not emitted, unnecessary
114 JIT_CODE_UNWINDING_INFO = 4, // not emitted
115
116 JIT_CODE_MAX
117 };
118
119 struct LLVMPerfJitHeader {
120 uint32_t Magic; // characters "JiTD"
121 uint32_t Version; // header version
122 uint32_t TotalSize; // total size of header
123 uint32_t ElfMach; // elf mach target
124 uint32_t Pad1; // reserved
125 uint32_t Pid;
126 uint64_t Timestamp; // timestamp
127 uint64_t Flags; // flags
128 };
129
130 // record prefix (mandatory in each record)
131 struct LLVMPerfJitRecordPrefix {
132 uint32_t Id; // record type identifier
133 uint32_t TotalSize;
134 uint64_t Timestamp;
135 };
136
137 struct LLVMPerfJitRecordCodeLoad {
138 LLVMPerfJitRecordPrefix Prefix;
139
140 uint32_t Pid;
141 uint32_t Tid;
142 uint64_t Vma;
143 uint64_t CodeAddr;
144 uint64_t CodeSize;
145 uint64_t CodeIndex;
146 };
147
148 struct LLVMPerfJitDebugEntry {
149 uint64_t Addr;
150 int Lineno; // source line number starting at 1
151 int Discrim; // column discriminator, 0 is default
152 // followed by null terminated filename, \xff\0 if same as previous entry
153 };
154
155 struct LLVMPerfJitRecordDebugInfo {
156 LLVMPerfJitRecordPrefix Prefix;
157
158 uint64_t CodeAddr;
159 uint64_t NrEntry;
160 // followed by NrEntry LLVMPerfJitDebugEntry records
161 };
162
163 static inline uint64_t timespec_to_ns(const struct timespec *ts) {
164 const uint64_t NanoSecPerSec = 1000000000;
165 return ((uint64_t)ts->tv_sec * NanoSecPerSec) + ts->tv_nsec;
166 }
167
168 static inline uint64_t perf_get_timestamp(void) {
169 struct timespec ts;
170 int ret;
171
172 ret = clock_gettime(CLOCK_MONOTONIC, &ts);
173 if (ret)
174 return 0;
175
176 return timespec_to_ns(&ts);
177 }
178
179 PerfJITEventListener::PerfJITEventListener() : Pid(::getpid()) {
180 // check if clock-source is supported
181 if (!perf_get_timestamp()) {
182 errs() << "kernel does not support CLOCK_MONOTONIC\n";
183 return;
184 }
185
186 if (!InitDebuggingDir()) {
187 errs() << "could not initialize debugging directory\n";
188 return;
189 }
190
191 std::string Filename;
192 raw_string_ostream FilenameBuf(Filename);
193 FilenameBuf << JitPath << "/jit-" << Pid << ".dump";
194
195 // Need to open ourselves, because we need to hand the FD to OpenMarker() and
196 // raw_fd_ostream doesn't expose the FD.
197 using sys::fs::openFileForWrite;
198 if (auto EC =
199 openFileForReadWrite(FilenameBuf.str(), DumpFd,
200 sys::fs::CD_CreateNew, sys::fs::OF_None)) {
201 errs() << "could not open JIT dump file " << FilenameBuf.str() << ": "
202 << EC.message() << "\n";
203 return;
204 }
205
206 Dumpstream = make_unique(DumpFd, true);
207
208 LLVMPerfJitHeader Header = {0};
209 if (!FillMachine(Header))
210 return;
211
212 // signal this process emits JIT information
213 if (!OpenMarker())
214 return;
215
216 // emit dumpstream header
217 Header.Magic = LLVM_PERF_JIT_MAGIC;
218 Header.Version = LLVM_PERF_JIT_VERSION;
219 Header.TotalSize = sizeof(Header);
220 Header.Pid = Pid;
221 Header.Timestamp = perf_get_timestamp();
222 Dumpstream->write(reinterpret_cast(&Header), sizeof(Header));
223
224 // Everything initialized, can do profiling now.
225 if (!Dumpstream->has_error())
226 SuccessfullyInitialized = true;
227 }
228
229 void PerfJITEventListener::NotifyObjectEmitted(
230 const ObjectFile &Obj, const RuntimeDyld::LoadedObjectInfo &L) {
231
232 if (!SuccessfullyInitialized)
233 return;
234
235 OwningBinary DebugObjOwner = L.getObjectForDebug(Obj);
236 const ObjectFile &DebugObj = *DebugObjOwner.getBinary();
237
238 // Get the address of the object image for use as a unique identifier
239 std::unique_ptr Context = DWARFContext::create(DebugObj);
240
241 // Use symbol info to iterate over functions in the object.
242 for (const std::pair &P : computeSymbolSizes(DebugObj)) {
243 SymbolRef Sym = P.first;
244 std::string SourceFileName;
245
246 Expected SymTypeOrErr = Sym.getType();
247 if (!SymTypeOrErr) {
248 // There's not much we can with errors here
249 consumeError(SymTypeOrErr.takeError());
250 continue;
251 }
252 SymbolRef::Type SymType = *SymTypeOrErr;
253 if (SymType != SymbolRef::ST_Function)
254 continue;
255
256 Expected Name = Sym.getName();
257 if (!Name) {
258 consumeError(Name.takeError());
259 continue;
260 }
261
262 Expected AddrOrErr = Sym.getAddress();
263 if (!AddrOrErr) {
264 consumeError(AddrOrErr.takeError());
265 continue;
266 }
267 uint64_t Addr = *AddrOrErr;
268 uint64_t Size = P.second;
269
270 // According to spec debugging info has to come before loading the
271 // corresonding code load.
272 DILineInfoTable Lines = Context->getLineInfoForAddressRange(
273 Addr, Size, FileLineInfoKind::AbsoluteFilePath);
274
275 NotifyDebug(Addr, Lines);
276 NotifyCode(Name, Addr, Size);
277 }
278
279 Dumpstream->flush();
280 }
281
282 void PerfJITEventListener::NotifyFreeingObject(const ObjectFile &Obj) {
283 // perf currently doesn't have an interface for unloading. But munmap()ing the
284 // code section does, so that's ok.
285 }
286
287 bool PerfJITEventListener::InitDebuggingDir() {
288 time_t Time;
289 struct tm LocalTime;
290 char TimeBuffer[sizeof("YYYYMMDD")];
291 SmallString<64> Path;
292
293 // search for location to dump data to
294 if (const char *BaseDir = getenv("JITDUMPDIR"))
295 Path.append(BaseDir);
296 else if (!sys::path::home_directory(Path))
297 Path = ".";
298
299 // create debug directory
300 Path += "/.debug/jit/";
301 if (auto EC = sys::fs::create_directories(Path)) {
302 errs() << "could not create jit cache directory " << Path << ": "
303 << EC.message() << "\n";
304 return false;
305 }
306
307 // create unique directory for dump data related to this process
308 time(&Time);
309 localtime_r(&Time, &LocalTime);
310 strftime(TimeBuffer, sizeof(TimeBuffer), "%Y%m%d", &LocalTime);
311 Path += JIT_LANG "-jit-";
312 Path += TimeBuffer;
313
314 SmallString<128> UniqueDebugDir;
315
316 using sys::fs::createUniqueDirectory;
317 if (auto EC = createUniqueDirectory(Path, UniqueDebugDir)) {
318 errs() << "could not create unique jit cache directory " << UniqueDebugDir
319 << ": " << EC.message() << "\n";
320 return false;
321 }
322
323 JitPath = UniqueDebugDir.str();
324
325 return true;
326 }
327
328 bool PerfJITEventListener::OpenMarker() {
329 // We mmap the jitdump to create an MMAP RECORD in perf.data file. The mmap
330 // is captured either live (perf record running when we mmap) or in deferred
331 // mode, via /proc/PID/maps. The MMAP record is used as a marker of a jitdump
332 // file for more meta data info about the jitted code. Perf report/annotate
333 // detect this special filename and process the jitdump file.
334 //
335 // Mapping must be PROT_EXEC to ensure it is captured by perf record
336 // even when not using -d option.
337 MarkerAddr = ::mmap(NULL, sys::Process::getPageSize(), PROT_READ | PROT_EXEC,
338 MAP_PRIVATE, DumpFd, 0);
339
340 if (MarkerAddr == MAP_FAILED) {
341 errs() << "could not mmap JIT marker\n";
342 return false;
343 }
344 return true;
345 }
346
347 void PerfJITEventListener::CloseMarker() {
348 if (!MarkerAddr)
349 return;
350
351 munmap(MarkerAddr, sys::Process::getPageSize());
352 MarkerAddr = nullptr;
353 }
354
355 bool PerfJITEventListener::FillMachine(LLVMPerfJitHeader &hdr) {
356 char id[16];
357 struct {
358 uint16_t e_type;
359 uint16_t e_machine;
360 } info;
361
362 size_t RequiredMemory = sizeof(id) + sizeof(info);
363
364 ErrorOr> MB =
365 MemoryBuffer::getFileSlice("/proc/self/exe",
366 RequiredMemory,
367 0);
368
369 // This'll not guarantee that enough data was actually read from the
370 // underlying file. Instead the trailing part of the buffer would be
371 // zeroed. Given the ELF signature check below that seems ok though,
372 // it's unlikely that the file ends just after that, and the
373 // consequence would just be that perf wouldn't recognize the
374 // signature.
375 if (auto EC = MB.getError()) {
376 errs() << "could not open /proc/self/exe: " << EC.message() << "\n";
377 return false;
378 }
379
380 memcpy(&id, (*MB)->getBufferStart(), sizeof(id));
381 memcpy(&info, (*MB)->getBufferStart() + sizeof(id), sizeof(info));
382
383 // check ELF signature
384 if (id[0] != 0x7f || id[1] != 'E' || id[2] != 'L' || id[3] != 'F') {
385 errs() << "invalid elf signature\n";
386 return false;
387 }
388
389 hdr.ElfMach = info.e_machine;
390
391 return true;
392 }
393
394 void PerfJITEventListener::NotifyCode(Expected &Symbol,
395 uint64_t CodeAddr, uint64_t CodeSize) {
396 assert(SuccessfullyInitialized);
397
398 // 0 length functions can't have samples.
399 if (CodeSize == 0)
400 return;
401
402 LLVMPerfJitRecordCodeLoad rec;
403 rec.Prefix.Id = JIT_CODE_LOAD;
404 rec.Prefix.TotalSize = sizeof(rec) + // debug record itself
405 Symbol->size() + 1 + // symbol name
406 CodeSize; // and code
407 rec.Prefix.Timestamp = perf_get_timestamp();
408
409 rec.CodeSize = CodeSize;
410 rec.Vma = 0;
411 rec.CodeAddr = CodeAddr;
412 rec.Pid = Pid;
413 rec.Tid = get_threadid();
414
415 // avoid interspersing output
416 MutexGuard Guard(Mutex);
417
418 rec.CodeIndex = CodeGeneration++; // under lock!
419
420 Dumpstream->write(reinterpret_cast(&rec), sizeof(rec));
421 Dumpstream->write(Symbol->data(), Symbol->size() + 1);
422 Dumpstream->write(reinterpret_cast(CodeAddr), CodeSize);
423 }
424
425 void PerfJITEventListener::NotifyDebug(uint64_t CodeAddr,
426 DILineInfoTable Lines) {
427 assert(SuccessfullyInitialized);
428
429 // Didn't get useful debug info.
430 if (Lines.empty())
431 return;
432
433 LLVMPerfJitRecordDebugInfo rec;
434 rec.Prefix.Id = JIT_CODE_DEBUG_INFO;
435 rec.Prefix.TotalSize = sizeof(rec); // will be increased further
436 rec.Prefix.Timestamp = perf_get_timestamp();
437 rec.CodeAddr = CodeAddr;
438 rec.NrEntry = Lines.size();
439
440 // compute total size size of record (variable due to filenames)
441 DILineInfoTable::iterator Begin = Lines.begin();
442 DILineInfoTable::iterator End = Lines.end();
443 for (DILineInfoTable::iterator It = Begin; It != End; ++It) {
444 DILineInfo &line = It->second;
445 rec.Prefix.TotalSize += sizeof(LLVMPerfJitDebugEntry);
446 rec.Prefix.TotalSize += line.FileName.size() + 1;
447 }
448
449 // The debug_entry describes the source line information. It is defined as
450 // follows in order:
451 // * uint64_t code_addr: address of function for which the debug information
452 // is generated
453 // * uint32_t line : source file line number (starting at 1)
454 // * uint32_t discrim : column discriminator, 0 is default
455 // * char name[n] : source file name in ASCII, including null termination
456
457 // avoid interspersing output
458 MutexGuard Guard(Mutex);
459
460 Dumpstream->write(reinterpret_cast(&rec), sizeof(rec));
461
462 for (DILineInfoTable::iterator It = Begin; It != End; ++It) {
463 LLVMPerfJitDebugEntry LineInfo;
464 DILineInfo &Line = It->second;
465
466 LineInfo.Addr = It->first;
467 // The function re-created by perf is preceded by a elf
468 // header. Need to adjust for that, otherwise the results are
469 // wrong.
470 LineInfo.Addr += 0x40;
471 LineInfo.Lineno = Line.Line;
472 LineInfo.Discrim = Line.Discriminator;
473
474 Dumpstream->write(reinterpret_cast(&LineInfo),
475 sizeof(LineInfo));
476 Dumpstream->write(Line.FileName.c_str(), Line.FileName.size() + 1);
477 }
478 }
479
480 // There should be only a single event listener per process, otherwise perf gets
481 // confused.
482 llvm::ManagedStatic PerfListener;
483
484 } // end anonymous namespace
485
486 namespace llvm {
487 JITEventListener *JITEventListener::createPerfJITEventListener() {
488 return &*PerfListener;
489 }
490
491 } // namespace llvm
492
493 LLVMJITEventListenerRef LLVMCreatePerfJITEventListener(void)
494 {
495 return wrap(JITEventListener::createPerfJITEventListener());
496 }
3535 )
3636 endif( LLVM_USE_INTEL_JITEVENTS )
3737
38 if( LLVM_USE_PERF )
39 set(LLVM_LINK_COMPONENTS
40 ${LLVM_LINK_COMPONENTS}
41 DebugInfoDWARF
42 PerfJITEvents
43 Object
44 )
45 endif( LLVM_USE_PERF )
46
3847 add_llvm_tool(lli
3948 lli.cpp
4049
521521 JITEventListener::createOProfileJITEventListener());
522522 EE->RegisterJITEventListener(
523523 JITEventListener::createIntelJITEventListener());
524 if (!RemoteMCJIT)
525 EE->RegisterJITEventListener(
526 JITEventListener::createPerfJITEventListener());
524527
525528 if (!NoLazyCompilation && RemoteMCJIT) {
526529 WithColor::warning(errs(), argv[0])