1 //===-- PerfHelper.cpp ------------------------------------------*- C++ -*-===//
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
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"
15 #include <perfmon/perf_event.h>
16 #include <perfmon/pfmlib.h>
17 #include <perfmon/pfmlib_perf_event.h>
22 #include <errno.h> // for erno
23 #include <string.h> // for strerror()
30 static bool isPfmError(int Code
) { return Code
!= PFM_SUCCESS
; }
33 bool pfmInitialize() {
35 return isPfmError(pfm_initialize());
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() {
61 PerfEvent::PerfEvent(PerfEvent
&&Other
)
62 : EventString(std::move(Other
.EventString
)),
63 FullQualifiedEventString(std::move(Other
.FullQualifiedEventString
)),
68 PerfEvent::PerfEvent(StringRef PfmEventString
)
69 : EventString(PfmEventString
.str()), Attr(nullptr) {
70 if (PfmEventString
!= DummyEventString
)
71 initRealEvent(PfmEventString
);
73 FullQualifiedEventString
= PfmEventString
;
76 void PerfEvent::initRealEvent(StringRef PfmEventString
) {
79 pfm_perf_encode_arg_t Arg
= {};
80 Attr
= new perf_event_attr();
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
90 errs() << pfm_strerror(Result
) << " - cannot create event " << EventString
94 FullQualifiedEventString
= Fstr
;
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());
116 void ConfiguredEvent::initRealEvent(const pid_t ProcessID
, const int GroupFD
) {
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 {
136 ssize_t ReadSize
= ::read(FileDescriptor
, &Count
, sizeof(Count
));
138 if (ReadSize
!= sizeof(Count
))
139 return make_error
<StringError
>("Failed to read event counter",
142 SmallVector
<int64_t, 1> Result
;
143 Result
.push_back(Count
);
147 ConfiguredEvent::~ConfiguredEvent() { close(FileDescriptor
); }
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
,
162 : EventCounter(std::move(E
)) {
163 IsDummyEvent
= EventCounter
.isDummyEvent();
165 for (auto &&ValEvent
: ValEvents
)
166 ValidationEventCounters
.emplace_back(std::move(ValEvent
));
169 initRealEvent(ProcessID
);
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() {
182 ioctl(getFileDescriptor(), PERF_EVENT_IOC_RESET
, PERF_IOC_FLAG_GROUP
);
185 void CounterGroup::stop() {
187 ioctl(getFileDescriptor(), PERF_EVENT_IOC_DISABLE
, PERF_IOC_FLAG_GROUP
);
190 Expected
<SmallVector
<int64_t, 4>>
191 CounterGroup::readOrError(StringRef FunctionBytes
) const {
193 return EventCounter
.readOrError(FunctionBytes
);
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());
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]);
217 int CounterGroup::numValues() const { return 1; }
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 {
229 SmallVector
<int64_t, 4> Result
;
230 Result
.push_back(42);
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; }
246 } // namespace exegesis