188e3358fSPrem Chintalapudi //===------- JITLoaderPerf.cpp - Register profiler objects ------*- C++ -*-===// 288e3358fSPrem Chintalapudi // 388e3358fSPrem Chintalapudi // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 488e3358fSPrem Chintalapudi // See https://llvm.org/LICENSE.txt for license information. 588e3358fSPrem Chintalapudi // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 688e3358fSPrem Chintalapudi // 788e3358fSPrem Chintalapudi //===----------------------------------------------------------------------===// 888e3358fSPrem Chintalapudi // 988e3358fSPrem Chintalapudi // Register objects for access by profilers via the perf JIT interface. 1088e3358fSPrem Chintalapudi // 1188e3358fSPrem Chintalapudi //===----------------------------------------------------------------------===// 1288e3358fSPrem Chintalapudi 1388e3358fSPrem Chintalapudi #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderPerf.h" 1488e3358fSPrem Chintalapudi 1588e3358fSPrem Chintalapudi #include "llvm/ExecutionEngine/Orc/Shared/PerfSharedStructs.h" 1688e3358fSPrem Chintalapudi 1788e3358fSPrem Chintalapudi #include "llvm/Support/FileSystem.h" 1888e3358fSPrem Chintalapudi #include "llvm/Support/MemoryBuffer.h" 1988e3358fSPrem Chintalapudi #include "llvm/Support/Path.h" 2088e3358fSPrem Chintalapudi #include "llvm/Support/Process.h" 2188e3358fSPrem Chintalapudi #include "llvm/Support/Threading.h" 2288e3358fSPrem Chintalapudi 2388e3358fSPrem Chintalapudi #include <mutex> 2488e3358fSPrem Chintalapudi #include <optional> 2588e3358fSPrem Chintalapudi 2688e3358fSPrem Chintalapudi #ifdef __linux__ 2788e3358fSPrem Chintalapudi 2888e3358fSPrem Chintalapudi #include <sys/mman.h> // mmap() 2988e3358fSPrem Chintalapudi #include <time.h> // clock_gettime(), time(), localtime_r() */ 3088e3358fSPrem Chintalapudi 3188e3358fSPrem Chintalapudi #define DEBUG_TYPE "orc" 3288e3358fSPrem Chintalapudi 3388e3358fSPrem Chintalapudi // language identifier (XXX: should we generate something better from debug 3488e3358fSPrem Chintalapudi // info?) 3588e3358fSPrem Chintalapudi #define JIT_LANG "llvm-IR" 3688e3358fSPrem Chintalapudi #define LLVM_PERF_JIT_MAGIC \ 3788e3358fSPrem Chintalapudi ((uint32_t)'J' << 24 | (uint32_t)'i' << 16 | (uint32_t)'T' << 8 | \ 3888e3358fSPrem Chintalapudi (uint32_t)'D') 3988e3358fSPrem Chintalapudi #define LLVM_PERF_JIT_VERSION 1 4088e3358fSPrem Chintalapudi 4188e3358fSPrem Chintalapudi using namespace llvm; 4288e3358fSPrem Chintalapudi using namespace llvm::orc; 4388e3358fSPrem Chintalapudi 4488e3358fSPrem Chintalapudi struct PerfState { 4588e3358fSPrem Chintalapudi // cache lookups 4688e3358fSPrem Chintalapudi uint32_t Pid; 4788e3358fSPrem Chintalapudi 4888e3358fSPrem Chintalapudi // base directory for output data 4988e3358fSPrem Chintalapudi std::string JitPath; 5088e3358fSPrem Chintalapudi 5188e3358fSPrem Chintalapudi // output data stream, closed via Dumpstream 5288e3358fSPrem Chintalapudi int DumpFd = -1; 5388e3358fSPrem Chintalapudi 5488e3358fSPrem Chintalapudi // output data stream 5588e3358fSPrem Chintalapudi std::unique_ptr<raw_fd_ostream> Dumpstream; 5688e3358fSPrem Chintalapudi 5788e3358fSPrem Chintalapudi // perf mmap marker 5888e3358fSPrem Chintalapudi void *MarkerAddr = NULL; 5988e3358fSPrem Chintalapudi }; 6088e3358fSPrem Chintalapudi 6188e3358fSPrem Chintalapudi // prevent concurrent dumps from messing up the output file 6288e3358fSPrem Chintalapudi static std::mutex Mutex; 6388e3358fSPrem Chintalapudi static std::optional<PerfState> State; 6488e3358fSPrem Chintalapudi 6588e3358fSPrem Chintalapudi struct RecHeader { 6688e3358fSPrem Chintalapudi uint32_t Id; 6788e3358fSPrem Chintalapudi uint32_t TotalSize; 6888e3358fSPrem Chintalapudi uint64_t Timestamp; 6988e3358fSPrem Chintalapudi }; 7088e3358fSPrem Chintalapudi 7188e3358fSPrem Chintalapudi struct DIR { 7288e3358fSPrem Chintalapudi RecHeader Prefix; 7388e3358fSPrem Chintalapudi uint64_t CodeAddr; 7488e3358fSPrem Chintalapudi uint64_t NrEntry; 7588e3358fSPrem Chintalapudi }; 7688e3358fSPrem Chintalapudi 7788e3358fSPrem Chintalapudi struct DIE { 7888e3358fSPrem Chintalapudi uint64_t CodeAddr; 7988e3358fSPrem Chintalapudi uint32_t Line; 8088e3358fSPrem Chintalapudi uint32_t Discrim; 8188e3358fSPrem Chintalapudi }; 8288e3358fSPrem Chintalapudi 8388e3358fSPrem Chintalapudi struct CLR { 8488e3358fSPrem Chintalapudi RecHeader Prefix; 8588e3358fSPrem Chintalapudi uint32_t Pid; 8688e3358fSPrem Chintalapudi uint32_t Tid; 8788e3358fSPrem Chintalapudi uint64_t Vma; 8888e3358fSPrem Chintalapudi uint64_t CodeAddr; 8988e3358fSPrem Chintalapudi uint64_t CodeSize; 9088e3358fSPrem Chintalapudi uint64_t CodeIndex; 9188e3358fSPrem Chintalapudi }; 9288e3358fSPrem Chintalapudi 9388e3358fSPrem Chintalapudi struct UWR { 9488e3358fSPrem Chintalapudi RecHeader Prefix; 9588e3358fSPrem Chintalapudi uint64_t UnwindDataSize; 9688e3358fSPrem Chintalapudi uint64_t EhFrameHeaderSize; 9788e3358fSPrem Chintalapudi uint64_t MappedSize; 9888e3358fSPrem Chintalapudi }; 9988e3358fSPrem Chintalapudi 10088e3358fSPrem Chintalapudi static inline uint64_t timespec_to_ns(const struct timespec *TS) { 10188e3358fSPrem Chintalapudi const uint64_t NanoSecPerSec = 1000000000; 10288e3358fSPrem Chintalapudi return ((uint64_t)TS->tv_sec * NanoSecPerSec) + TS->tv_nsec; 10388e3358fSPrem Chintalapudi } 10488e3358fSPrem Chintalapudi 10588e3358fSPrem Chintalapudi static inline uint64_t perf_get_timestamp() { 10688e3358fSPrem Chintalapudi timespec TS; 10788e3358fSPrem Chintalapudi if (clock_gettime(CLOCK_MONOTONIC, &TS)) 10888e3358fSPrem Chintalapudi return 0; 10988e3358fSPrem Chintalapudi 11088e3358fSPrem Chintalapudi return timespec_to_ns(&TS); 11188e3358fSPrem Chintalapudi } 11288e3358fSPrem Chintalapudi 11388e3358fSPrem Chintalapudi static void writeDebugRecord(const PerfJITDebugInfoRecord &DebugRecord) { 11488e3358fSPrem Chintalapudi assert(State && "PerfState not initialized"); 11588e3358fSPrem Chintalapudi LLVM_DEBUG(dbgs() << "Writing debug record with " 11688e3358fSPrem Chintalapudi << DebugRecord.Entries.size() << " entries\n"); 11754a38c9cSJie Fu [[maybe_unused]] size_t Written = 0; 11888e3358fSPrem Chintalapudi DIR Dir{RecHeader{static_cast<uint32_t>(DebugRecord.Prefix.Id), 11988e3358fSPrem Chintalapudi DebugRecord.Prefix.TotalSize, perf_get_timestamp()}, 12088e3358fSPrem Chintalapudi DebugRecord.CodeAddr, DebugRecord.Entries.size()}; 12188e3358fSPrem Chintalapudi State->Dumpstream->write(reinterpret_cast<const char *>(&Dir), sizeof(Dir)); 12288e3358fSPrem Chintalapudi Written += sizeof(Dir); 12388e3358fSPrem Chintalapudi for (auto &Die : DebugRecord.Entries) { 12488e3358fSPrem Chintalapudi DIE d{Die.Addr, Die.Lineno, Die.Discrim}; 12588e3358fSPrem Chintalapudi State->Dumpstream->write(reinterpret_cast<const char *>(&d), sizeof(d)); 12688e3358fSPrem Chintalapudi State->Dumpstream->write(Die.Name.data(), Die.Name.size() + 1); 12788e3358fSPrem Chintalapudi Written += sizeof(d) + Die.Name.size() + 1; 12888e3358fSPrem Chintalapudi } 12988e3358fSPrem Chintalapudi LLVM_DEBUG(dbgs() << "wrote " << Written << " bytes of debug info\n"); 13088e3358fSPrem Chintalapudi } 13188e3358fSPrem Chintalapudi 13288e3358fSPrem Chintalapudi static void writeCodeRecord(const PerfJITCodeLoadRecord &CodeRecord) { 13388e3358fSPrem Chintalapudi assert(State && "PerfState not initialized"); 13488e3358fSPrem Chintalapudi uint32_t Tid = get_threadid(); 13588e3358fSPrem Chintalapudi LLVM_DEBUG(dbgs() << "Writing code record with code size " 13688e3358fSPrem Chintalapudi << CodeRecord.CodeSize << " and code index " 13788e3358fSPrem Chintalapudi << CodeRecord.CodeIndex << "\n"); 13888e3358fSPrem Chintalapudi CLR Clr{RecHeader{static_cast<uint32_t>(CodeRecord.Prefix.Id), 13988e3358fSPrem Chintalapudi CodeRecord.Prefix.TotalSize, perf_get_timestamp()}, 14088e3358fSPrem Chintalapudi State->Pid, 14188e3358fSPrem Chintalapudi Tid, 14288e3358fSPrem Chintalapudi CodeRecord.Vma, 14388e3358fSPrem Chintalapudi CodeRecord.CodeAddr, 14488e3358fSPrem Chintalapudi CodeRecord.CodeSize, 14588e3358fSPrem Chintalapudi CodeRecord.CodeIndex}; 14688e3358fSPrem Chintalapudi LLVM_DEBUG(dbgs() << "wrote " << sizeof(Clr) << " bytes of CLR, " 14788e3358fSPrem Chintalapudi << CodeRecord.Name.size() + 1 << " bytes of name, " 14888e3358fSPrem Chintalapudi << CodeRecord.CodeSize << " bytes of code\n"); 14988e3358fSPrem Chintalapudi State->Dumpstream->write(reinterpret_cast<const char *>(&Clr), sizeof(Clr)); 15088e3358fSPrem Chintalapudi State->Dumpstream->write(CodeRecord.Name.data(), CodeRecord.Name.size() + 1); 15188e3358fSPrem Chintalapudi State->Dumpstream->write((const char *)CodeRecord.CodeAddr, 15288e3358fSPrem Chintalapudi CodeRecord.CodeSize); 15388e3358fSPrem Chintalapudi } 15488e3358fSPrem Chintalapudi 15588e3358fSPrem Chintalapudi static void 15688e3358fSPrem Chintalapudi writeUnwindRecord(const PerfJITCodeUnwindingInfoRecord &UnwindRecord) { 15788e3358fSPrem Chintalapudi assert(State && "PerfState not initialized"); 15888e3358fSPrem Chintalapudi dbgs() << "Writing unwind record with unwind data size " 15988e3358fSPrem Chintalapudi << UnwindRecord.UnwindDataSize << " and EH frame header size " 16088e3358fSPrem Chintalapudi << UnwindRecord.EHFrameHdrSize << " and mapped size " 16188e3358fSPrem Chintalapudi << UnwindRecord.MappedSize << "\n"; 16288e3358fSPrem Chintalapudi UWR Uwr{RecHeader{static_cast<uint32_t>(UnwindRecord.Prefix.Id), 16388e3358fSPrem Chintalapudi UnwindRecord.Prefix.TotalSize, perf_get_timestamp()}, 16488e3358fSPrem Chintalapudi UnwindRecord.UnwindDataSize, UnwindRecord.EHFrameHdrSize, 16588e3358fSPrem Chintalapudi UnwindRecord.MappedSize}; 16688e3358fSPrem Chintalapudi LLVM_DEBUG(dbgs() << "wrote " << sizeof(Uwr) << " bytes of UWR, " 16788e3358fSPrem Chintalapudi << UnwindRecord.EHFrameHdrSize 16888e3358fSPrem Chintalapudi << " bytes of EH frame header, " 16988e3358fSPrem Chintalapudi << UnwindRecord.UnwindDataSize - UnwindRecord.EHFrameHdrSize 17088e3358fSPrem Chintalapudi << " bytes of EH frame\n"); 17188e3358fSPrem Chintalapudi State->Dumpstream->write(reinterpret_cast<const char *>(&Uwr), sizeof(Uwr)); 17288e3358fSPrem Chintalapudi if (UnwindRecord.EHFrameHdrAddr) 17388e3358fSPrem Chintalapudi State->Dumpstream->write((const char *)UnwindRecord.EHFrameHdrAddr, 17488e3358fSPrem Chintalapudi UnwindRecord.EHFrameHdrSize); 17588e3358fSPrem Chintalapudi else 17688e3358fSPrem Chintalapudi State->Dumpstream->write(UnwindRecord.EHFrameHdr.data(), 17788e3358fSPrem Chintalapudi UnwindRecord.EHFrameHdrSize); 17888e3358fSPrem Chintalapudi State->Dumpstream->write((const char *)UnwindRecord.EHFrameAddr, 17988e3358fSPrem Chintalapudi UnwindRecord.UnwindDataSize - 18088e3358fSPrem Chintalapudi UnwindRecord.EHFrameHdrSize); 18188e3358fSPrem Chintalapudi } 18288e3358fSPrem Chintalapudi 18388e3358fSPrem Chintalapudi static Error registerJITLoaderPerfImpl(const PerfJITRecordBatch &Batch) { 18488e3358fSPrem Chintalapudi if (!State) 18588e3358fSPrem Chintalapudi return make_error<StringError>("PerfState not initialized", 18688e3358fSPrem Chintalapudi inconvertibleErrorCode()); 18788e3358fSPrem Chintalapudi 18888e3358fSPrem Chintalapudi // Serialize the batch 18988e3358fSPrem Chintalapudi std::lock_guard<std::mutex> Lock(Mutex); 19088e3358fSPrem Chintalapudi if (Batch.UnwindingRecord.Prefix.TotalSize > 0) 19188e3358fSPrem Chintalapudi writeUnwindRecord(Batch.UnwindingRecord); 19288e3358fSPrem Chintalapudi 19388e3358fSPrem Chintalapudi for (const auto &DebugInfo : Batch.DebugInfoRecords) 19488e3358fSPrem Chintalapudi writeDebugRecord(DebugInfo); 19588e3358fSPrem Chintalapudi 19688e3358fSPrem Chintalapudi for (const auto &CodeLoad : Batch.CodeLoadRecords) 19788e3358fSPrem Chintalapudi writeCodeRecord(CodeLoad); 19888e3358fSPrem Chintalapudi 19988e3358fSPrem Chintalapudi State->Dumpstream->flush(); 20088e3358fSPrem Chintalapudi 20188e3358fSPrem Chintalapudi return Error::success(); 20288e3358fSPrem Chintalapudi } 20388e3358fSPrem Chintalapudi 20488e3358fSPrem Chintalapudi struct Header { 20588e3358fSPrem Chintalapudi uint32_t Magic; // characters "JiTD" 20688e3358fSPrem Chintalapudi uint32_t Version; // header version 20788e3358fSPrem Chintalapudi uint32_t TotalSize; // total size of header 20888e3358fSPrem Chintalapudi uint32_t ElfMach; // elf mach target 20988e3358fSPrem Chintalapudi uint32_t Pad1; // reserved 21088e3358fSPrem Chintalapudi uint32_t Pid; 21188e3358fSPrem Chintalapudi uint64_t Timestamp; // timestamp 21288e3358fSPrem Chintalapudi uint64_t Flags; // flags 21388e3358fSPrem Chintalapudi }; 21488e3358fSPrem Chintalapudi 21588e3358fSPrem Chintalapudi static Error OpenMarker(PerfState &State) { 21688e3358fSPrem Chintalapudi // We mmap the jitdump to create an MMAP RECORD in perf.data file. The mmap 21788e3358fSPrem Chintalapudi // is captured either live (perf record running when we mmap) or in deferred 21888e3358fSPrem Chintalapudi // mode, via /proc/PID/maps. The MMAP record is used as a marker of a jitdump 21988e3358fSPrem Chintalapudi // file for more meta data info about the jitted code. Perf report/annotate 22088e3358fSPrem Chintalapudi // detect this special filename and process the jitdump file. 22188e3358fSPrem Chintalapudi // 22288e3358fSPrem Chintalapudi // Mapping must be PROT_EXEC to ensure it is captured by perf record 22388e3358fSPrem Chintalapudi // even when not using -d option. 22488e3358fSPrem Chintalapudi State.MarkerAddr = 22588e3358fSPrem Chintalapudi ::mmap(NULL, sys::Process::getPageSizeEstimate(), PROT_READ | PROT_EXEC, 22688e3358fSPrem Chintalapudi MAP_PRIVATE, State.DumpFd, 0); 22788e3358fSPrem Chintalapudi 22888e3358fSPrem Chintalapudi if (State.MarkerAddr == MAP_FAILED) 22988e3358fSPrem Chintalapudi return make_error<llvm::StringError>("could not mmap JIT marker", 23088e3358fSPrem Chintalapudi inconvertibleErrorCode()); 23188e3358fSPrem Chintalapudi 23288e3358fSPrem Chintalapudi return Error::success(); 23388e3358fSPrem Chintalapudi } 23488e3358fSPrem Chintalapudi 23588e3358fSPrem Chintalapudi void CloseMarker(PerfState &State) { 23688e3358fSPrem Chintalapudi if (!State.MarkerAddr) 23788e3358fSPrem Chintalapudi return; 23888e3358fSPrem Chintalapudi 23988e3358fSPrem Chintalapudi munmap(State.MarkerAddr, sys::Process::getPageSizeEstimate()); 24088e3358fSPrem Chintalapudi State.MarkerAddr = nullptr; 24188e3358fSPrem Chintalapudi } 24288e3358fSPrem Chintalapudi 24388e3358fSPrem Chintalapudi static Expected<Header> FillMachine(PerfState &State) { 24488e3358fSPrem Chintalapudi Header Hdr; 24588e3358fSPrem Chintalapudi Hdr.Magic = LLVM_PERF_JIT_MAGIC; 24688e3358fSPrem Chintalapudi Hdr.Version = LLVM_PERF_JIT_VERSION; 24788e3358fSPrem Chintalapudi Hdr.TotalSize = sizeof(Hdr); 24888e3358fSPrem Chintalapudi Hdr.Pid = State.Pid; 24988e3358fSPrem Chintalapudi Hdr.Timestamp = perf_get_timestamp(); 25088e3358fSPrem Chintalapudi 25188e3358fSPrem Chintalapudi char Id[16]; 25288e3358fSPrem Chintalapudi struct { 25388e3358fSPrem Chintalapudi uint16_t e_type; 25488e3358fSPrem Chintalapudi uint16_t e_machine; 25588e3358fSPrem Chintalapudi } Info; 25688e3358fSPrem Chintalapudi 25788e3358fSPrem Chintalapudi size_t RequiredMemory = sizeof(Id) + sizeof(Info); 25888e3358fSPrem Chintalapudi 25988e3358fSPrem Chintalapudi ErrorOr<std::unique_ptr<MemoryBuffer>> MB = 26088e3358fSPrem Chintalapudi MemoryBuffer::getFileSlice("/proc/self/exe", RequiredMemory, 0); 26188e3358fSPrem Chintalapudi 26288e3358fSPrem Chintalapudi // This'll not guarantee that enough data was actually read from the 26388e3358fSPrem Chintalapudi // underlying file. Instead the trailing part of the buffer would be 26488e3358fSPrem Chintalapudi // zeroed. Given the ELF signature check below that seems ok though, 26588e3358fSPrem Chintalapudi // it's unlikely that the file ends just after that, and the 26688e3358fSPrem Chintalapudi // consequence would just be that perf wouldn't recognize the 26788e3358fSPrem Chintalapudi // signature. 26888e3358fSPrem Chintalapudi if (!MB) 26988e3358fSPrem Chintalapudi return make_error<llvm::StringError>("could not open /proc/self/exe", 27088e3358fSPrem Chintalapudi MB.getError()); 27188e3358fSPrem Chintalapudi 27288e3358fSPrem Chintalapudi memcpy(&Id, (*MB)->getBufferStart(), sizeof(Id)); 27388e3358fSPrem Chintalapudi memcpy(&Info, (*MB)->getBufferStart() + sizeof(Id), sizeof(Info)); 27488e3358fSPrem Chintalapudi 27588e3358fSPrem Chintalapudi // check ELF signature 27688e3358fSPrem Chintalapudi if (Id[0] != 0x7f || Id[1] != 'E' || Id[2] != 'L' || Id[3] != 'F') 27788e3358fSPrem Chintalapudi return make_error<llvm::StringError>("invalid ELF signature", 27888e3358fSPrem Chintalapudi inconvertibleErrorCode()); 27988e3358fSPrem Chintalapudi 28088e3358fSPrem Chintalapudi Hdr.ElfMach = Info.e_machine; 28188e3358fSPrem Chintalapudi 28288e3358fSPrem Chintalapudi return Hdr; 28388e3358fSPrem Chintalapudi } 28488e3358fSPrem Chintalapudi 28588e3358fSPrem Chintalapudi static Error InitDebuggingDir(PerfState &State) { 28688e3358fSPrem Chintalapudi time_t Time; 28788e3358fSPrem Chintalapudi struct tm LocalTime; 28888e3358fSPrem Chintalapudi char TimeBuffer[sizeof("YYYYMMDD")]; 28988e3358fSPrem Chintalapudi SmallString<64> Path; 29088e3358fSPrem Chintalapudi 29188e3358fSPrem Chintalapudi // search for location to dump data to 29288e3358fSPrem Chintalapudi if (const char *BaseDir = getenv("JITDUMPDIR")) 29388e3358fSPrem Chintalapudi Path.append(BaseDir); 29488e3358fSPrem Chintalapudi else if (!sys::path::home_directory(Path)) 29588e3358fSPrem Chintalapudi Path = "."; 29688e3358fSPrem Chintalapudi 29788e3358fSPrem Chintalapudi // create debug directory 29888e3358fSPrem Chintalapudi Path += "/.debug/jit/"; 29988e3358fSPrem Chintalapudi if (auto EC = sys::fs::create_directories(Path)) { 30088e3358fSPrem Chintalapudi std::string ErrStr; 30188e3358fSPrem Chintalapudi raw_string_ostream ErrStream(ErrStr); 30288e3358fSPrem Chintalapudi ErrStream << "could not create jit cache directory " << Path << ": " 30388e3358fSPrem Chintalapudi << EC.message() << "\n"; 30488e3358fSPrem Chintalapudi return make_error<StringError>(std::move(ErrStr), inconvertibleErrorCode()); 30588e3358fSPrem Chintalapudi } 30688e3358fSPrem Chintalapudi 30788e3358fSPrem Chintalapudi // create unique directory for dump data related to this process 30888e3358fSPrem Chintalapudi time(&Time); 30988e3358fSPrem Chintalapudi localtime_r(&Time, &LocalTime); 31088e3358fSPrem Chintalapudi strftime(TimeBuffer, sizeof(TimeBuffer), "%Y%m%d", &LocalTime); 31188e3358fSPrem Chintalapudi Path += JIT_LANG "-jit-"; 31288e3358fSPrem Chintalapudi Path += TimeBuffer; 31388e3358fSPrem Chintalapudi 31488e3358fSPrem Chintalapudi SmallString<128> UniqueDebugDir; 31588e3358fSPrem Chintalapudi 31688e3358fSPrem Chintalapudi using sys::fs::createUniqueDirectory; 31788e3358fSPrem Chintalapudi if (auto EC = createUniqueDirectory(Path, UniqueDebugDir)) { 31888e3358fSPrem Chintalapudi std::string ErrStr; 31988e3358fSPrem Chintalapudi raw_string_ostream ErrStream(ErrStr); 32088e3358fSPrem Chintalapudi ErrStream << "could not create unique jit cache directory " 32188e3358fSPrem Chintalapudi << UniqueDebugDir << ": " << EC.message() << "\n"; 32288e3358fSPrem Chintalapudi return make_error<StringError>(std::move(ErrStr), inconvertibleErrorCode()); 32388e3358fSPrem Chintalapudi } 32488e3358fSPrem Chintalapudi 325b7a66d0fSKazu Hirata State.JitPath = std::string(UniqueDebugDir); 32688e3358fSPrem Chintalapudi 32788e3358fSPrem Chintalapudi return Error::success(); 32888e3358fSPrem Chintalapudi } 32988e3358fSPrem Chintalapudi 33088e3358fSPrem Chintalapudi static Error registerJITLoaderPerfStartImpl() { 33188e3358fSPrem Chintalapudi PerfState Tentative; 33288e3358fSPrem Chintalapudi Tentative.Pid = sys::Process::getProcessId(); 33388e3358fSPrem Chintalapudi // check if clock-source is supported 33488e3358fSPrem Chintalapudi if (!perf_get_timestamp()) 33588e3358fSPrem Chintalapudi return make_error<StringError>("kernel does not support CLOCK_MONOTONIC", 33688e3358fSPrem Chintalapudi inconvertibleErrorCode()); 33788e3358fSPrem Chintalapudi 33888e3358fSPrem Chintalapudi if (auto Err = InitDebuggingDir(Tentative)) 33988e3358fSPrem Chintalapudi return Err; 34088e3358fSPrem Chintalapudi 34188e3358fSPrem Chintalapudi std::string Filename; 34288e3358fSPrem Chintalapudi raw_string_ostream FilenameBuf(Filename); 34388e3358fSPrem Chintalapudi FilenameBuf << Tentative.JitPath << "/jit-" << Tentative.Pid << ".dump"; 34488e3358fSPrem Chintalapudi 34588e3358fSPrem Chintalapudi // Need to open ourselves, because we need to hand the FD to OpenMarker() and 34688e3358fSPrem Chintalapudi // raw_fd_ostream doesn't expose the FD. 34788e3358fSPrem Chintalapudi using sys::fs::openFileForWrite; 348*a75565a6SJOE1994 if (auto EC = openFileForReadWrite(Filename, Tentative.DumpFd, 34988e3358fSPrem Chintalapudi sys::fs::CD_CreateNew, sys::fs::OF_None)) { 35088e3358fSPrem Chintalapudi std::string ErrStr; 35188e3358fSPrem Chintalapudi raw_string_ostream ErrStream(ErrStr); 352*a75565a6SJOE1994 ErrStream << "could not open JIT dump file " << Filename << ": " 35388e3358fSPrem Chintalapudi << EC.message() << "\n"; 35488e3358fSPrem Chintalapudi return make_error<StringError>(std::move(ErrStr), inconvertibleErrorCode()); 35588e3358fSPrem Chintalapudi } 35688e3358fSPrem Chintalapudi 35788e3358fSPrem Chintalapudi Tentative.Dumpstream = 35888e3358fSPrem Chintalapudi std::make_unique<raw_fd_ostream>(Tentative.DumpFd, true); 35988e3358fSPrem Chintalapudi 36088e3358fSPrem Chintalapudi auto Header = FillMachine(Tentative); 36188e3358fSPrem Chintalapudi if (!Header) 36288e3358fSPrem Chintalapudi return Header.takeError(); 36388e3358fSPrem Chintalapudi 36488e3358fSPrem Chintalapudi // signal this process emits JIT information 36588e3358fSPrem Chintalapudi if (auto Err = OpenMarker(Tentative)) 36688e3358fSPrem Chintalapudi return Err; 36788e3358fSPrem Chintalapudi 36888e3358fSPrem Chintalapudi Tentative.Dumpstream->write(reinterpret_cast<const char *>(&Header.get()), 36988e3358fSPrem Chintalapudi sizeof(*Header)); 37088e3358fSPrem Chintalapudi 37188e3358fSPrem Chintalapudi // Everything initialized, can do profiling now. 37288e3358fSPrem Chintalapudi if (Tentative.Dumpstream->has_error()) 37388e3358fSPrem Chintalapudi return make_error<StringError>("could not write JIT dump header", 37488e3358fSPrem Chintalapudi inconvertibleErrorCode()); 37588e3358fSPrem Chintalapudi 37688e3358fSPrem Chintalapudi State = std::move(Tentative); 37788e3358fSPrem Chintalapudi return Error::success(); 37888e3358fSPrem Chintalapudi } 37988e3358fSPrem Chintalapudi 38088e3358fSPrem Chintalapudi static Error registerJITLoaderPerfEndImpl() { 38188e3358fSPrem Chintalapudi if (!State) 38288e3358fSPrem Chintalapudi return make_error<StringError>("PerfState not initialized", 38388e3358fSPrem Chintalapudi inconvertibleErrorCode()); 38488e3358fSPrem Chintalapudi 38588e3358fSPrem Chintalapudi RecHeader Close; 38688e3358fSPrem Chintalapudi Close.Id = static_cast<uint32_t>(PerfJITRecordType::JIT_CODE_CLOSE); 38788e3358fSPrem Chintalapudi Close.TotalSize = sizeof(Close); 38888e3358fSPrem Chintalapudi Close.Timestamp = perf_get_timestamp(); 38988e3358fSPrem Chintalapudi State->Dumpstream->write(reinterpret_cast<const char *>(&Close), 39088e3358fSPrem Chintalapudi sizeof(Close)); 39188e3358fSPrem Chintalapudi if (State->MarkerAddr) 39288e3358fSPrem Chintalapudi CloseMarker(*State); 39388e3358fSPrem Chintalapudi 39488e3358fSPrem Chintalapudi State.reset(); 39588e3358fSPrem Chintalapudi return Error::success(); 39688e3358fSPrem Chintalapudi } 39788e3358fSPrem Chintalapudi 39888e3358fSPrem Chintalapudi extern "C" llvm::orc::shared::CWrapperFunctionResult 39988e3358fSPrem Chintalapudi llvm_orc_registerJITLoaderPerfImpl(const char *Data, uint64_t Size) { 40088e3358fSPrem Chintalapudi using namespace orc::shared; 40188e3358fSPrem Chintalapudi return WrapperFunction<SPSError(SPSPerfJITRecordBatch)>::handle( 40288e3358fSPrem Chintalapudi Data, Size, registerJITLoaderPerfImpl) 40388e3358fSPrem Chintalapudi .release(); 40488e3358fSPrem Chintalapudi } 40588e3358fSPrem Chintalapudi 40688e3358fSPrem Chintalapudi extern "C" llvm::orc::shared::CWrapperFunctionResult 40788e3358fSPrem Chintalapudi llvm_orc_registerJITLoaderPerfStart(const char *Data, uint64_t Size) { 40888e3358fSPrem Chintalapudi using namespace orc::shared; 40988e3358fSPrem Chintalapudi return WrapperFunction<SPSError()>::handle(Data, Size, 41088e3358fSPrem Chintalapudi registerJITLoaderPerfStartImpl) 41188e3358fSPrem Chintalapudi .release(); 41288e3358fSPrem Chintalapudi } 41388e3358fSPrem Chintalapudi 41488e3358fSPrem Chintalapudi extern "C" llvm::orc::shared::CWrapperFunctionResult 41588e3358fSPrem Chintalapudi llvm_orc_registerJITLoaderPerfEnd(const char *Data, uint64_t Size) { 41688e3358fSPrem Chintalapudi using namespace orc::shared; 41788e3358fSPrem Chintalapudi return WrapperFunction<SPSError()>::handle(Data, Size, 41888e3358fSPrem Chintalapudi registerJITLoaderPerfEndImpl) 41988e3358fSPrem Chintalapudi .release(); 42088e3358fSPrem Chintalapudi } 42188e3358fSPrem Chintalapudi 42288e3358fSPrem Chintalapudi #else 42388e3358fSPrem Chintalapudi 42488e3358fSPrem Chintalapudi using namespace llvm; 42588e3358fSPrem Chintalapudi using namespace llvm::orc; 42688e3358fSPrem Chintalapudi 42788e3358fSPrem Chintalapudi static Error badOS() { 42888e3358fSPrem Chintalapudi using namespace llvm; 42988e3358fSPrem Chintalapudi return llvm::make_error<StringError>( 43088e3358fSPrem Chintalapudi "unsupported OS (perf support is only available on linux!)", 43188e3358fSPrem Chintalapudi inconvertibleErrorCode()); 43288e3358fSPrem Chintalapudi } 43388e3358fSPrem Chintalapudi 43488e3358fSPrem Chintalapudi static Error badOSBatch(PerfJITRecordBatch &Batch) { return badOS(); } 43588e3358fSPrem Chintalapudi 43688e3358fSPrem Chintalapudi extern "C" llvm::orc::shared::CWrapperFunctionResult 43788e3358fSPrem Chintalapudi llvm_orc_registerJITLoaderPerfImpl(const char *Data, uint64_t Size) { 43888e3358fSPrem Chintalapudi using namespace shared; 43988e3358fSPrem Chintalapudi return WrapperFunction<SPSError(SPSPerfJITRecordBatch)>::handle(Data, Size, 44088e3358fSPrem Chintalapudi badOSBatch) 44188e3358fSPrem Chintalapudi .release(); 44288e3358fSPrem Chintalapudi } 44388e3358fSPrem Chintalapudi 44488e3358fSPrem Chintalapudi extern "C" llvm::orc::shared::CWrapperFunctionResult 44588e3358fSPrem Chintalapudi llvm_orc_registerJITLoaderPerfStart(const char *Data, uint64_t Size) { 44688e3358fSPrem Chintalapudi using namespace shared; 44788e3358fSPrem Chintalapudi return WrapperFunction<SPSError()>::handle(Data, Size, badOS).release(); 44888e3358fSPrem Chintalapudi } 44988e3358fSPrem Chintalapudi 45088e3358fSPrem Chintalapudi extern "C" llvm::orc::shared::CWrapperFunctionResult 45188e3358fSPrem Chintalapudi llvm_orc_registerJITLoaderPerfEnd(const char *Data, uint64_t Size) { 45288e3358fSPrem Chintalapudi using namespace shared; 45388e3358fSPrem Chintalapudi return WrapperFunction<SPSError()>::handle(Data, Size, badOS).release(); 45488e3358fSPrem Chintalapudi } 45588e3358fSPrem Chintalapudi 45688e3358fSPrem Chintalapudi #endif 457