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