LCOV - code coverage report
Current view: top level - lib/ExecutionEngine/PerfJITEvents - PerfJITEventListener.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 23 144 16.0 %
Date: 2018-10-20 13:21:21 Functions: 5 15 33.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===-- PerfJITEventListener.cpp - Tell Linux's perf about JITted code ----===//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is distributed under the University of Illinois Open Source
       6             : // License. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : //
      10             : // This file defines a JITEventListener object that tells perf about JITted
      11             : // functions, including source line information.
      12             : //
      13             : // Documentation for perf jit integration is available at:
      14             : // https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/tools/perf/Documentation/jitdump-specification.txt
      15             : // https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/tools/perf/Documentation/jit-interface.txt
      16             : //
      17             : //===----------------------------------------------------------------------===//
      18             : 
      19             : #include "llvm/ADT/Twine.h"
      20             : #include "llvm/Config/config.h"
      21             : #include "llvm/DebugInfo/DWARF/DWARFContext.h"
      22             : #include "llvm/ExecutionEngine/JITEventListener.h"
      23             : #include "llvm/Object/ObjectFile.h"
      24             : #include "llvm/Object/SymbolSize.h"
      25             : #include "llvm/Support/Debug.h"
      26             : #include "llvm/Support/Errno.h"
      27             : #include "llvm/Support/FileSystem.h"
      28             : #include "llvm/Support/MemoryBuffer.h"
      29             : #include "llvm/Support/Mutex.h"
      30             : #include "llvm/Support/MutexGuard.h"
      31             : #include "llvm/Support/Path.h"
      32             : #include "llvm/Support/Process.h"
      33             : #include "llvm/Support/Threading.h"
      34             : #include "llvm/Support/raw_ostream.h"
      35             : 
      36             : #include <sys/mman.h>  // mmap()
      37             : #include <sys/types.h> // getpid()
      38             : #include <time.h>      // clock_gettime(), time(), localtime_r() */
      39             : #include <unistd.h>    // for getpid(), read(), close()
      40             : 
      41             : using namespace llvm;
      42             : using namespace llvm::object;
      43             : typedef DILineInfoSpecifier::FileLineInfoKind FileLineInfoKind;
      44             : 
      45             : namespace {
      46             : 
      47             : // language identifier (XXX: should we generate something better from debug
      48             : // info?)
      49             : #define JIT_LANG "llvm-IR"
      50             : #define LLVM_PERF_JIT_MAGIC                                                    \
      51             :   ((uint32_t)'J' << 24 | (uint32_t)'i' << 16 | (uint32_t)'T' << 8 |            \
      52             :    (uint32_t)'D')
      53             : #define LLVM_PERF_JIT_VERSION 1
      54             : 
      55             : // bit 0: set if the jitdump file is using an architecture-specific timestamp
      56             : // clock source
      57             : #define JITDUMP_FLAGS_ARCH_TIMESTAMP (1ULL << 0)
      58             : 
      59             : struct LLVMPerfJitHeader;
      60             : 
      61             : class PerfJITEventListener : public JITEventListener {
      62             : public:
      63             :   PerfJITEventListener();
      64           0 :   ~PerfJITEventListener() {
      65           0 :     if (MarkerAddr)
      66           0 :       CloseMarker();
      67           0 :   }
      68           0 : 
      69             :   void NotifyObjectEmitted(const ObjectFile &Obj,
      70             :                            const RuntimeDyld::LoadedObjectInfo &L) override;
      71           0 :   void NotifyFreeingObject(const ObjectFile &Obj) override;
      72           0 : 
      73           0 : private:
      74           0 :   bool InitDebuggingDir();
      75           0 :   bool OpenMarker();
      76             :   void CloseMarker();
      77             :   static bool FillMachine(LLVMPerfJitHeader &hdr);
      78             : 
      79             :   void NotifyCode(Expected<llvm::StringRef> &Symbol, uint64_t CodeAddr,
      80             :                   uint64_t CodeSize);
      81             :   void NotifyDebug(uint64_t CodeAddr, DILineInfoTable Lines);
      82             : 
      83             :   // cache lookups
      84             :   pid_t Pid;
      85             : 
      86             :   // base directory for output data
      87             :   std::string JitPath;
      88             : 
      89             :   // output data stream, closed via Dumpstream
      90             :   int DumpFd = -1;
      91             : 
      92             :   // output data stream
      93             :   std::unique_ptr<raw_fd_ostream> Dumpstream;
      94             : 
      95             :   // prevent concurrent dumps from messing up the output file
      96             :   sys::Mutex Mutex;
      97             : 
      98             :   // perf mmap marker
      99             :   void *MarkerAddr = NULL;
     100             : 
     101             :   // perf support ready
     102             :   bool SuccessfullyInitialized = false;
     103             : 
     104             :   // identifier for functions, primarily to identify when moving them around
     105             :   uint64_t CodeGeneration = 1;
     106             : };
     107             : 
     108             : // The following are POD struct definitions from the perf jit specification
     109             : 
     110             : enum LLVMPerfJitRecordType {
     111             :   JIT_CODE_LOAD = 0,
     112             :   JIT_CODE_MOVE = 1, // not emitted, code isn't moved
     113             :   JIT_CODE_DEBUG_INFO = 2,
     114             :   JIT_CODE_CLOSE = 3,          // not emitted, unnecessary
     115             :   JIT_CODE_UNWINDING_INFO = 4, // not emitted
     116             : 
     117             :   JIT_CODE_MAX
     118             : };
     119             : 
     120             : struct LLVMPerfJitHeader {
     121             :   uint32_t Magic;     // characters "JiTD"
     122             :   uint32_t Version;   // header version
     123             :   uint32_t TotalSize; // total size of header
     124             :   uint32_t ElfMach;   // elf mach target
     125             :   uint32_t Pad1;      // reserved
     126             :   uint32_t Pid;
     127             :   uint64_t Timestamp; // timestamp
     128             :   uint64_t Flags;     // flags
     129             : };
     130             : 
     131             : // record prefix (mandatory in each record)
     132             : struct LLVMPerfJitRecordPrefix {
     133             :   uint32_t Id; // record type identifier
     134             :   uint32_t TotalSize;
     135             :   uint64_t Timestamp;
     136             : };
     137             : 
     138             : struct LLVMPerfJitRecordCodeLoad {
     139             :   LLVMPerfJitRecordPrefix Prefix;
     140             : 
     141             :   uint32_t Pid;
     142             :   uint32_t Tid;
     143             :   uint64_t Vma;
     144             :   uint64_t CodeAddr;
     145             :   uint64_t CodeSize;
     146             :   uint64_t CodeIndex;
     147             : };
     148             : 
     149             : struct LLVMPerfJitDebugEntry {
     150             :   uint64_t Addr;
     151             :   int Lineno;  // source line number starting at 1
     152             :   int Discrim; // column discriminator, 0 is default
     153             :   // followed by null terminated filename, \xff\0 if same as previous entry
     154             : };
     155             : 
     156             : struct LLVMPerfJitRecordDebugInfo {
     157             :   LLVMPerfJitRecordPrefix Prefix;
     158             : 
     159             :   uint64_t CodeAddr;
     160             :   uint64_t NrEntry;
     161             :   // followed by NrEntry LLVMPerfJitDebugEntry records
     162             : };
     163             : 
     164             : static inline uint64_t timespec_to_ns(const struct timespec *ts) {
     165             :   const uint64_t NanoSecPerSec = 1000000000;
     166             :   return ((uint64_t)ts->tv_sec * NanoSecPerSec) + ts->tv_nsec;
     167             : }
     168             : 
     169             : static inline uint64_t perf_get_timestamp(void) {
     170             :   struct timespec ts;
     171             :   int ret;
     172           0 : 
     173             :   ret = clock_gettime(CLOCK_MONOTONIC, &ts);
     174         155 :   if (ret)
     175             :     return 0;
     176             : 
     177         155 :   return timespec_to_ns(&ts);
     178             : }
     179             : 
     180             : PerfJITEventListener::PerfJITEventListener() : Pid(::getpid()) {
     181         155 :   // check if clock-source is supported
     182         155 :   if (!perf_get_timestamp()) {
     183             :     errs() << "kernel does not support CLOCK_MONOTONIC\n";
     184             :     return;
     185         155 :   }
     186             : 
     187             :   if (!InitDebuggingDir()) {
     188         155 :     errs() << "could not initialize debugging directory\n";
     189             :     return;
     190         155 :   }
     191           0 : 
     192         155 :   std::string Filename;
     193             :   raw_string_ostream FilenameBuf(Filename);
     194             :   FilenameBuf << JitPath << "/jit-" << Pid << ".dump";
     195         155 : 
     196         155 :   // Need to open ourselves, because we need to hand the FD to OpenMarker() and
     197         155 :   // raw_fd_ostream doesn't expose the FD.
     198             :   using sys::fs::openFileForWrite;
     199             :   if (auto EC =
     200             :           openFileForReadWrite(FilenameBuf.str(), DumpFd,
     201           0 :                                sys::fs::CD_CreateNew, sys::fs::OF_None)) {
     202           0 :     errs() << "could not open JIT dump file " << FilenameBuf.str() << ": "
     203             :            << EC.message() << "\n";
     204             :     return;
     205             :   }
     206             : 
     207           0 :   Dumpstream = make_unique<raw_fd_ostream>(DumpFd, true);
     208           0 : 
     209           0 :   LLVMPerfJitHeader Header = {0};
     210           0 :   if (!FillMachine(Header))
     211           0 :     return;
     212             : 
     213             :   // signal this process emits JIT information
     214             :   if (!OpenMarker())
     215           0 :     return;
     216             : 
     217           0 :   // emit dumpstream header
     218           0 :   Header.Magic = LLVM_PERF_JIT_MAGIC;
     219             :   Header.Version = LLVM_PERF_JIT_VERSION;
     220             :   Header.TotalSize = sizeof(Header);
     221             :   Header.Pid = Pid;
     222           0 :   Header.Timestamp = perf_get_timestamp();
     223             :   Dumpstream->write(reinterpret_cast<const char *>(&Header), sizeof(Header));
     224             : 
     225             :   // Everything initialized, can do profiling now.
     226           0 :   if (!Dumpstream->has_error())
     227           0 :     SuccessfullyInitialized = true;
     228           0 : }
     229           0 : 
     230           0 : void PerfJITEventListener::NotifyObjectEmitted(
     231           0 :     const ObjectFile &Obj, const RuntimeDyld::LoadedObjectInfo &L) {
     232             : 
     233             :   if (!SuccessfullyInitialized)
     234           0 :     return;
     235           0 : 
     236             :   OwningBinary<ObjectFile> DebugObjOwner = L.getObjectForDebug(Obj);
     237             :   const ObjectFile &DebugObj = *DebugObjOwner.getBinary();
     238          83 : 
     239             :   // Get the address of the object image for use as a unique identifier
     240             :   std::unique_ptr<DIContext> Context = DWARFContext::create(DebugObj);
     241          83 : 
     242          83 :   // Use symbol info to iterate over functions in the object.
     243             :   for (const std::pair<SymbolRef, uint64_t> &P : computeSymbolSizes(DebugObj)) {
     244           0 :     SymbolRef Sym = P.first;
     245             :     std::string SourceFileName;
     246             : 
     247             :     Expected<SymbolRef::Type> SymTypeOrErr = Sym.getType();
     248           0 :     if (!SymTypeOrErr) {
     249             :       // There's not much we can with errors here
     250             :       consumeError(SymTypeOrErr.takeError());
     251           0 :       continue;
     252           0 :     }
     253             :     SymbolRef::Type SymType = *SymTypeOrErr;
     254             :     if (SymType != SymbolRef::ST_Function)
     255             :       continue;
     256           0 : 
     257             :     Expected<StringRef> Name = Sym.getName();
     258           0 :     if (!Name) {
     259           0 :       consumeError(Name.takeError());
     260             :       continue;
     261           0 :     }
     262           0 : 
     263             :     Expected<uint64_t> AddrOrErr = Sym.getAddress();
     264             :     if (!AddrOrErr) {
     265             :       consumeError(AddrOrErr.takeError());
     266           0 :       continue;
     267           0 :     }
     268           0 :     uint64_t Addr = *AddrOrErr;
     269             :     uint64_t Size = P.second;
     270             : 
     271             :     // According to spec debugging info has to come before loading the
     272           0 :     // corresonding code load.
     273           0 :     DILineInfoTable Lines = Context->getLineInfoForAddressRange(
     274             :         Addr, Size, FileLineInfoKind::AbsoluteFilePath);
     275             : 
     276           0 :     NotifyDebug(Addr, Lines);
     277           0 :     NotifyCode(Name, Addr, Size);
     278             :   }
     279             : 
     280             :   Dumpstream->flush();
     281             : }
     282           0 : 
     283             : void PerfJITEventListener::NotifyFreeingObject(const ObjectFile &Obj) {
     284           0 :   // perf currently doesn't have an interface for unloading. But munmap()ing the
     285           0 :   // code section does, so that's ok.
     286             : }
     287             : 
     288           0 : bool PerfJITEventListener::InitDebuggingDir() {
     289             :   time_t Time;
     290             :   struct tm LocalTime;
     291           0 :   char TimeBuffer[sizeof("YYYYMMDD")];
     292             :   SmallString<64> Path;
     293             : 
     294           0 :   // search for location to dump data to
     295             :   if (const char *BaseDir = getenv("JITDUMPDIR"))
     296         155 :     Path.append(BaseDir);
     297             :   else if (!sys::path::home_directory(Path))
     298             :     Path = ".";
     299             : 
     300             :   // create debug directory
     301             :   Path += "/.debug/jit/";
     302             :   if (auto EC = sys::fs::create_directories(Path)) {
     303         155 :     errs() << "could not create jit cache directory " << Path << ": "
     304             :            << EC.message() << "\n";
     305         155 :     return false;
     306             :   }
     307             : 
     308             :   // create unique directory for dump data related to this process
     309             :   time(&Time);
     310         155 :   localtime_r(&Time, &LocalTime);
     311         310 :   strftime(TimeBuffer, sizeof(TimeBuffer), "%Y%m%d", &LocalTime);
     312         155 :   Path += JIT_LANG "-jit-";
     313         155 :   Path += TimeBuffer;
     314             : 
     315             :   SmallString<128> UniqueDebugDir;
     316             : 
     317           0 :   using sys::fs::createUniqueDirectory;
     318           0 :   if (auto EC = createUniqueDirectory(Path, UniqueDebugDir)) {
     319           0 :     errs() << "could not create unique jit cache directory " << UniqueDebugDir
     320             :            << ": " << EC.message() << "\n";
     321             :     return false;
     322             :   }
     323             : 
     324             :   JitPath = UniqueDebugDir.str();
     325             : 
     326           0 :   return true;
     327           0 : }
     328           0 : 
     329           0 : bool PerfJITEventListener::OpenMarker() {
     330             :   // We mmap the jitdump to create an MMAP RECORD in perf.data file.  The mmap
     331             :   // is captured either live (perf record running when we mmap) or in deferred
     332           0 :   // mode, via /proc/PID/maps. The MMAP record is used as a marker of a jitdump
     333             :   // file for more meta data info about the jitted code. Perf report/annotate
     334           0 :   // detect this special filename and process the jitdump file.
     335             :   //
     336             :   // Mapping must be PROT_EXEC to ensure it is captured by perf record
     337           0 :   // even when not using -d option.
     338             :   MarkerAddr = ::mmap(NULL, sys::Process::getPageSize(), PROT_READ | PROT_EXEC,
     339             :                       MAP_PRIVATE, DumpFd, 0);
     340             : 
     341             :   if (MarkerAddr == MAP_FAILED) {
     342             :     errs() << "could not mmap JIT marker\n";
     343             :     return false;
     344             :   }
     345             :   return true;
     346           0 : }
     347             : 
     348             : void PerfJITEventListener::CloseMarker() {
     349           0 :   if (!MarkerAddr)
     350           0 :     return;
     351           0 : 
     352             :   munmap(MarkerAddr, sys::Process::getPageSize());
     353             :   MarkerAddr = nullptr;
     354             : }
     355             : 
     356           0 : bool PerfJITEventListener::FillMachine(LLVMPerfJitHeader &hdr) {
     357           0 :   char id[16];
     358           0 :   struct {
     359             :     uint16_t e_type;
     360           0 :     uint16_t e_machine;
     361           0 :   } info;
     362             : 
     363             :   size_t RequiredMemory = sizeof(id) + sizeof(info);
     364           0 : 
     365             :   ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
     366             :     MemoryBuffer::getFileSlice("/proc/self/exe",
     367             :                                RequiredMemory,
     368             :                                0);
     369             : 
     370             :   // This'll not guarantee that enough data was actually read from the
     371             :   // underlying file. Instead the trailing part of the buffer would be
     372             :   // zeroed. Given the ELF signature check below that seems ok though,
     373             :   // it's unlikely that the file ends just after that, and the
     374             :   // consequence would just be that perf wouldn't recognize the
     375             :   // signature.
     376           0 :   if (auto EC = MB.getError()) {
     377             :     errs() << "could not open /proc/self/exe: " << EC.message() << "\n";
     378             :     return false;
     379             :   }
     380             : 
     381             :   memcpy(&id, (*MB)->getBufferStart(), sizeof(id));
     382             :   memcpy(&info, (*MB)->getBufferStart() + sizeof(id), sizeof(info));
     383             : 
     384           0 :   // check ELF signature
     385           0 :   if (id[0] != 0x7f || id[1] != 'E' || id[2] != 'L' || id[3] != 'F') {
     386           0 :     errs() << "invalid elf signature\n";
     387             :     return false;
     388             :   }
     389           0 : 
     390           0 :   hdr.ElfMach = info.e_machine;
     391             : 
     392             :   return true;
     393           0 : }
     394           0 : 
     395           0 : void PerfJITEventListener::NotifyCode(Expected<llvm::StringRef> &Symbol,
     396             :                                       uint64_t CodeAddr, uint64_t CodeSize) {
     397             :   assert(SuccessfullyInitialized);
     398           0 : 
     399             :   // 0 length functions can't have samples.
     400           0 :   if (CodeSize == 0)
     401             :     return;
     402             : 
     403           0 :   LLVMPerfJitRecordCodeLoad rec;
     404             :   rec.Prefix.Id = JIT_CODE_LOAD;
     405             :   rec.Prefix.TotalSize = sizeof(rec) +        // debug record itself
     406             :                          Symbol->size() + 1 + // symbol name
     407             :                          CodeSize;            // and code
     408           0 :   rec.Prefix.Timestamp = perf_get_timestamp();
     409           0 : 
     410             :   rec.CodeSize = CodeSize;
     411             :   rec.Vma = 0;
     412           0 :   rec.CodeAddr = CodeAddr;
     413           0 :   rec.Pid = Pid;
     414           0 :   rec.Tid = get_threadid();
     415             : 
     416           0 :   // avoid interspersing output
     417             :   MutexGuard Guard(Mutex);
     418           0 : 
     419           0 :   rec.CodeIndex = CodeGeneration++; // under lock!
     420           0 : 
     421           0 :   Dumpstream->write(reinterpret_cast<const char *>(&rec), sizeof(rec));
     422           0 :   Dumpstream->write(Symbol->data(), Symbol->size() + 1);
     423             :   Dumpstream->write(reinterpret_cast<const char *>(CodeAddr), CodeSize);
     424             : }
     425             : 
     426             : void PerfJITEventListener::NotifyDebug(uint64_t CodeAddr,
     427           0 :                                        DILineInfoTable Lines) {
     428             :   assert(SuccessfullyInitialized);
     429           0 : 
     430           0 :   // Didn't get useful debug info.
     431           0 :   if (Lines.empty())
     432             :     return;
     433             : 
     434           0 :   LLVMPerfJitRecordDebugInfo rec;
     435             :   rec.Prefix.Id = JIT_CODE_DEBUG_INFO;
     436             :   rec.Prefix.TotalSize = sizeof(rec); // will be increased further
     437             :   rec.Prefix.Timestamp = perf_get_timestamp();
     438             :   rec.CodeAddr = CodeAddr;
     439           0 :   rec.NrEntry = Lines.size();
     440           0 : 
     441             :   // compute total size size of record (variable due to filenames)
     442             :   DILineInfoTable::iterator Begin = Lines.begin();
     443           0 :   DILineInfoTable::iterator End = Lines.end();
     444           0 :   for (DILineInfoTable::iterator It = Begin; It != End; ++It) {
     445           0 :     DILineInfo &line = It->second;
     446           0 :     rec.Prefix.TotalSize += sizeof(LLVMPerfJitDebugEntry);
     447           0 :     rec.Prefix.TotalSize += line.FileName.size() + 1;
     448             :   }
     449             : 
     450             :   // The debug_entry describes the source line information. It is defined as
     451             :   // follows in order:
     452           0 :   // * uint64_t code_addr: address of function for which the debug information
     453             :   // is generated
     454           0 :   // * uint32_t line     : source file line number (starting at 1)
     455           0 :   // * uint32_t discrim  : column discriminator, 0 is default
     456             :   // * char name[n]      : source file name in ASCII, including null termination
     457             : 
     458             :   // avoid interspersing output
     459             :   MutexGuard Guard(Mutex);
     460             : 
     461             :   Dumpstream->write(reinterpret_cast<const char *>(&rec), sizeof(rec));
     462             : 
     463             :   for (DILineInfoTable::iterator It = Begin; It != End; ++It) {
     464             :     LLVMPerfJitDebugEntry LineInfo;
     465             :     DILineInfo &Line = It->second;
     466             : 
     467             :     LineInfo.Addr = It->first;
     468             :     // The function re-created by perf is preceded by a elf
     469           0 :     // header. Need to adjust for that, otherwise the results are
     470             :     // wrong.
     471           0 :     LineInfo.Addr += 0x40;
     472             :     LineInfo.Lineno = Line.Line;
     473             :     LineInfo.Discrim = Line.Discriminator;
     474             : 
     475           0 :     Dumpstream->write(reinterpret_cast<const char *>(&LineInfo),
     476             :                       sizeof(LineInfo));
     477             :     Dumpstream->write(Line.FileName.c_str(), Line.FileName.size() + 1);
     478             :   }
     479           0 : }
     480           0 : 
     481           0 : // There should be only a single event listener per process, otherwise perf gets
     482             : // confused.
     483             : llvm::ManagedStatic<PerfJITEventListener> PerfListener;
     484           0 : 
     485           0 : } // end anonymous namespace
     486             : 
     487             : namespace llvm {
     488             : JITEventListener *JITEventListener::createPerfJITEventListener() {
     489             :   return &*PerfListener;
     490             : }
     491             : 
     492             : } // namespace llvm
     493             : 
     494             : LLVMJITEventListenerRef LLVMCreatePerfJITEventListener(void)
     495             : {
     496         155 :   return wrap(JITEventListener::createPerfJITEventListener());
     497         155 : }

Generated by: LCOV version 1.13