LLVM  8.0.1
PerfJITEventListener.cpp
Go to the documentation of this file.
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"
23 #include "llvm/Object/ObjectFile.h"
24 #include "llvm/Object/SymbolSize.h"
25 #include "llvm/Support/Debug.h"
26 #include "llvm/Support/Errno.h"
29 #include "llvm/Support/Mutex.h"
31 #include "llvm/Support/Path.h"
32 #include "llvm/Support/Process.h"
33 #include "llvm/Support/Threading.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;
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  ~PerfJITEventListener() {
65  if (MarkerAddr)
66  CloseMarker();
67  }
68 
69  void notifyObjectLoaded(ObjectKey K, const ObjectFile &Obj,
70  const RuntimeDyld::LoadedObjectInfo &L) override;
71  void notifyFreeingObject(ObjectKey K) override;
72 
73 private:
74  bool InitDebuggingDir();
75  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
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 
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 
173  ret = clock_gettime(CLOCK_MONOTONIC, &ts);
174  if (ret)
175  return 0;
176 
177  return timespec_to_ns(&ts);
178 }
179 
180 PerfJITEventListener::PerfJITEventListener() : Pid(::getpid()) {
181  // check if clock-source is supported
182  if (!perf_get_timestamp()) {
183  errs() << "kernel does not support CLOCK_MONOTONIC\n";
184  return;
185  }
186 
187  if (!InitDebuggingDir()) {
188  errs() << "could not initialize debugging directory\n";
189  return;
190  }
191 
192  std::string Filename;
193  raw_string_ostream FilenameBuf(Filename);
194  FilenameBuf << JitPath << "/jit-" << Pid << ".dump";
195 
196  // Need to open ourselves, because we need to hand the FD to OpenMarker() and
197  // raw_fd_ostream doesn't expose the FD.
199  if (auto EC =
200  openFileForReadWrite(FilenameBuf.str(), DumpFd,
202  errs() << "could not open JIT dump file " << FilenameBuf.str() << ": "
203  << EC.message() << "\n";
204  return;
205  }
206 
207  Dumpstream = make_unique<raw_fd_ostream>(DumpFd, true);
208 
209  LLVMPerfJitHeader Header = {0};
210  if (!FillMachine(Header))
211  return;
212 
213  // signal this process emits JIT information
214  if (!OpenMarker())
215  return;
216 
217  // emit dumpstream header
218  Header.Magic = LLVM_PERF_JIT_MAGIC;
219  Header.Version = LLVM_PERF_JIT_VERSION;
220  Header.TotalSize = sizeof(Header);
221  Header.Pid = Pid;
222  Header.Timestamp = perf_get_timestamp();
223  Dumpstream->write(reinterpret_cast<const char *>(&Header), sizeof(Header));
224 
225  // Everything initialized, can do profiling now.
226  if (!Dumpstream->has_error())
227  SuccessfullyInitialized = true;
228 }
229 
230 void PerfJITEventListener::notifyObjectLoaded(
231  ObjectKey K, const ObjectFile &Obj,
233 
234  if (!SuccessfullyInitialized)
235  return;
236 
237  OwningBinary<ObjectFile> DebugObjOwner = L.getObjectForDebug(Obj);
238  const ObjectFile &DebugObj = *DebugObjOwner.getBinary();
239 
240  // Get the address of the object image for use as a unique identifier
241  std::unique_ptr<DIContext> Context = DWARFContext::create(DebugObj);
242 
243  // Use symbol info to iterate over functions in the object.
244  for (const std::pair<SymbolRef, uint64_t> &P : computeSymbolSizes(DebugObj)) {
245  SymbolRef Sym = P.first;
246  std::string SourceFileName;
247 
248  Expected<SymbolRef::Type> SymTypeOrErr = Sym.getType();
249  if (!SymTypeOrErr) {
250  // There's not much we can with errors here
251  consumeError(SymTypeOrErr.takeError());
252  continue;
253  }
254  SymbolRef::Type SymType = *SymTypeOrErr;
255  if (SymType != SymbolRef::ST_Function)
256  continue;
257 
259  if (!Name) {
260  consumeError(Name.takeError());
261  continue;
262  }
263 
264  Expected<uint64_t> AddrOrErr = Sym.getAddress();
265  if (!AddrOrErr) {
266  consumeError(AddrOrErr.takeError());
267  continue;
268  }
269  uint64_t Addr = *AddrOrErr;
270  uint64_t Size = P.second;
271 
272  // According to spec debugging info has to come before loading the
273  // corresonding code load.
274  DILineInfoTable Lines = Context->getLineInfoForAddressRange(
275  Addr, Size, FileLineInfoKind::AbsoluteFilePath);
276 
277  NotifyDebug(Addr, Lines);
278  NotifyCode(Name, Addr, Size);
279  }
280 
281  Dumpstream->flush();
282 }
283 
284 void PerfJITEventListener::notifyFreeingObject(ObjectKey K) {
285  // perf currently doesn't have an interface for unloading. But munmap()ing the
286  // code section does, so that's ok.
287 }
288 
289 bool PerfJITEventListener::InitDebuggingDir() {
290  time_t Time;
291  struct tm LocalTime;
292  char TimeBuffer[sizeof("YYYYMMDD")];
293  SmallString<64> Path;
294 
295  // search for location to dump data to
296  if (const char *BaseDir = getenv("JITDUMPDIR"))
297  Path.append(BaseDir);
298  else if (!sys::path::home_directory(Path))
299  Path = ".";
300 
301  // create debug directory
302  Path += "/.debug/jit/";
303  if (auto EC = sys::fs::create_directories(Path)) {
304  errs() << "could not create jit cache directory " << Path << ": "
305  << EC.message() << "\n";
306  return false;
307  }
308 
309  // create unique directory for dump data related to this process
310  time(&Time);
311  localtime_r(&Time, &LocalTime);
312  strftime(TimeBuffer, sizeof(TimeBuffer), "%Y%m%d", &LocalTime);
313  Path += JIT_LANG "-jit-";
314  Path += TimeBuffer;
315 
316  SmallString<128> UniqueDebugDir;
317 
319  if (auto EC = createUniqueDirectory(Path, UniqueDebugDir)) {
320  errs() << "could not create unique jit cache directory " << UniqueDebugDir
321  << ": " << EC.message() << "\n";
322  return false;
323  }
324 
325  JitPath = UniqueDebugDir.str();
326 
327  return true;
328 }
329 
330 bool PerfJITEventListener::OpenMarker() {
331  // We mmap the jitdump to create an MMAP RECORD in perf.data file. The mmap
332  // is captured either live (perf record running when we mmap) or in deferred
333  // mode, via /proc/PID/maps. The MMAP record is used as a marker of a jitdump
334  // file for more meta data info about the jitted code. Perf report/annotate
335  // detect this special filename and process the jitdump file.
336  //
337  // Mapping must be PROT_EXEC to ensure it is captured by perf record
338  // even when not using -d option.
339  MarkerAddr = ::mmap(NULL, sys::Process::getPageSize(), PROT_READ | PROT_EXEC,
340  MAP_PRIVATE, DumpFd, 0);
341 
342  if (MarkerAddr == MAP_FAILED) {
343  errs() << "could not mmap JIT marker\n";
344  return false;
345  }
346  return true;
347 }
348 
349 void PerfJITEventListener::CloseMarker() {
350  if (!MarkerAddr)
351  return;
352 
353  munmap(MarkerAddr, sys::Process::getPageSize());
354  MarkerAddr = nullptr;
355 }
356 
357 bool PerfJITEventListener::FillMachine(LLVMPerfJitHeader &hdr) {
358  char id[16];
359  struct {
360  uint16_t e_type;
361  uint16_t e_machine;
362  } info;
363 
364  size_t RequiredMemory = sizeof(id) + sizeof(info);
365 
367  MemoryBuffer::getFileSlice("/proc/self/exe",
368  RequiredMemory,
369  0);
370 
371  // This'll not guarantee that enough data was actually read from the
372  // underlying file. Instead the trailing part of the buffer would be
373  // zeroed. Given the ELF signature check below that seems ok though,
374  // it's unlikely that the file ends just after that, and the
375  // consequence would just be that perf wouldn't recognize the
376  // signature.
377  if (auto EC = MB.getError()) {
378  errs() << "could not open /proc/self/exe: " << EC.message() << "\n";
379  return false;
380  }
381 
382  memcpy(&id, (*MB)->getBufferStart(), sizeof(id));
383  memcpy(&info, (*MB)->getBufferStart() + sizeof(id), sizeof(info));
384 
385  // check ELF signature
386  if (id[0] != 0x7f || id[1] != 'E' || id[2] != 'L' || id[3] != 'F') {
387  errs() << "invalid elf signature\n";
388  return false;
389  }
390 
391  hdr.ElfMach = info.e_machine;
392 
393  return true;
394 }
395 
396 void PerfJITEventListener::NotifyCode(Expected<llvm::StringRef> &Symbol,
397  uint64_t CodeAddr, uint64_t CodeSize) {
398  assert(SuccessfullyInitialized);
399 
400  // 0 length functions can't have samples.
401  if (CodeSize == 0)
402  return;
403 
404  LLVMPerfJitRecordCodeLoad rec;
405  rec.Prefix.Id = JIT_CODE_LOAD;
406  rec.Prefix.TotalSize = sizeof(rec) + // debug record itself
407  Symbol->size() + 1 + // symbol name
408  CodeSize; // and code
409  rec.Prefix.Timestamp = perf_get_timestamp();
410 
411  rec.CodeSize = CodeSize;
412  rec.Vma = 0;
413  rec.CodeAddr = CodeAddr;
414  rec.Pid = Pid;
415  rec.Tid = get_threadid();
416 
417  // avoid interspersing output
418  MutexGuard Guard(Mutex);
419 
420  rec.CodeIndex = CodeGeneration++; // under lock!
421 
422  Dumpstream->write(reinterpret_cast<const char *>(&rec), sizeof(rec));
423  Dumpstream->write(Symbol->data(), Symbol->size() + 1);
424  Dumpstream->write(reinterpret_cast<const char *>(CodeAddr), CodeSize);
425 }
426 
427 void PerfJITEventListener::NotifyDebug(uint64_t CodeAddr,
428  DILineInfoTable Lines) {
429  assert(SuccessfullyInitialized);
430 
431  // Didn't get useful debug info.
432  if (Lines.empty())
433  return;
434 
435  LLVMPerfJitRecordDebugInfo rec;
436  rec.Prefix.Id = JIT_CODE_DEBUG_INFO;
437  rec.Prefix.TotalSize = sizeof(rec); // will be increased further
438  rec.Prefix.Timestamp = perf_get_timestamp();
439  rec.CodeAddr = CodeAddr;
440  rec.NrEntry = Lines.size();
441 
442  // compute total size size of record (variable due to filenames)
443  DILineInfoTable::iterator Begin = Lines.begin();
444  DILineInfoTable::iterator End = Lines.end();
445  for (DILineInfoTable::iterator It = Begin; It != End; ++It) {
446  DILineInfo &line = It->second;
447  rec.Prefix.TotalSize += sizeof(LLVMPerfJitDebugEntry);
448  rec.Prefix.TotalSize += line.FileName.size() + 1;
449  }
450 
451  // The debug_entry describes the source line information. It is defined as
452  // follows in order:
453  // * uint64_t code_addr: address of function for which the debug information
454  // is generated
455  // * uint32_t line : source file line number (starting at 1)
456  // * uint32_t discrim : column discriminator, 0 is default
457  // * char name[n] : source file name in ASCII, including null termination
458 
459  // avoid interspersing output
460  MutexGuard Guard(Mutex);
461 
462  Dumpstream->write(reinterpret_cast<const char *>(&rec), sizeof(rec));
463 
464  for (DILineInfoTable::iterator It = Begin; It != End; ++It) {
465  LLVMPerfJitDebugEntry LineInfo;
466  DILineInfo &Line = It->second;
467 
468  LineInfo.Addr = It->first;
469  // The function re-created by perf is preceded by a elf
470  // header. Need to adjust for that, otherwise the results are
471  // wrong.
472  LineInfo.Addr += 0x40;
473  LineInfo.Lineno = Line.Line;
474  LineInfo.Discrim = Line.Discriminator;
475 
476  Dumpstream->write(reinterpret_cast<const char *>(&LineInfo),
477  sizeof(LineInfo));
478  Dumpstream->write(Line.FileName.c_str(), Line.FileName.size() + 1);
479  }
480 }
481 
482 // There should be only a single event listener per process, otherwise perf gets
483 // confused.
485 
486 } // end anonymous namespace
487 
488 namespace llvm {
490  return &*PerfListener;
491 }
492 
493 } // namespace llvm
494 
496 {
498 }
Information about the loaded object.
Definition: RuntimeDyld.h:69
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:914
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:992
Represents either an error or a value T.
Definition: ErrorOr.h:57
uint32_t Discriminator
Definition: DIContext.h:40
raw_ostream & errs()
This returns a reference to a raw_ostream for standard error.
std::string FileName
Definition: DIContext.h:32
LLVMContext & Context
This class represents lattice values for constants.
Definition: AllocatorList.h:24
Expected< StringRef > getName() const
Definition: ObjectFile.h:359
JITEventListener - Abstract interface for use by the JIT to notify clients about significant events d...
DILineInfoSpecifier::FileLineInfoKind FileLineInfoKind
This class is the base class for all object file types.
Definition: ObjectFile.h:202
Error takeError()
Take ownership of the stored error.
Definition: Error.h:553
A format-neutral container for source line information.
Definition: DIContext.h:31
LLVMPerfJitRecordType
SmartMutex< false > Mutex
Mutex - A standard, always enforced mutex.
Definition: Mutex.h:139
amdgpu Simplify well known AMD library false Value Value const Twine & Name
Tagged union holding either a T or a Error.
Definition: CachePruning.h:23
#define LLVM_PERF_JIT_MAGIC
#define JIT_LANG
StringRef str() const
Explicit conversion to StringRef.
Definition: SmallString.h:267
CD_CreateNew - When opening a file:
Definition: FileSystem.h:726
void append(in_iter S, in_iter E)
Append from an iterator pair.
Definition: SmallString.h:75
Instances of this class acquire a given Mutex Lock when constructed and hold that lock until destruct...
Definition: MutexGuard.h:27
#define P(N)
LLVM_ATTRIBUTE_ALWAYS_INLINE iterator begin()
Definition: SmallVector.h:129
std::error_code getError() const
Definition: ErrorOr.h:160
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:951
Expected< uint64_t > getAddress() const
Returns the symbol virtual address (i.e.
Definition: ObjectFile.h:363
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:982
size_t size() const
Definition: SmallVector.h:53
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:499
static unsigned getPageSize()
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:42
virtual object::OwningBinary< object::ObjectFile > getObjectForDebug(const object::ObjectFile &Obj) const =0
uint32_t Line
Definition: DIContext.h:35
Expected< SymbolRef::Type > getType() const
Definition: ObjectFile.h:383
This is a &#39;vector&#39; (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:847
static JITEventListener * createPerfJITEventListener()
std::error_code createUniqueDirectory(const Twine &Prefix, SmallVectorImpl< char > &ResultPath)
Definition: Path.cpp:831
std::vector< std::pair< SymbolRef, uint64_t > > computeSymbolSizes(const ObjectFile &O)
Definition: SymbolSize.cpp:41
typename SuperClass::iterator iterator
Definition: SmallVector.h:327
This is a value type class that represents a single symbol in the list of symbols in the object file...
Definition: ObjectFile.h:141
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.
LLVM_ATTRIBUTE_ALWAYS_INLINE iterator end()
Definition: SmallVector.h:133
Provides a library for accessing information about this process and other processes on the operating ...
LLVMAttributeRef wrap(Attribute Attr)
Definition: Attributes.h:190
LLVM_NODISCARD bool empty() const
Definition: SmallVector.h:56
#define LLVM_PERF_JIT_VERSION
uint32_t Size
Definition: Profile.cpp:47
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:483
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:61
const uint64_t Version
Definition: InstrProf.h:895