PerfHelper.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. //===-- PerfHelper.cpp ------------------------------------------*- C++ -*-===//
  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. #include "PerfHelper.h"
  9. #include "llvm/Config/config.h"
  10. #include "llvm/Support/Errc.h"
  11. #include "llvm/Support/Error.h"
  12. #include "llvm/Support/raw_ostream.h"
  13. #ifdef HAVE_LIBPFM
  14. #error #include <perfmon/perf_event.h>
  15. #error #include <perfmon/pfmlib.h>
  16. #error #include <perfmon/pfmlib_perf_event.h>
  17. #endif
  18. #include <cassert>
  19. #include <cstddef>
  20. #include <errno.h> // for erno
  21. #include <string.h> // for strerror()
  22. namespace llvm {
  23. namespace exegesis {
  24. namespace pfm {
  25. #ifdef HAVE_LIBPFM
  26. static bool isPfmError(int Code) { return Code != PFM_SUCCESS; }
  27. #endif
  28. bool pfmInitialize() {
  29. #ifdef HAVE_LIBPFM
  30. return isPfmError(pfm_initialize());
  31. #else
  32. return true;
  33. #endif
  34. }
  35. void pfmTerminate() {
  36. #ifdef HAVE_LIBPFM
  37. pfm_terminate();
  38. #endif
  39. }
  40. PerfEvent::~PerfEvent() {
  41. #ifdef HAVE_LIBPFM
  42. delete Attr;
  43. ;
  44. #endif
  45. }
  46. PerfEvent::PerfEvent(PerfEvent &&Other)
  47. : EventString(std::move(Other.EventString)),
  48. FullQualifiedEventString(std::move(Other.FullQualifiedEventString)),
  49. Attr(Other.Attr) {
  50. Other.Attr = nullptr;
  51. }
  52. PerfEvent::PerfEvent(StringRef PfmEventString)
  53. : EventString(PfmEventString.str()), Attr(nullptr) {
  54. #ifdef HAVE_LIBPFM
  55. char *Fstr = nullptr;
  56. pfm_perf_encode_arg_t Arg = {};
  57. Attr = new perf_event_attr();
  58. Arg.attr = Attr;
  59. Arg.fstr = &Fstr;
  60. Arg.size = sizeof(pfm_perf_encode_arg_t);
  61. const int Result = pfm_get_os_event_encoding(EventString.c_str(), PFM_PLM3,
  62. PFM_OS_PERF_EVENT, &Arg);
  63. if (isPfmError(Result)) {
  64. // We don't know beforehand which counters are available (e.g. 6 uops ports
  65. // on Sandybridge but 8 on Haswell) so we report the missing counter without
  66. // crashing.
  67. errs() << pfm_strerror(Result) << " - cannot create event " << EventString
  68. << "\n";
  69. }
  70. if (Fstr) {
  71. FullQualifiedEventString = Fstr;
  72. free(Fstr);
  73. }
  74. #endif
  75. }
  76. StringRef PerfEvent::name() const { return EventString; }
  77. bool PerfEvent::valid() const { return !FullQualifiedEventString.empty(); }
  78. const perf_event_attr *PerfEvent::attribute() const { return Attr; }
  79. StringRef PerfEvent::getPfmEventString() const {
  80. return FullQualifiedEventString;
  81. }
  82. #ifdef HAVE_LIBPFM
  83. Counter::Counter(PerfEvent &&E) : Event(std::move(E)){
  84. assert(Event.valid());
  85. const pid_t Pid = 0; // measure current process/thread.
  86. const int Cpu = -1; // measure any processor.
  87. const int GroupFd = -1; // no grouping of counters.
  88. const uint32_t Flags = 0;
  89. perf_event_attr AttrCopy = *Event.attribute();
  90. FileDescriptor = perf_event_open(&AttrCopy, Pid, Cpu, GroupFd, Flags);
  91. if (FileDescriptor == -1) {
  92. errs() << "Unable to open event. ERRNO: " << strerror(errno)
  93. << ". Make sure your kernel allows user "
  94. "space perf monitoring.\nYou may want to try:\n$ sudo sh "
  95. "-c 'echo -1 > /proc/sys/kernel/perf_event_paranoid'\n";
  96. }
  97. assert(FileDescriptor != -1 && "Unable to open event");
  98. }
  99. Counter::~Counter() { close(FileDescriptor); }
  100. void Counter::start() { ioctl(FileDescriptor, PERF_EVENT_IOC_RESET, 0); }
  101. void Counter::stop() { ioctl(FileDescriptor, PERF_EVENT_IOC_DISABLE, 0); }
  102. int64_t Counter::read() const {
  103. auto ValueOrError = readOrError();
  104. if (ValueOrError) {
  105. if (!ValueOrError.get().empty())
  106. return ValueOrError.get()[0];
  107. errs() << "Counter has no reading\n";
  108. } else
  109. errs() << ValueOrError.takeError() << "\n";
  110. return -1;
  111. }
  112. llvm::Expected<llvm::SmallVector<int64_t, 4>>
  113. Counter::readOrError(StringRef /*unused*/) const {
  114. int64_t Count = 0;
  115. ssize_t ReadSize = ::read(FileDescriptor, &Count, sizeof(Count));
  116. if (ReadSize != sizeof(Count))
  117. return llvm::make_error<llvm::StringError>("Failed to read event counter",
  118. llvm::errc::io_error);
  119. llvm::SmallVector<int64_t, 4> Result;
  120. Result.push_back(Count);
  121. return Result;
  122. }
  123. int Counter::numValues() const { return 1; }
  124. #else
  125. Counter::Counter(PerfEvent &&Event) : Event(std::move(Event)) {}
  126. Counter::~Counter() = default;
  127. void Counter::start() {}
  128. void Counter::stop() {}
  129. int64_t Counter::read() const { return 42; }
  130. llvm::Expected<llvm::SmallVector<int64_t, 4>>
  131. Counter::readOrError(StringRef /*unused*/) const {
  132. return llvm::make_error<llvm::StringError>("Not implemented",
  133. llvm::errc::io_error);
  134. }
  135. int Counter::numValues() const { return 1; }
  136. #endif
  137. } // namespace pfm
  138. } // namespace exegesis
  139. } // namespace llvm