32#define DEBUG_TYPE "orc"
36#define JIT_LANG "llvm-IR"
37#define LLVM_PERF_JIT_MAGIC \
38 ((uint32_t)'J' << 24 | (uint32_t)'i' << 16 | (uint32_t)'T' << 8 | \
40#define LLVM_PERF_JIT_VERSION 1
56 std::unique_ptr<raw_fd_ostream> Dumpstream;
59 void *MarkerAddr = NULL;
63static std::mutex
Mutex;
64static std::optional<PerfState> State;
101static inline uint64_t timespec_to_ns(
const struct timespec *TS) {
102 const uint64_t NanoSecPerSec = 1000000000;
103 return ((
uint64_t)TS->tv_sec * NanoSecPerSec) + TS->tv_nsec;
106static inline uint64_t perf_get_timestamp() {
108 if (clock_gettime(CLOCK_MONOTONIC, &TS))
111 return timespec_to_ns(&TS);
115 assert(State &&
"PerfState not initialized");
117 << DebugRecord.
Entries.size() <<
" entries\n");
118 [[maybe_unused]]
size_t Written = 0;
122 State->Dumpstream->write(
reinterpret_cast<const char *
>(&Dir),
sizeof(Dir));
123 Written +=
sizeof(Dir);
124 for (
auto &Die : DebugRecord.
Entries) {
125 DIE d{Die.Addr, Die.Lineno, Die.Discrim};
126 State->Dumpstream->write(
reinterpret_cast<const char *
>(&d),
sizeof(d));
127 State->Dumpstream->write(Die.Name.data(), Die.Name.size() + 1);
128 Written +=
sizeof(d) + Die.Name.size() + 1;
130 LLVM_DEBUG(
dbgs() <<
"wrote " << Written <<
" bytes of debug info\n");
134 assert(State &&
"PerfState not initialized");
137 << CodeRecord.
CodeSize <<
" and code index "
148 << CodeRecord.
Name.size() + 1 <<
" bytes of name, "
149 << CodeRecord.
CodeSize <<
" bytes of code\n");
150 State->Dumpstream->write(
reinterpret_cast<const char *
>(&Clr),
sizeof(Clr));
151 State->Dumpstream->write(CodeRecord.
Name.data(), CodeRecord.
Name.size() + 1);
152 State->Dumpstream->write((
const char *)CodeRecord.
CodeAddr,
158 assert(State &&
"PerfState not initialized");
159 dbgs() <<
"Writing unwind record with unwind data size "
169 <<
" bytes of EH frame header, "
171 <<
" bytes of EH frame\n");
172 State->Dumpstream->write(
reinterpret_cast<const char *
>(&Uwr),
sizeof(Uwr));
174 State->Dumpstream->write((
const char *)UnwindRecord.
EHFrameHdrAddr,
177 State->Dumpstream->write(UnwindRecord.
EHFrameHdr.data(),
179 State->Dumpstream->write((
const char *)UnwindRecord.
EHFrameAddr,
186 return make_error<StringError>(
"PerfState not initialized",
190 std::lock_guard<std::mutex> Lock(
Mutex);
198 writeCodeRecord(CodeLoad);
200 State->Dumpstream->flush();
216static Error OpenMarker(PerfState &State) {
227 MAP_PRIVATE, State.DumpFd, 0);
229 if (State.MarkerAddr == MAP_FAILED)
230 return make_error<llvm::StringError>(
"could not mmap JIT marker",
236void CloseMarker(PerfState &State) {
237 if (!State.MarkerAddr)
241 State.MarkerAddr =
nullptr;
248 Hdr.TotalSize =
sizeof(Hdr);
250 Hdr.Timestamp = perf_get_timestamp();
258 size_t RequiredMemory =
sizeof(
Id) +
sizeof(Info);
270 return make_error<llvm::StringError>(
"could not open /proc/self/exe",
273 memcpy(&Id, (*MB)->getBufferStart(),
sizeof(Id));
274 memcpy(&Info, (*MB)->getBufferStart() +
sizeof(Id),
sizeof(Info));
277 if (Id[0] != 0x7f || Id[1] !=
'E' || Id[2] !=
'L' || Id[3] !=
'F')
278 return make_error<llvm::StringError>(
"invalid ELF signature",
281 Hdr.ElfMach =
Info.e_machine;
286static Error InitDebuggingDir(PerfState &State) {
289 char TimeBuffer[
sizeof(
"YYYYMMDD")];
293 if (
const char *BaseDir = getenv(
"JITDUMPDIR"))
294 Path.append(BaseDir);
299 Path +=
"/.debug/jit/";
303 ErrStream <<
"could not create jit cache directory " <<
Path <<
": "
304 <<
EC.message() <<
"\n";
310 localtime_r(&Time, &LocalTime);
311 strftime(TimeBuffer,
sizeof(TimeBuffer),
"%Y%m%d", &LocalTime);
321 ErrStream <<
"could not create unique jit cache directory "
322 << UniqueDebugDir <<
": " <<
EC.message() <<
"\n";
326 State.JitPath = std::string(UniqueDebugDir);
331static Error registerJITLoaderPerfStartImpl() {
335 if (!perf_get_timestamp())
336 return make_error<StringError>(
"kernel does not support CLOCK_MONOTONIC",
339 if (
auto Err = InitDebuggingDir(Tentative))
344 FilenameBuf << Tentative.JitPath <<
"/jit-" << Tentative.Pid <<
".dump";
353 ErrStream <<
"could not open JIT dump file " << FilenameBuf.str() <<
": "
354 <<
EC.message() <<
"\n";
358 Tentative.Dumpstream =
359 std::make_unique<raw_fd_ostream>(Tentative.DumpFd,
true);
361 auto Header = FillMachine(Tentative);
363 return Header.takeError();
366 if (
auto Err = OpenMarker(Tentative))
369 Tentative.Dumpstream->write(
reinterpret_cast<const char *
>(&Header.get()),
373 if (Tentative.Dumpstream->has_error())
374 return make_error<StringError>(
"could not write JIT dump header",
377 State = std::move(Tentative);
381static Error registerJITLoaderPerfEndImpl() {
383 return make_error<StringError>(
"PerfState not initialized",
387 Close.Id =
static_cast<uint32_t>(PerfJITRecordType::JIT_CODE_CLOSE);
388 Close.TotalSize =
sizeof(Close);
389 Close.Timestamp = perf_get_timestamp();
390 State->Dumpstream->write(
reinterpret_cast<const char *
>(&Close),
392 if (State->MarkerAddr)
401 using namespace orc::shared;
402 return WrapperFunction<SPSError(SPSPerfJITRecordBatch)>::handle(
403 Data,
Size, registerJITLoaderPerfImpl)
409 using namespace orc::shared;
410 return WrapperFunction<SPSError()>::handle(Data,
Size,
411 registerJITLoaderPerfStartImpl)
417 using namespace orc::shared;
418 return WrapperFunction<SPSError()>::handle(Data,
Size,
419 registerJITLoaderPerfEndImpl)
429 using namespace llvm;
430 return llvm::make_error<StringError>(
431 "unsupported OS (perf support is only available on linux!)",
439 using namespace shared;
440 return WrapperFunction<SPSError(SPSPerfJITRecordBatch)>::handle(Data,
Size,
447 using namespace shared;
448 return WrapperFunction<SPSError()>::handle(Data,
Size,
badOS).release();
453 using namespace shared;
454 return WrapperFunction<SPSError()>::handle(Data,
Size,
badOS).release();
Analysis containing CSE Info
llvm::orc::shared::CWrapperFunctionResult llvm_orc_registerJITLoaderPerfStart(const char *Data, uint64_t Size)
llvm::orc::shared::CWrapperFunctionResult llvm_orc_registerJITLoaderPerfImpl(const char *Data, uint64_t Size)
static Error badOSBatch(PerfJITRecordBatch &Batch)
llvm::orc::shared::CWrapperFunctionResult llvm_orc_registerJITLoaderPerfEnd(const char *Data, uint64_t Size)
#define LLVM_PERF_JIT_MAGIC
#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())
A structured debug information entry.
Represents either an error or a value T.
std::error_code getError() const
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
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.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
A raw_ostream that writes to an std::string.
static unsigned getPageSizeEstimate()
Get the process's estimated page size.
static Pid getProcessId()
Get the process's identifier.
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.
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
uint64_t get_threadid()
Return the current thread id, as used in various OS system calls.
PerfJITRecordPrefix Prefix
PerfJITRecordPrefix Prefix
std::vector< PerfJITDebugEntry > Entries
PerfJITRecordPrefix Prefix
std::vector< PerfJITDebugInfoRecord > DebugInfoRecords
PerfJITCodeUnwindingInfoRecord UnwindingRecord
std::vector< PerfJITCodeLoadRecord > CodeLoadRecords