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 if (!ValueOrError.get().empty()) 124 return ValueOrError.get()[0]; 125 errs() << "Counter has no reading\n"; 126 } else 127 errs() << ValueOrError.takeError() << "\n"; 128 return -1; 129 } 130 131 llvm::Expected<llvm::SmallVector<int64_t, 4>> 132 Counter::readOrError(StringRef /*unused*/) const { 133 int64_t Count = 0; 134 ssize_t ReadSize = ::read(FileDescriptor, &Count, sizeof(Count)); 135 if (ReadSize != sizeof(Count)) 136 return llvm::make_error<llvm::StringError>("Failed to read event counter", 137 llvm::errc::io_error); 138 llvm::SmallVector<int64_t, 4> Result; 139 Result.push_back(Count); 140 return Result; 141 } 142 143 int Counter::numValues() const { return 1; } 144 #else 145 146 Counter::Counter(PerfEvent &&Event) : Event(std::move(Event)) {} 147 148 Counter::~Counter() = default; 149 150 void Counter::start() {} 151 152 void Counter::stop() {} 153 154 int64_t Counter::read() const { return 42; } 155 156 llvm::Expected<llvm::SmallVector<int64_t, 4>> 157 Counter::readOrError(StringRef /*unused*/) const { 158 return llvm::make_error<llvm::StringError>("Not implemented", 159 llvm::errc::io_error); 160 } 161 162 int Counter::numValues() const { return 1; } 163 164 #endif 165 166 } // namespace pfm 167 } // namespace exegesis 168 } // namespace llvm 169