xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/JITLoaderPerf.cpp (revision 7a6dacaca14b62ca4b74406814becb87a3fefac0)
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