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