15f757f3fSDimitry Andric //===------- JITLoaderPerf.cpp - Register profiler objects ------*- C++ -*-===// 25f757f3fSDimitry Andric // 35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65f757f3fSDimitry Andric // 75f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 85f757f3fSDimitry Andric // 95f757f3fSDimitry Andric // Register objects for access by profilers via the perf JIT interface. 105f757f3fSDimitry Andric // 115f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 125f757f3fSDimitry Andric 135f757f3fSDimitry Andric #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderPerf.h" 145f757f3fSDimitry Andric 155f757f3fSDimitry Andric #include "llvm/ExecutionEngine/Orc/Shared/PerfSharedStructs.h" 165f757f3fSDimitry Andric 175f757f3fSDimitry Andric #include "llvm/Support/FileSystem.h" 185f757f3fSDimitry Andric #include "llvm/Support/MemoryBuffer.h" 195f757f3fSDimitry Andric #include "llvm/Support/Path.h" 205f757f3fSDimitry Andric #include "llvm/Support/Process.h" 215f757f3fSDimitry Andric #include "llvm/Support/Threading.h" 225f757f3fSDimitry Andric 235f757f3fSDimitry Andric #include <mutex> 245f757f3fSDimitry Andric #include <optional> 255f757f3fSDimitry Andric 265f757f3fSDimitry Andric #ifdef __linux__ 275f757f3fSDimitry Andric 285f757f3fSDimitry Andric #include <sys/mman.h> // mmap() 295f757f3fSDimitry Andric #include <time.h> // clock_gettime(), time(), localtime_r() */ 305f757f3fSDimitry Andric #include <unistd.h> // for read(), close() 315f757f3fSDimitry Andric 325f757f3fSDimitry Andric #define DEBUG_TYPE "orc" 335f757f3fSDimitry Andric 345f757f3fSDimitry Andric // language identifier (XXX: should we generate something better from debug 355f757f3fSDimitry Andric // info?) 365f757f3fSDimitry Andric #define JIT_LANG "llvm-IR" 375f757f3fSDimitry Andric #define LLVM_PERF_JIT_MAGIC \ 385f757f3fSDimitry Andric ((uint32_t)'J' << 24 | (uint32_t)'i' << 16 | (uint32_t)'T' << 8 | \ 395f757f3fSDimitry Andric (uint32_t)'D') 405f757f3fSDimitry Andric #define LLVM_PERF_JIT_VERSION 1 415f757f3fSDimitry Andric 425f757f3fSDimitry Andric using namespace llvm; 435f757f3fSDimitry Andric using namespace llvm::orc; 445f757f3fSDimitry Andric 455f757f3fSDimitry Andric struct PerfState { 465f757f3fSDimitry Andric // cache lookups 475f757f3fSDimitry Andric uint32_t Pid; 485f757f3fSDimitry Andric 495f757f3fSDimitry Andric // base directory for output data 505f757f3fSDimitry Andric std::string JitPath; 515f757f3fSDimitry Andric 525f757f3fSDimitry Andric // output data stream, closed via Dumpstream 535f757f3fSDimitry Andric int DumpFd = -1; 545f757f3fSDimitry Andric 555f757f3fSDimitry Andric // output data stream 565f757f3fSDimitry Andric std::unique_ptr<raw_fd_ostream> Dumpstream; 575f757f3fSDimitry Andric 585f757f3fSDimitry Andric // perf mmap marker 595f757f3fSDimitry Andric void *MarkerAddr = NULL; 605f757f3fSDimitry Andric }; 615f757f3fSDimitry Andric 625f757f3fSDimitry Andric // prevent concurrent dumps from messing up the output file 635f757f3fSDimitry Andric static std::mutex Mutex; 645f757f3fSDimitry Andric static std::optional<PerfState> State; 655f757f3fSDimitry Andric 665f757f3fSDimitry Andric struct RecHeader { 675f757f3fSDimitry Andric uint32_t Id; 685f757f3fSDimitry Andric uint32_t TotalSize; 695f757f3fSDimitry Andric uint64_t Timestamp; 705f757f3fSDimitry Andric }; 715f757f3fSDimitry Andric 725f757f3fSDimitry Andric struct DIR { 735f757f3fSDimitry Andric RecHeader Prefix; 745f757f3fSDimitry Andric uint64_t CodeAddr; 755f757f3fSDimitry Andric uint64_t NrEntry; 765f757f3fSDimitry Andric }; 775f757f3fSDimitry Andric 785f757f3fSDimitry Andric struct DIE { 795f757f3fSDimitry Andric uint64_t CodeAddr; 805f757f3fSDimitry Andric uint32_t Line; 815f757f3fSDimitry Andric uint32_t Discrim; 825f757f3fSDimitry Andric }; 835f757f3fSDimitry Andric 845f757f3fSDimitry Andric struct CLR { 855f757f3fSDimitry Andric RecHeader Prefix; 865f757f3fSDimitry Andric uint32_t Pid; 875f757f3fSDimitry Andric uint32_t Tid; 885f757f3fSDimitry Andric uint64_t Vma; 895f757f3fSDimitry Andric uint64_t CodeAddr; 905f757f3fSDimitry Andric uint64_t CodeSize; 915f757f3fSDimitry Andric uint64_t CodeIndex; 925f757f3fSDimitry Andric }; 935f757f3fSDimitry Andric 945f757f3fSDimitry Andric struct UWR { 955f757f3fSDimitry Andric RecHeader Prefix; 965f757f3fSDimitry Andric uint64_t UnwindDataSize; 975f757f3fSDimitry Andric uint64_t EhFrameHeaderSize; 985f757f3fSDimitry Andric uint64_t MappedSize; 995f757f3fSDimitry Andric }; 1005f757f3fSDimitry Andric 1015f757f3fSDimitry Andric static inline uint64_t timespec_to_ns(const struct timespec *TS) { 1025f757f3fSDimitry Andric const uint64_t NanoSecPerSec = 1000000000; 1035f757f3fSDimitry Andric return ((uint64_t)TS->tv_sec * NanoSecPerSec) + TS->tv_nsec; 1045f757f3fSDimitry Andric } 1055f757f3fSDimitry Andric 1065f757f3fSDimitry Andric static inline uint64_t perf_get_timestamp() { 1075f757f3fSDimitry Andric timespec TS; 1085f757f3fSDimitry Andric if (clock_gettime(CLOCK_MONOTONIC, &TS)) 1095f757f3fSDimitry Andric return 0; 1105f757f3fSDimitry Andric 1115f757f3fSDimitry Andric return timespec_to_ns(&TS); 1125f757f3fSDimitry Andric } 1135f757f3fSDimitry Andric 1145f757f3fSDimitry Andric static void writeDebugRecord(const PerfJITDebugInfoRecord &DebugRecord) { 1155f757f3fSDimitry Andric assert(State && "PerfState not initialized"); 1165f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Writing debug record with " 1175f757f3fSDimitry Andric << DebugRecord.Entries.size() << " entries\n"); 1185f757f3fSDimitry Andric [[maybe_unused]] size_t Written = 0; 1195f757f3fSDimitry Andric DIR Dir{RecHeader{static_cast<uint32_t>(DebugRecord.Prefix.Id), 1205f757f3fSDimitry Andric DebugRecord.Prefix.TotalSize, perf_get_timestamp()}, 1215f757f3fSDimitry Andric DebugRecord.CodeAddr, DebugRecord.Entries.size()}; 1225f757f3fSDimitry Andric State->Dumpstream->write(reinterpret_cast<const char *>(&Dir), sizeof(Dir)); 1235f757f3fSDimitry Andric Written += sizeof(Dir); 1245f757f3fSDimitry Andric for (auto &Die : DebugRecord.Entries) { 1255f757f3fSDimitry Andric DIE d{Die.Addr, Die.Lineno, Die.Discrim}; 1265f757f3fSDimitry Andric State->Dumpstream->write(reinterpret_cast<const char *>(&d), sizeof(d)); 1275f757f3fSDimitry Andric State->Dumpstream->write(Die.Name.data(), Die.Name.size() + 1); 1285f757f3fSDimitry Andric Written += sizeof(d) + Die.Name.size() + 1; 1295f757f3fSDimitry Andric } 1305f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "wrote " << Written << " bytes of debug info\n"); 1315f757f3fSDimitry Andric } 1325f757f3fSDimitry Andric 1335f757f3fSDimitry Andric static void writeCodeRecord(const PerfJITCodeLoadRecord &CodeRecord) { 1345f757f3fSDimitry Andric assert(State && "PerfState not initialized"); 1355f757f3fSDimitry Andric uint32_t Tid = get_threadid(); 1365f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Writing code record with code size " 1375f757f3fSDimitry Andric << CodeRecord.CodeSize << " and code index " 1385f757f3fSDimitry Andric << CodeRecord.CodeIndex << "\n"); 1395f757f3fSDimitry Andric CLR Clr{RecHeader{static_cast<uint32_t>(CodeRecord.Prefix.Id), 1405f757f3fSDimitry Andric CodeRecord.Prefix.TotalSize, perf_get_timestamp()}, 1415f757f3fSDimitry Andric State->Pid, 1425f757f3fSDimitry Andric Tid, 1435f757f3fSDimitry Andric CodeRecord.Vma, 1445f757f3fSDimitry Andric CodeRecord.CodeAddr, 1455f757f3fSDimitry Andric CodeRecord.CodeSize, 1465f757f3fSDimitry Andric CodeRecord.CodeIndex}; 1475f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "wrote " << sizeof(Clr) << " bytes of CLR, " 1485f757f3fSDimitry Andric << CodeRecord.Name.size() + 1 << " bytes of name, " 1495f757f3fSDimitry Andric << CodeRecord.CodeSize << " bytes of code\n"); 1505f757f3fSDimitry Andric State->Dumpstream->write(reinterpret_cast<const char *>(&Clr), sizeof(Clr)); 1515f757f3fSDimitry Andric State->Dumpstream->write(CodeRecord.Name.data(), CodeRecord.Name.size() + 1); 1525f757f3fSDimitry Andric State->Dumpstream->write((const char *)CodeRecord.CodeAddr, 1535f757f3fSDimitry Andric CodeRecord.CodeSize); 1545f757f3fSDimitry Andric } 1555f757f3fSDimitry Andric 1565f757f3fSDimitry Andric static void 1575f757f3fSDimitry Andric writeUnwindRecord(const PerfJITCodeUnwindingInfoRecord &UnwindRecord) { 1585f757f3fSDimitry Andric assert(State && "PerfState not initialized"); 1595f757f3fSDimitry Andric dbgs() << "Writing unwind record with unwind data size " 1605f757f3fSDimitry Andric << UnwindRecord.UnwindDataSize << " and EH frame header size " 1615f757f3fSDimitry Andric << UnwindRecord.EHFrameHdrSize << " and mapped size " 1625f757f3fSDimitry Andric << UnwindRecord.MappedSize << "\n"; 1635f757f3fSDimitry Andric UWR Uwr{RecHeader{static_cast<uint32_t>(UnwindRecord.Prefix.Id), 1645f757f3fSDimitry Andric UnwindRecord.Prefix.TotalSize, perf_get_timestamp()}, 1655f757f3fSDimitry Andric UnwindRecord.UnwindDataSize, UnwindRecord.EHFrameHdrSize, 1665f757f3fSDimitry Andric UnwindRecord.MappedSize}; 1675f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "wrote " << sizeof(Uwr) << " bytes of UWR, " 1685f757f3fSDimitry Andric << UnwindRecord.EHFrameHdrSize 1695f757f3fSDimitry Andric << " bytes of EH frame header, " 1705f757f3fSDimitry Andric << UnwindRecord.UnwindDataSize - UnwindRecord.EHFrameHdrSize 1715f757f3fSDimitry Andric << " bytes of EH frame\n"); 1725f757f3fSDimitry Andric State->Dumpstream->write(reinterpret_cast<const char *>(&Uwr), sizeof(Uwr)); 1735f757f3fSDimitry Andric if (UnwindRecord.EHFrameHdrAddr) 1745f757f3fSDimitry Andric State->Dumpstream->write((const char *)UnwindRecord.EHFrameHdrAddr, 1755f757f3fSDimitry Andric UnwindRecord.EHFrameHdrSize); 1765f757f3fSDimitry Andric else 1775f757f3fSDimitry Andric State->Dumpstream->write(UnwindRecord.EHFrameHdr.data(), 1785f757f3fSDimitry Andric UnwindRecord.EHFrameHdrSize); 1795f757f3fSDimitry Andric State->Dumpstream->write((const char *)UnwindRecord.EHFrameAddr, 1805f757f3fSDimitry Andric UnwindRecord.UnwindDataSize - 1815f757f3fSDimitry Andric UnwindRecord.EHFrameHdrSize); 1825f757f3fSDimitry Andric } 1835f757f3fSDimitry Andric 1845f757f3fSDimitry Andric static Error registerJITLoaderPerfImpl(const PerfJITRecordBatch &Batch) { 1855f757f3fSDimitry Andric if (!State) 1865f757f3fSDimitry Andric return make_error<StringError>("PerfState not initialized", 1875f757f3fSDimitry Andric inconvertibleErrorCode()); 1885f757f3fSDimitry Andric 1895f757f3fSDimitry Andric // Serialize the batch 1905f757f3fSDimitry Andric std::lock_guard<std::mutex> Lock(Mutex); 1915f757f3fSDimitry Andric if (Batch.UnwindingRecord.Prefix.TotalSize > 0) 1925f757f3fSDimitry Andric writeUnwindRecord(Batch.UnwindingRecord); 1935f757f3fSDimitry Andric 1945f757f3fSDimitry Andric for (const auto &DebugInfo : Batch.DebugInfoRecords) 1955f757f3fSDimitry Andric writeDebugRecord(DebugInfo); 1965f757f3fSDimitry Andric 1975f757f3fSDimitry Andric for (const auto &CodeLoad : Batch.CodeLoadRecords) 1985f757f3fSDimitry Andric writeCodeRecord(CodeLoad); 1995f757f3fSDimitry Andric 2005f757f3fSDimitry Andric State->Dumpstream->flush(); 2015f757f3fSDimitry Andric 2025f757f3fSDimitry Andric return Error::success(); 2035f757f3fSDimitry Andric } 2045f757f3fSDimitry Andric 2055f757f3fSDimitry Andric struct Header { 2065f757f3fSDimitry Andric uint32_t Magic; // characters "JiTD" 2075f757f3fSDimitry Andric uint32_t Version; // header version 2085f757f3fSDimitry Andric uint32_t TotalSize; // total size of header 2095f757f3fSDimitry Andric uint32_t ElfMach; // elf mach target 2105f757f3fSDimitry Andric uint32_t Pad1; // reserved 2115f757f3fSDimitry Andric uint32_t Pid; 2125f757f3fSDimitry Andric uint64_t Timestamp; // timestamp 2135f757f3fSDimitry Andric uint64_t Flags; // flags 2145f757f3fSDimitry Andric }; 2155f757f3fSDimitry Andric 2165f757f3fSDimitry Andric static Error OpenMarker(PerfState &State) { 2175f757f3fSDimitry Andric // We mmap the jitdump to create an MMAP RECORD in perf.data file. The mmap 2185f757f3fSDimitry Andric // is captured either live (perf record running when we mmap) or in deferred 2195f757f3fSDimitry Andric // mode, via /proc/PID/maps. The MMAP record is used as a marker of a jitdump 2205f757f3fSDimitry Andric // file for more meta data info about the jitted code. Perf report/annotate 2215f757f3fSDimitry Andric // detect this special filename and process the jitdump file. 2225f757f3fSDimitry Andric // 2235f757f3fSDimitry Andric // Mapping must be PROT_EXEC to ensure it is captured by perf record 2245f757f3fSDimitry Andric // even when not using -d option. 2255f757f3fSDimitry Andric State.MarkerAddr = 2265f757f3fSDimitry Andric ::mmap(NULL, sys::Process::getPageSizeEstimate(), PROT_READ | PROT_EXEC, 2275f757f3fSDimitry Andric MAP_PRIVATE, State.DumpFd, 0); 2285f757f3fSDimitry Andric 2295f757f3fSDimitry Andric if (State.MarkerAddr == MAP_FAILED) 2305f757f3fSDimitry Andric return make_error<llvm::StringError>("could not mmap JIT marker", 2315f757f3fSDimitry Andric inconvertibleErrorCode()); 2325f757f3fSDimitry Andric 2335f757f3fSDimitry Andric return Error::success(); 2345f757f3fSDimitry Andric } 2355f757f3fSDimitry Andric 2365f757f3fSDimitry Andric void CloseMarker(PerfState &State) { 2375f757f3fSDimitry Andric if (!State.MarkerAddr) 2385f757f3fSDimitry Andric return; 2395f757f3fSDimitry Andric 2405f757f3fSDimitry Andric munmap(State.MarkerAddr, sys::Process::getPageSizeEstimate()); 2415f757f3fSDimitry Andric State.MarkerAddr = nullptr; 2425f757f3fSDimitry Andric } 2435f757f3fSDimitry Andric 2445f757f3fSDimitry Andric static Expected<Header> FillMachine(PerfState &State) { 2455f757f3fSDimitry Andric Header Hdr; 2465f757f3fSDimitry Andric Hdr.Magic = LLVM_PERF_JIT_MAGIC; 2475f757f3fSDimitry Andric Hdr.Version = LLVM_PERF_JIT_VERSION; 2485f757f3fSDimitry Andric Hdr.TotalSize = sizeof(Hdr); 2495f757f3fSDimitry Andric Hdr.Pid = State.Pid; 2505f757f3fSDimitry Andric Hdr.Timestamp = perf_get_timestamp(); 2515f757f3fSDimitry Andric 2525f757f3fSDimitry Andric char Id[16]; 2535f757f3fSDimitry Andric struct { 2545f757f3fSDimitry Andric uint16_t e_type; 2555f757f3fSDimitry Andric uint16_t e_machine; 2565f757f3fSDimitry Andric } Info; 2575f757f3fSDimitry Andric 2585f757f3fSDimitry Andric size_t RequiredMemory = sizeof(Id) + sizeof(Info); 2595f757f3fSDimitry Andric 2605f757f3fSDimitry Andric ErrorOr<std::unique_ptr<MemoryBuffer>> MB = 2615f757f3fSDimitry Andric MemoryBuffer::getFileSlice("/proc/self/exe", RequiredMemory, 0); 2625f757f3fSDimitry Andric 2635f757f3fSDimitry Andric // This'll not guarantee that enough data was actually read from the 2645f757f3fSDimitry Andric // underlying file. Instead the trailing part of the buffer would be 2655f757f3fSDimitry Andric // zeroed. Given the ELF signature check below that seems ok though, 2665f757f3fSDimitry Andric // it's unlikely that the file ends just after that, and the 2675f757f3fSDimitry Andric // consequence would just be that perf wouldn't recognize the 2685f757f3fSDimitry Andric // signature. 2695f757f3fSDimitry Andric if (!MB) 2705f757f3fSDimitry Andric return make_error<llvm::StringError>("could not open /proc/self/exe", 2715f757f3fSDimitry Andric MB.getError()); 2725f757f3fSDimitry Andric 2735f757f3fSDimitry Andric memcpy(&Id, (*MB)->getBufferStart(), sizeof(Id)); 2745f757f3fSDimitry Andric memcpy(&Info, (*MB)->getBufferStart() + sizeof(Id), sizeof(Info)); 2755f757f3fSDimitry Andric 2765f757f3fSDimitry Andric // check ELF signature 2775f757f3fSDimitry Andric if (Id[0] != 0x7f || Id[1] != 'E' || Id[2] != 'L' || Id[3] != 'F') 2785f757f3fSDimitry Andric return make_error<llvm::StringError>("invalid ELF signature", 2795f757f3fSDimitry Andric inconvertibleErrorCode()); 2805f757f3fSDimitry Andric 2815f757f3fSDimitry Andric Hdr.ElfMach = Info.e_machine; 2825f757f3fSDimitry Andric 2835f757f3fSDimitry Andric return Hdr; 2845f757f3fSDimitry Andric } 2855f757f3fSDimitry Andric 2865f757f3fSDimitry Andric static Error InitDebuggingDir(PerfState &State) { 2875f757f3fSDimitry Andric time_t Time; 2885f757f3fSDimitry Andric struct tm LocalTime; 2895f757f3fSDimitry Andric char TimeBuffer[sizeof("YYYYMMDD")]; 2905f757f3fSDimitry Andric SmallString<64> Path; 2915f757f3fSDimitry Andric 2925f757f3fSDimitry Andric // search for location to dump data to 2935f757f3fSDimitry Andric if (const char *BaseDir = getenv("JITDUMPDIR")) 2945f757f3fSDimitry Andric Path.append(BaseDir); 2955f757f3fSDimitry Andric else if (!sys::path::home_directory(Path)) 2965f757f3fSDimitry Andric Path = "."; 2975f757f3fSDimitry Andric 2985f757f3fSDimitry Andric // create debug directory 2995f757f3fSDimitry Andric Path += "/.debug/jit/"; 3005f757f3fSDimitry Andric if (auto EC = sys::fs::create_directories(Path)) { 3015f757f3fSDimitry Andric std::string ErrStr; 3025f757f3fSDimitry Andric raw_string_ostream ErrStream(ErrStr); 3035f757f3fSDimitry Andric ErrStream << "could not create jit cache directory " << Path << ": " 3045f757f3fSDimitry Andric << EC.message() << "\n"; 3055f757f3fSDimitry Andric return make_error<StringError>(std::move(ErrStr), inconvertibleErrorCode()); 3065f757f3fSDimitry Andric } 3075f757f3fSDimitry Andric 3085f757f3fSDimitry Andric // create unique directory for dump data related to this process 3095f757f3fSDimitry Andric time(&Time); 3105f757f3fSDimitry Andric localtime_r(&Time, &LocalTime); 3115f757f3fSDimitry Andric strftime(TimeBuffer, sizeof(TimeBuffer), "%Y%m%d", &LocalTime); 3125f757f3fSDimitry Andric Path += JIT_LANG "-jit-"; 3135f757f3fSDimitry Andric Path += TimeBuffer; 3145f757f3fSDimitry Andric 3155f757f3fSDimitry Andric SmallString<128> UniqueDebugDir; 3165f757f3fSDimitry Andric 3175f757f3fSDimitry Andric using sys::fs::createUniqueDirectory; 3185f757f3fSDimitry Andric if (auto EC = createUniqueDirectory(Path, UniqueDebugDir)) { 3195f757f3fSDimitry Andric std::string ErrStr; 3205f757f3fSDimitry Andric raw_string_ostream ErrStream(ErrStr); 3215f757f3fSDimitry Andric ErrStream << "could not create unique jit cache directory " 3225f757f3fSDimitry Andric << UniqueDebugDir << ": " << EC.message() << "\n"; 3235f757f3fSDimitry Andric return make_error<StringError>(std::move(ErrStr), inconvertibleErrorCode()); 3245f757f3fSDimitry Andric } 3255f757f3fSDimitry Andric 326*7a6dacacSDimitry Andric State.JitPath = std::string(UniqueDebugDir); 3275f757f3fSDimitry Andric 3285f757f3fSDimitry Andric return Error::success(); 3295f757f3fSDimitry Andric } 3305f757f3fSDimitry Andric 3315f757f3fSDimitry Andric static Error registerJITLoaderPerfStartImpl() { 3325f757f3fSDimitry Andric PerfState Tentative; 3335f757f3fSDimitry Andric Tentative.Pid = sys::Process::getProcessId(); 3345f757f3fSDimitry Andric // check if clock-source is supported 3355f757f3fSDimitry Andric if (!perf_get_timestamp()) 3365f757f3fSDimitry Andric return make_error<StringError>("kernel does not support CLOCK_MONOTONIC", 3375f757f3fSDimitry Andric inconvertibleErrorCode()); 3385f757f3fSDimitry Andric 3395f757f3fSDimitry Andric if (auto Err = InitDebuggingDir(Tentative)) 3405f757f3fSDimitry Andric return Err; 3415f757f3fSDimitry Andric 3425f757f3fSDimitry Andric std::string Filename; 3435f757f3fSDimitry Andric raw_string_ostream FilenameBuf(Filename); 3445f757f3fSDimitry Andric FilenameBuf << Tentative.JitPath << "/jit-" << Tentative.Pid << ".dump"; 3455f757f3fSDimitry Andric 3465f757f3fSDimitry Andric // Need to open ourselves, because we need to hand the FD to OpenMarker() and 3475f757f3fSDimitry Andric // raw_fd_ostream doesn't expose the FD. 3485f757f3fSDimitry Andric using sys::fs::openFileForWrite; 3495f757f3fSDimitry Andric if (auto EC = openFileForReadWrite(FilenameBuf.str(), Tentative.DumpFd, 3505f757f3fSDimitry Andric sys::fs::CD_CreateNew, sys::fs::OF_None)) { 3515f757f3fSDimitry Andric std::string ErrStr; 3525f757f3fSDimitry Andric raw_string_ostream ErrStream(ErrStr); 3535f757f3fSDimitry Andric ErrStream << "could not open JIT dump file " << FilenameBuf.str() << ": " 3545f757f3fSDimitry Andric << EC.message() << "\n"; 3555f757f3fSDimitry Andric return make_error<StringError>(std::move(ErrStr), inconvertibleErrorCode()); 3565f757f3fSDimitry Andric } 3575f757f3fSDimitry Andric 3585f757f3fSDimitry Andric Tentative.Dumpstream = 3595f757f3fSDimitry Andric std::make_unique<raw_fd_ostream>(Tentative.DumpFd, true); 3605f757f3fSDimitry Andric 3615f757f3fSDimitry Andric auto Header = FillMachine(Tentative); 3625f757f3fSDimitry Andric if (!Header) 3635f757f3fSDimitry Andric return Header.takeError(); 3645f757f3fSDimitry Andric 3655f757f3fSDimitry Andric // signal this process emits JIT information 3665f757f3fSDimitry Andric if (auto Err = OpenMarker(Tentative)) 3675f757f3fSDimitry Andric return Err; 3685f757f3fSDimitry Andric 3695f757f3fSDimitry Andric Tentative.Dumpstream->write(reinterpret_cast<const char *>(&Header.get()), 3705f757f3fSDimitry Andric sizeof(*Header)); 3715f757f3fSDimitry Andric 3725f757f3fSDimitry Andric // Everything initialized, can do profiling now. 3735f757f3fSDimitry Andric if (Tentative.Dumpstream->has_error()) 3745f757f3fSDimitry Andric return make_error<StringError>("could not write JIT dump header", 3755f757f3fSDimitry Andric inconvertibleErrorCode()); 3765f757f3fSDimitry Andric 3775f757f3fSDimitry Andric State = std::move(Tentative); 3785f757f3fSDimitry Andric return Error::success(); 3795f757f3fSDimitry Andric } 3805f757f3fSDimitry Andric 3815f757f3fSDimitry Andric static Error registerJITLoaderPerfEndImpl() { 3825f757f3fSDimitry Andric if (!State) 3835f757f3fSDimitry Andric return make_error<StringError>("PerfState not initialized", 3845f757f3fSDimitry Andric inconvertibleErrorCode()); 3855f757f3fSDimitry Andric 3865f757f3fSDimitry Andric RecHeader Close; 3875f757f3fSDimitry Andric Close.Id = static_cast<uint32_t>(PerfJITRecordType::JIT_CODE_CLOSE); 3885f757f3fSDimitry Andric Close.TotalSize = sizeof(Close); 3895f757f3fSDimitry Andric Close.Timestamp = perf_get_timestamp(); 3905f757f3fSDimitry Andric State->Dumpstream->write(reinterpret_cast<const char *>(&Close), 3915f757f3fSDimitry Andric sizeof(Close)); 3925f757f3fSDimitry Andric if (State->MarkerAddr) 3935f757f3fSDimitry Andric CloseMarker(*State); 3945f757f3fSDimitry Andric 3955f757f3fSDimitry Andric State.reset(); 3965f757f3fSDimitry Andric return Error::success(); 3975f757f3fSDimitry Andric } 3985f757f3fSDimitry Andric 3995f757f3fSDimitry Andric extern "C" llvm::orc::shared::CWrapperFunctionResult 4005f757f3fSDimitry Andric llvm_orc_registerJITLoaderPerfImpl(const char *Data, uint64_t Size) { 4015f757f3fSDimitry Andric using namespace orc::shared; 4025f757f3fSDimitry Andric return WrapperFunction<SPSError(SPSPerfJITRecordBatch)>::handle( 4035f757f3fSDimitry Andric Data, Size, registerJITLoaderPerfImpl) 4045f757f3fSDimitry Andric .release(); 4055f757f3fSDimitry Andric } 4065f757f3fSDimitry Andric 4075f757f3fSDimitry Andric extern "C" llvm::orc::shared::CWrapperFunctionResult 4085f757f3fSDimitry Andric llvm_orc_registerJITLoaderPerfStart(const char *Data, uint64_t Size) { 4095f757f3fSDimitry Andric using namespace orc::shared; 4105f757f3fSDimitry Andric return WrapperFunction<SPSError()>::handle(Data, Size, 4115f757f3fSDimitry Andric registerJITLoaderPerfStartImpl) 4125f757f3fSDimitry Andric .release(); 4135f757f3fSDimitry Andric } 4145f757f3fSDimitry Andric 4155f757f3fSDimitry Andric extern "C" llvm::orc::shared::CWrapperFunctionResult 4165f757f3fSDimitry Andric llvm_orc_registerJITLoaderPerfEnd(const char *Data, uint64_t Size) { 4175f757f3fSDimitry Andric using namespace orc::shared; 4185f757f3fSDimitry Andric return WrapperFunction<SPSError()>::handle(Data, Size, 4195f757f3fSDimitry Andric registerJITLoaderPerfEndImpl) 4205f757f3fSDimitry Andric .release(); 4215f757f3fSDimitry Andric } 4225f757f3fSDimitry Andric 4235f757f3fSDimitry Andric #else 4245f757f3fSDimitry Andric 4255f757f3fSDimitry Andric using namespace llvm; 4265f757f3fSDimitry Andric using namespace llvm::orc; 4275f757f3fSDimitry Andric 4285f757f3fSDimitry Andric static Error badOS() { 4295f757f3fSDimitry Andric using namespace llvm; 4305f757f3fSDimitry Andric return llvm::make_error<StringError>( 4315f757f3fSDimitry Andric "unsupported OS (perf support is only available on linux!)", 4325f757f3fSDimitry Andric inconvertibleErrorCode()); 4335f757f3fSDimitry Andric } 4345f757f3fSDimitry Andric 4355f757f3fSDimitry Andric static Error badOSBatch(PerfJITRecordBatch &Batch) { return badOS(); } 4365f757f3fSDimitry Andric 4375f757f3fSDimitry Andric extern "C" llvm::orc::shared::CWrapperFunctionResult 4385f757f3fSDimitry Andric llvm_orc_registerJITLoaderPerfImpl(const char *Data, uint64_t Size) { 4395f757f3fSDimitry Andric using namespace shared; 4405f757f3fSDimitry Andric return WrapperFunction<SPSError(SPSPerfJITRecordBatch)>::handle(Data, Size, 4415f757f3fSDimitry Andric badOSBatch) 4425f757f3fSDimitry Andric .release(); 4435f757f3fSDimitry Andric } 4445f757f3fSDimitry Andric 4455f757f3fSDimitry Andric extern "C" llvm::orc::shared::CWrapperFunctionResult 4465f757f3fSDimitry Andric llvm_orc_registerJITLoaderPerfStart(const char *Data, uint64_t Size) { 4475f757f3fSDimitry Andric using namespace shared; 4485f757f3fSDimitry Andric return WrapperFunction<SPSError()>::handle(Data, Size, badOS).release(); 4495f757f3fSDimitry Andric } 4505f757f3fSDimitry Andric 4515f757f3fSDimitry Andric extern "C" llvm::orc::shared::CWrapperFunctionResult 4525f757f3fSDimitry Andric llvm_orc_registerJITLoaderPerfEnd(const char *Data, uint64_t Size) { 4535f757f3fSDimitry Andric using namespace shared; 4545f757f3fSDimitry Andric return WrapperFunction<SPSError()>::handle(Data, Size, badOS).release(); 4555f757f3fSDimitry Andric } 4565f757f3fSDimitry Andric 4575f757f3fSDimitry Andric #endif 458