19#include "llvm/Config/config.h"
47#define JIT_LANG "llvm-IR"
48#define LLVM_PERF_JIT_MAGIC \
49 ((uint32_t)'J' << 24 | (uint32_t)'i' << 16 | (uint32_t)'T' << 8 | \
51#define LLVM_PERF_JIT_VERSION 1
55#define JITDUMP_FLAGS_ARCH_TIMESTAMP (1ULL << 0)
57struct LLVMPerfJitHeader;
61 PerfJITEventListener();
62 ~PerfJITEventListener() {
66 std::lock_guard<sys::Mutex> Guard(
Mutex);
76 bool InitDebuggingDir();
79 static bool FillMachine(LLVMPerfJitHeader &hdr);
95 std::unique_ptr<raw_fd_ostream> Dumpstream;
101 void *MarkerAddr = NULL;
104 bool SuccessfullyInitialized =
false;
112enum LLVMPerfJitRecordType {
122struct LLVMPerfJitHeader {
134struct LLVMPerfJitRecordPrefix {
140struct LLVMPerfJitRecordCodeLoad {
141 LLVMPerfJitRecordPrefix
Prefix;
151struct LLVMPerfJitDebugEntry {
158struct LLVMPerfJitRecordDebugInfo {
159 LLVMPerfJitRecordPrefix
Prefix;
166static inline uint64_t timespec_to_ns(
const struct timespec *ts) {
167 const uint64_t NanoSecPerSec = 1000000000;
168 return ((
uint64_t)ts->tv_sec * NanoSecPerSec) + ts->tv_nsec;
171static inline uint64_t perf_get_timestamp(
void) {
175 ret = clock_gettime(CLOCK_MONOTONIC, &ts);
179 return timespec_to_ns(&ts);
182PerfJITEventListener::PerfJITEventListener()
183 : Pid(sys::
Process::getProcessId()) {
185 if (!perf_get_timestamp()) {
186 errs() <<
"kernel does not support CLOCK_MONOTONIC\n";
190 if (!InitDebuggingDir()) {
191 errs() <<
"could not initialize debugging directory\n";
197 FilenameBuf << JitPath <<
"/jit-" << Pid <<
".dump";
204 errs() <<
"could not open JIT dump file " <<
Filename <<
": "
205 <<
EC.message() <<
"\n";
209 Dumpstream = std::make_unique<raw_fd_ostream>(DumpFd,
true);
211 LLVMPerfJitHeader Header = {0, 0, 0, 0, 0, 0, 0, 0};
212 if (!FillMachine(Header))
222 Header.TotalSize =
sizeof(Header);
224 Header.Timestamp = perf_get_timestamp();
225 Dumpstream->write(
reinterpret_cast<const char *
>(&Header),
sizeof(Header));
228 if (!Dumpstream->has_error())
229 SuccessfullyInitialized =
true;
232void PerfJITEventListener::notifyObjectLoaded(
236 if (!SuccessfullyInitialized)
248 std::string SourceFileName;
276 if (
auto SectOrErr =
Sym.getSection())
278 SectionIndex = SectOrErr.get()->getIndex();
283 {*AddrOrErr, SectionIndex},
Size, FileLineInfoKind::AbsoluteFilePath);
285 NotifyDebug(*AddrOrErr, Lines);
290 std::lock_guard<sys::Mutex> Guard(
Mutex);
295void PerfJITEventListener::notifyFreeingObject(ObjectKey K) {
300bool PerfJITEventListener::InitDebuggingDir() {
303 char TimeBuffer[
sizeof(
"YYYYMMDD")];
307 if (
const char *BaseDir = getenv(
"JITDUMPDIR"))
308 Path.append(BaseDir);
313 Path +=
"/.debug/jit/";
315 errs() <<
"could not create jit cache directory " <<
Path <<
": "
316 <<
EC.message() <<
"\n";
322 localtime_r(&Time, &LocalTime);
323 strftime(TimeBuffer,
sizeof(TimeBuffer),
"%Y%m%d", &LocalTime);
331 errs() <<
"could not create unique jit cache directory " << UniqueDebugDir
332 <<
": " <<
EC.message() <<
"\n";
336 JitPath = std::string(UniqueDebugDir.
str());
341bool PerfJITEventListener::OpenMarker() {
351 PROT_READ | PROT_EXEC, MAP_PRIVATE, DumpFd, 0);
353 if (MarkerAddr == MAP_FAILED) {
354 errs() <<
"could not mmap JIT marker\n";
360void PerfJITEventListener::CloseMarker() {
365 MarkerAddr =
nullptr;
368bool PerfJITEventListener::FillMachine(LLVMPerfJitHeader &hdr) {
375 size_t RequiredMemory =
sizeof(
id) +
sizeof(
info);
389 errs() <<
"could not open /proc/self/exe: " <<
EC.message() <<
"\n";
393 memcpy(&
id, (*MB)->getBufferStart(),
sizeof(
id));
394 memcpy(&
info, (*MB)->getBufferStart() +
sizeof(
id),
sizeof(
info));
397 if (
id[0] != 0x7f ||
id[1] !=
'E' ||
id[2] !=
'L' ||
id[3] !=
'F') {
398 errs() <<
"invalid elf signature\n";
402 hdr.ElfMach =
info.e_machine;
409 assert(SuccessfullyInitialized);
415 LLVMPerfJitRecordCodeLoad rec;
417 rec.Prefix.TotalSize =
sizeof(rec) +
420 rec.Prefix.Timestamp = perf_get_timestamp();
422 rec.CodeSize = CodeSize;
424 rec.CodeAddr = CodeAddr;
429 std::lock_guard<sys::Mutex> Guard(
Mutex);
431 rec.CodeIndex = CodeGeneration++;
433 Dumpstream->write(
reinterpret_cast<const char *
>(&rec),
sizeof(rec));
435 Dumpstream->write(
reinterpret_cast<const char *
>(CodeAddr), CodeSize);
438void PerfJITEventListener::NotifyDebug(
uint64_t CodeAddr,
440 assert(SuccessfullyInitialized);
446 LLVMPerfJitRecordDebugInfo rec;
448 rec.Prefix.TotalSize =
sizeof(rec);
449 rec.Prefix.Timestamp = perf_get_timestamp();
450 rec.CodeAddr = CodeAddr;
451 rec.NrEntry =
Lines.size();
458 rec.Prefix.TotalSize +=
sizeof(LLVMPerfJitDebugEntry);
459 rec.Prefix.TotalSize += line.
FileName.size() + 1;
471 std::lock_guard<sys::Mutex> Guard(
Mutex);
473 Dumpstream->write(
reinterpret_cast<const char *
>(&rec),
sizeof(rec));
476 LLVMPerfJitDebugEntry LineInfo;
479 LineInfo.Addr = It->first;
483 LineInfo.Addr += 0x40;
484 LineInfo.Lineno =
Line.Line;
485 LineInfo.Discrim =
Line.Discriminator;
487 Dumpstream->write(
reinterpret_cast<const char *
>(&LineInfo),
489 Dumpstream->write(
Line.FileName.c_str(),
Line.FileName.size() + 1);
499 static PerfJITEventListener PerfListener;
500 return &PerfListener;
#define LLVM_PERF_JIT_MAGIC
DILineInfoSpecifier::FileLineInfoKind FileLineInfoKind
#define LLVM_PERF_JIT_VERSION
Provides a library for accessing information about this process and other processes on the operating ...
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static std::unique_ptr< DWARFContext > create(const object::ObjectFile &Obj, ProcessDebugRelocations RelocAction=ProcessDebugRelocations::Process, const LoadedObjectInfo *L=nullptr, std::string DWPName="", std::function< void(Error)> RecoverableErrorHandler=WithColor::defaultErrorHandler, std::function< void(Error)> WarningHandler=WithColor::defaultWarningHandler, bool ThreadSafe=false)
Represents either an error or a value T.
std::error_code getError() const
Tagged union holding either a T or a Error.
Error takeError()
Take ownership of the stored error.
JITEventListener - Abstract interface for use by the JIT to notify clients about significant events d...
virtual void notifyFreeingObject(ObjectKey K)
notifyFreeingObject - Called just before the memory associated with a previously emitted object is re...
virtual void notifyObjectLoaded(ObjectKey K, const object::ObjectFile &Obj, const RuntimeDyld::LoadedObjectInfo &L)
notifyObjectLoaded - Called after an object has had its sections allocated and addresses assigned to ...
static JITEventListener * createPerfJITEventListener()
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFileSlice(const Twine &Filename, uint64_t MapSize, uint64_t Offset, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Map a subrange of the specified file as a MemoryBuffer.
Information about the loaded object.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
StringRef str() const
Explicit conversion to StringRef.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
This class is the base class for all object file types.
virtual section_iterator section_end() const =0
This is a value type class that represents a single symbol in the list of symbols in the object file.
A raw_ostream that writes to an std::string.
A collection of legacy interfaces for querying information about the current executing process.
static unsigned getPageSizeEstimate()
Get the process's estimated page size.
LLVMJITEventListenerRef LLVMCreatePerfJITEventListener(void)
struct LLVMOpaqueJITEventListener * LLVMJITEventListenerRef
std::vector< std::pair< SymbolRef, uint64_t > > computeSymbolSizes(const ObjectFile &O)
@ JIT_CODE_UNWINDING_INFO
std::error_code openFileForReadWrite(const Twine &Name, int &ResultFD, CreationDisposition Disp, OpenFlags Flags, unsigned Mode=0666)
Opens the file with the given name in a write-only or read-write mode, returning its open file descri...
@ CD_CreateNew
CD_CreateNew - When opening a file:
std::error_code openFileForWrite(const Twine &Name, int &ResultFD, CreationDisposition Disp=CD_CreateAlways, OpenFlags Flags=OF_None, unsigned Mode=0666)
Opens the file with the given name in a write-only or read-write mode, returning its open file descri...
std::error_code create_directories(const Twine &path, bool IgnoreExisting=true, perms Perms=owner_all|group_all)
Create all the non-existent directories in path.
std::error_code createUniqueDirectory(const Twine &Prefix, SmallVectorImpl< char > &ResultPath)
bool home_directory(SmallVectorImpl< char > &result)
Get the user's home directory.
SmartMutex< false > Mutex
Mutex - A standard, always enforced mutex.
This is an optimization pass for GlobalISel generic memory operations.
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
uint64_t get_threadid()
Return the current thread id, as used in various OS system calls.
LLVMAttributeRef wrap(Attribute Attr)
void consumeError(Error Err)
Consume a Error without doing anything.
A format-neutral container for source line information.
static const uint64_t UndefSection