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