31#define DEBUG_TYPE "orc"
35#define JIT_LANG "llvm-IR"
36#define LLVM_PERF_JIT_MAGIC \
37 ((uint32_t)'J' << 24 | (uint32_t)'i' << 16 | (uint32_t)'T' << 8 | \
39#define LLVM_PERF_JIT_VERSION 1
55 std::unique_ptr<raw_fd_ostream> Dumpstream;
58 void *MarkerAddr = NULL;
62static std::mutex
Mutex;
63static std::optional<PerfState> State;
100static inline uint64_t timespec_to_ns(
const struct timespec *TS) {
101 const uint64_t NanoSecPerSec = 1000000000;
102 return ((
uint64_t)TS->tv_sec * NanoSecPerSec) + TS->tv_nsec;
105static inline uint64_t perf_get_timestamp() {
107 if (clock_gettime(CLOCK_MONOTONIC, &TS))
110 return timespec_to_ns(&TS);
114 assert(State &&
"PerfState not initialized");
116 << DebugRecord.
Entries.size() <<
" entries\n");
117 [[maybe_unused]]
size_t Written = 0;
121 State->Dumpstream->write(
reinterpret_cast<const char *
>(&Dir),
sizeof(Dir));
122 Written +=
sizeof(Dir);
123 for (
auto &Die : DebugRecord.
Entries) {
124 DIE d{Die.Addr, Die.Lineno, Die.Discrim};
125 State->Dumpstream->write(
reinterpret_cast<const char *
>(&d),
sizeof(d));
126 State->Dumpstream->write(Die.Name.data(), Die.Name.size() + 1);
127 Written +=
sizeof(d) + Die.Name.size() + 1;
129 LLVM_DEBUG(
dbgs() <<
"wrote " << Written <<
" bytes of debug info\n");
133 assert(State &&
"PerfState not initialized");
136 << CodeRecord.
CodeSize <<
" and code index "
147 << CodeRecord.
Name.size() + 1 <<
" bytes of name, "
148 << CodeRecord.
CodeSize <<
" bytes of code\n");
149 State->Dumpstream->write(
reinterpret_cast<const char *
>(&Clr),
sizeof(Clr));
150 State->Dumpstream->write(CodeRecord.
Name.data(), CodeRecord.
Name.size() + 1);
151 State->Dumpstream->write((
const char *)CodeRecord.
CodeAddr,
157 assert(State &&
"PerfState not initialized");
158 dbgs() <<
"Writing unwind record with unwind data size "
168 <<
" bytes of EH frame header, "
170 <<
" bytes of EH frame\n");
171 State->Dumpstream->write(
reinterpret_cast<const char *
>(&Uwr),
sizeof(Uwr));
173 State->Dumpstream->write((
const char *)UnwindRecord.
EHFrameHdrAddr,
176 State->Dumpstream->write(UnwindRecord.
EHFrameHdr.data(),
178 State->Dumpstream->write((
const char *)UnwindRecord.
EHFrameAddr,
185 return make_error<StringError>(
"PerfState not initialized",
189 std::lock_guard<std::mutex> Lock(
Mutex);
197 writeCodeRecord(CodeLoad);
199 State->Dumpstream->flush();
215static Error OpenMarker(PerfState &State) {
226 MAP_PRIVATE, State.DumpFd, 0);
228 if (State.MarkerAddr == MAP_FAILED)
229 return make_error<llvm::StringError>(
"could not mmap JIT marker",
235void CloseMarker(PerfState &State) {
236 if (!State.MarkerAddr)
240 State.MarkerAddr =
nullptr;
247 Hdr.TotalSize =
sizeof(Hdr);
249 Hdr.Timestamp = perf_get_timestamp();
257 size_t RequiredMemory =
sizeof(
Id) +
sizeof(Info);
269 return make_error<llvm::StringError>(
"could not open /proc/self/exe",
272 memcpy(&Id, (*MB)->getBufferStart(),
sizeof(Id));
273 memcpy(&Info, (*MB)->getBufferStart() +
sizeof(Id),
sizeof(Info));
276 if (Id[0] != 0x7f || Id[1] !=
'E' || Id[2] !=
'L' || Id[3] !=
'F')
277 return make_error<llvm::StringError>(
"invalid ELF signature",
280 Hdr.ElfMach =
Info.e_machine;
285static Error InitDebuggingDir(PerfState &State) {
288 char TimeBuffer[
sizeof(
"YYYYMMDD")];
292 if (
const char *BaseDir = getenv(
"JITDUMPDIR"))
293 Path.append(BaseDir);
298 Path +=
"/.debug/jit/";
302 ErrStream <<
"could not create jit cache directory " <<
Path <<
": "
303 <<
EC.message() <<
"\n";
309 localtime_r(&Time, &LocalTime);
310 strftime(TimeBuffer,
sizeof(TimeBuffer),
"%Y%m%d", &LocalTime);
320 ErrStream <<
"could not create unique jit cache directory "
321 << UniqueDebugDir <<
": " <<
EC.message() <<
"\n";
325 State.JitPath = std::string(UniqueDebugDir);
330static Error registerJITLoaderPerfStartImpl() {
334 if (!perf_get_timestamp())
335 return make_error<StringError>(
"kernel does not support CLOCK_MONOTONIC",
338 if (
auto Err = InitDebuggingDir(Tentative))
343 FilenameBuf << Tentative.JitPath <<
"/jit-" << Tentative.Pid <<
".dump";
352 ErrStream <<
"could not open JIT dump file " <<
Filename <<
": "
353 <<
EC.message() <<
"\n";
357 Tentative.Dumpstream =
358 std::make_unique<raw_fd_ostream>(Tentative.DumpFd,
true);
360 auto Header = FillMachine(Tentative);
362 return Header.takeError();
365 if (
auto Err = OpenMarker(Tentative))
368 Tentative.Dumpstream->write(
reinterpret_cast<const char *
>(&Header.get()),
372 if (Tentative.Dumpstream->has_error())
373 return make_error<StringError>(
"could not write JIT dump header",
376 State = std::move(Tentative);
380static Error registerJITLoaderPerfEndImpl() {
382 return make_error<StringError>(
"PerfState not initialized",
386 Close.Id =
static_cast<uint32_t>(PerfJITRecordType::JIT_CODE_CLOSE);
387 Close.TotalSize =
sizeof(Close);
388 Close.Timestamp = perf_get_timestamp();
389 State->Dumpstream->write(
reinterpret_cast<const char *
>(&Close),
391 if (State->MarkerAddr)
400 using namespace orc::shared;
401 return WrapperFunction<SPSError(SPSPerfJITRecordBatch)>::handle(
402 Data,
Size, registerJITLoaderPerfImpl)
408 using namespace orc::shared;
409 return WrapperFunction<SPSError()>::handle(Data,
Size,
410 registerJITLoaderPerfStartImpl)
416 using namespace orc::shared;
417 return WrapperFunction<SPSError()>::handle(Data,
Size,
418 registerJITLoaderPerfEndImpl)
428 using namespace llvm;
429 return llvm::make_error<StringError>(
430 "unsupported OS (perf support is only available on linux!)",
438 using namespace shared;
439 return WrapperFunction<SPSError(SPSPerfJITRecordBatch)>::handle(Data,
Size,
446 using namespace shared;
447 return WrapperFunction<SPSError()>::handle(Data,
Size,
badOS).release();
452 using namespace shared;
453 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