//===-- 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 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