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