| //===-- PerfHelper.cpp ------------------------------------------*- C++ -*-===// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "PerfHelper.h" | |
| #include "llvm/Config/config.h" | |
| #include "llvm/Support/raw_ostream.h" | |
| #ifdef HAVE_LIBPFM | |
| #include "perfmon/perf_event.h" | |
| #include "perfmon/pfmlib.h" | |
| #include "perfmon/pfmlib_perf_event.h" | |
| #endif | |
| #include <cassert> | |
| namespace exegesis { | |
| namespace pfm { | |
| #ifdef HAVE_LIBPFM | |
| static bool isPfmError(int Code) { return Code != PFM_SUCCESS; } | |
| #endif | |
| bool pfmInitialize() { | |
| #ifdef HAVE_LIBPFM | |
| return isPfmError(pfm_initialize()); | |
| #else | |
| return true; | |
| #endif | |
| } | |
| void pfmTerminate() { | |
| #ifdef HAVE_LIBPFM | |
| pfm_terminate(); | |
| #endif | |
| } | |
| PerfEvent::~PerfEvent() { | |
| #ifdef HAVE_LIBPFM | |
| delete Attr; | |
| ; | |
| #endif | |
| } | |
| PerfEvent::PerfEvent(PerfEvent &&Other) | |
| : EventString(std::move(Other.EventString)), | |
| FullQualifiedEventString(std::move(Other.FullQualifiedEventString)), | |
| Attr(Other.Attr) { | |
| Other.Attr = nullptr; | |
| } | |
| PerfEvent::PerfEvent(llvm::StringRef PfmEventString) | |
| : EventString(PfmEventString.str()), Attr(nullptr) { | |
| #ifdef HAVE_LIBPFM | |
| char *Fstr = nullptr; | |
| pfm_perf_encode_arg_t Arg = {}; | |
| Attr = new perf_event_attr(); | |
| Arg.attr = Attr; | |
| Arg.fstr = &Fstr; | |
| Arg.size = sizeof(pfm_perf_encode_arg_t); | |
| const int Result = pfm_get_os_event_encoding(EventString.c_str(), PFM_PLM3, | |
| PFM_OS_PERF_EVENT, &Arg); | |
| if (isPfmError(Result)) { | |
| // We don't know beforehand which counters are available (e.g. 6 uops ports | |
| // on Sandybridge but 8 on Haswell) so we report the missing counter without | |
| // crashing. | |
| llvm::errs() << pfm_strerror(Result) << " - cannot create event " | |
| << EventString << "\n"; | |
| } | |
| if (Fstr) { | |
| FullQualifiedEventString = Fstr; | |
| free(Fstr); | |
| } | |
| #endif | |
| } | |
| llvm::StringRef PerfEvent::name() const { return EventString; } | |
| bool PerfEvent::valid() const { return !FullQualifiedEventString.empty(); } | |
| const perf_event_attr *PerfEvent::attribute() const { return Attr; } | |
| llvm::StringRef PerfEvent::getPfmEventString() const { | |
| return FullQualifiedEventString; | |
| } | |
| #ifdef HAVE_LIBPFM | |
| Counter::Counter(const PerfEvent &Event) { | |
| assert(Event.valid()); | |
| const pid_t Pid = 0; // measure current process/thread. | |
| const int Cpu = -1; // measure any processor. | |
| const int GroupFd = -1; // no grouping of counters. | |
| const uint32_t Flags = 0; | |
| perf_event_attr AttrCopy = *Event.attribute(); | |
| FileDescriptor = perf_event_open(&AttrCopy, Pid, Cpu, GroupFd, Flags); | |
| if (FileDescriptor == -1) { | |
| llvm::errs() << "Unable to open event, make sure your kernel allows user " | |
| "space perf monitoring.\nYou may want to try:\n$ sudo sh " | |
| "-c 'echo -1 > /proc/sys/kernel/perf_event_paranoid'\n"; | |
| } | |
| assert(FileDescriptor != -1 && "Unable to open event"); | |
| } | |
| Counter::~Counter() { close(FileDescriptor); } | |
| void Counter::start() { ioctl(FileDescriptor, PERF_EVENT_IOC_RESET, 0); } | |
| void Counter::stop() { ioctl(FileDescriptor, PERF_EVENT_IOC_DISABLE, 0); } | |
| int64_t Counter::read() const { | |
| int64_t Count = 0; | |
| ssize_t ReadSize = ::read(FileDescriptor, &Count, sizeof(Count)); | |
| if (ReadSize != sizeof(Count)) { | |
| Count = -1; | |
| llvm::errs() << "Failed to read event counter\n"; | |
| } | |
| return Count; | |
| } | |
| #else | |
| Counter::Counter(const PerfEvent &Event) {} | |
| Counter::~Counter() = default; | |
| void Counter::start() {} | |
| void Counter::stop() {} | |
| int64_t Counter::read() const { return 42; } | |
| #endif | |
| } // namespace pfm | |
| } // namespace exegesis |