Allow SymbolUserOpInterface operators to be used in RemoveDeadValues Pass (#117405)
[llvm-project.git] / llvm / tools / llvm-exegesis / lib / PerfHelper.cpp
blob3f3288ceb1e4f09884fc701e764a0127df4b0b06
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 //===----------------------------------------------------------------------===//
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
20 #include <cassert>
21 #include <cstddef>
22 #include <errno.h> // for erno
23 #include <string.h> // for strerror()
25 namespace llvm {
26 namespace exegesis {
27 namespace pfm {
29 #ifdef HAVE_LIBPFM
30 static bool isPfmError(int Code) { return Code != PFM_SUCCESS; }
31 #endif
33 bool pfmInitialize() {
34 #ifdef HAVE_LIBPFM
35 return isPfmError(pfm_initialize());
36 #else
37 return true;
38 #endif
41 void pfmTerminate() {
42 #ifdef HAVE_LIBPFM
43 pfm_terminate();
44 #endif
47 // Performance counters may be unavailable for a number of reasons (such as
48 // kernel.perf_event_paranoid restriction or CPU being unknown to libpfm).
50 // Dummy event can be specified to skip interaction with real performance
51 // counters while still passing control to the generated code snippet.
52 const char *const PerfEvent::DummyEventString = "not-really-an-event";
54 PerfEvent::~PerfEvent() {
55 #ifdef HAVE_LIBPFM
56 delete Attr;
58 #endif
61 PerfEvent::PerfEvent(PerfEvent &&Other)
62 : EventString(std::move(Other.EventString)),
63 FullQualifiedEventString(std::move(Other.FullQualifiedEventString)),
64 Attr(Other.Attr) {
65 Other.Attr = nullptr;
68 PerfEvent::PerfEvent(StringRef PfmEventString)
69 : EventString(PfmEventString.str()), Attr(nullptr) {
70 if (PfmEventString != DummyEventString)
71 initRealEvent(PfmEventString);
72 else
73 FullQualifiedEventString = PfmEventString;
76 void PerfEvent::initRealEvent(StringRef PfmEventString) {
77 #ifdef HAVE_LIBPFM
78 char *Fstr = nullptr;
79 pfm_perf_encode_arg_t Arg = {};
80 Attr = new perf_event_attr();
81 Arg.attr = Attr;
82 Arg.fstr = &Fstr;
83 Arg.size = sizeof(pfm_perf_encode_arg_t);
84 const int Result = pfm_get_os_event_encoding(EventString.c_str(), PFM_PLM3,
85 PFM_OS_PERF_EVENT, &Arg);
86 if (isPfmError(Result)) {
87 // We don't know beforehand which counters are available (e.g. 6 uops ports
88 // on Sandybridge but 8 on Haswell) so we report the missing counter without
89 // crashing.
90 errs() << pfm_strerror(Result) << " - cannot create event " << EventString
91 << "\n";
93 if (Fstr) {
94 FullQualifiedEventString = Fstr;
95 free(Fstr);
97 #endif
100 StringRef PerfEvent::name() const { return EventString; }
102 bool PerfEvent::valid() const { return !FullQualifiedEventString.empty(); }
104 const perf_event_attr *PerfEvent::attribute() const { return Attr; }
106 StringRef PerfEvent::getPfmEventString() const {
107 return FullQualifiedEventString;
110 ConfiguredEvent::ConfiguredEvent(PerfEvent &&EventToConfigure)
111 : Event(std::move(EventToConfigure)) {
112 assert(Event.valid());
115 #ifdef HAVE_LIBPFM
116 void ConfiguredEvent::initRealEvent(const pid_t ProcessID, const int GroupFD) {
117 const int CPU = -1;
118 const uint32_t Flags = 0;
119 perf_event_attr AttrCopy = *Event.attribute();
120 FileDescriptor = perf_event_open(&AttrCopy, ProcessID, CPU, GroupFD, Flags);
121 if (FileDescriptor == -1) {
122 errs() << "Unable to open event. ERRNO: " << strerror(errno)
123 << ". Make sure your kernel allows user "
124 "space perf monitoring.\nYou may want to try:\n$ sudo sh "
125 "-c 'echo -1 > /proc/sys/kernel/perf_event_paranoid'.\n"
126 << "If you are debugging and just want to execute the snippet "
127 "without actually reading performance counters, "
128 "pass --use-dummy-perf-counters command line option.\n";
130 assert(FileDescriptor != -1 && "Unable to open event");
133 Expected<SmallVector<int64_t>>
134 ConfiguredEvent::readOrError(StringRef /*unused*/) const {
135 int64_t Count = 0;
136 ssize_t ReadSize = ::read(FileDescriptor, &Count, sizeof(Count));
138 if (ReadSize != sizeof(Count))
139 return make_error<StringError>("Failed to read event counter",
140 errc::io_error);
142 SmallVector<int64_t, 1> Result;
143 Result.push_back(Count);
144 return Result;
147 ConfiguredEvent::~ConfiguredEvent() { close(FileDescriptor); }
148 #else
149 void ConfiguredEvent::initRealEvent(pid_t ProcessID, const int GroupFD) {}
151 Expected<SmallVector<int64_t>>
152 ConfiguredEvent::readOrError(StringRef /*unused*/) const {
153 return make_error<StringError>("Not implemented",
154 errc::function_not_supported);
157 ConfiguredEvent::~ConfiguredEvent() = default;
158 #endif // HAVE_LIBPFM
160 CounterGroup::CounterGroup(PerfEvent &&E, std::vector<PerfEvent> &&ValEvents,
161 pid_t ProcessID)
162 : EventCounter(std::move(E)) {
163 IsDummyEvent = EventCounter.isDummyEvent();
165 for (auto &&ValEvent : ValEvents)
166 ValidationEventCounters.emplace_back(std::move(ValEvent));
168 if (!IsDummyEvent)
169 initRealEvent(ProcessID);
172 #ifdef HAVE_LIBPFM
173 void CounterGroup::initRealEvent(pid_t ProcessID) {
174 EventCounter.initRealEvent(ProcessID);
176 for (auto &ValCounter : ValidationEventCounters)
177 ValCounter.initRealEvent(ProcessID, getFileDescriptor());
180 void CounterGroup::start() {
181 if (!IsDummyEvent)
182 ioctl(getFileDescriptor(), PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP);
185 void CounterGroup::stop() {
186 if (!IsDummyEvent)
187 ioctl(getFileDescriptor(), PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP);
190 Expected<SmallVector<int64_t, 4>>
191 CounterGroup::readOrError(StringRef FunctionBytes) const {
192 if (!IsDummyEvent)
193 return EventCounter.readOrError(FunctionBytes);
194 else
195 return SmallVector<int64_t, 1>(1, 42);
198 Expected<SmallVector<int64_t>>
199 CounterGroup::readValidationCountersOrError() const {
200 SmallVector<int64_t, 4> Result;
201 for (const auto &ValCounter : ValidationEventCounters) {
202 Expected<SmallVector<int64_t>> ValueOrError =
203 ValCounter.readOrError(StringRef());
205 if (!ValueOrError)
206 return ValueOrError.takeError();
208 // Reading a validation counter will only return a single value, so it is
209 // safe to only append the first value here. Also assert that this is true.
210 assert(ValueOrError->size() == 1 &&
211 "Validation counters should only return a single value");
212 Result.push_back((*ValueOrError)[0]);
214 return Result;
217 int CounterGroup::numValues() const { return 1; }
218 #else
220 void CounterGroup::initRealEvent(pid_t ProcessID) {}
222 void CounterGroup::start() {}
224 void CounterGroup::stop() {}
226 Expected<SmallVector<int64_t, 4>>
227 CounterGroup::readOrError(StringRef /*unused*/) const {
228 if (IsDummyEvent) {
229 SmallVector<int64_t, 4> Result;
230 Result.push_back(42);
231 return Result;
233 return make_error<StringError>("Not implemented", errc::io_error);
236 Expected<SmallVector<int64_t>>
237 CounterGroup::readValidationCountersOrError() const {
238 return SmallVector<int64_t>(0);
241 int CounterGroup::numValues() const { return 1; }
243 #endif
245 } // namespace pfm
246 } // namespace exegesis
247 } // namespace llvm