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 PerfEvent::~PerfEvent() {
54 PerfEvent::PerfEvent(PerfEvent
&&Other
)
55 : EventString(std::move(Other
.EventString
)),
56 FullQualifiedEventString(std::move(Other
.FullQualifiedEventString
)),
61 PerfEvent::PerfEvent(StringRef PfmEventString
)
62 : EventString(PfmEventString
.str()), Attr(nullptr) {
65 pfm_perf_encode_arg_t Arg
= {};
66 Attr
= new perf_event_attr();
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
76 errs() << pfm_strerror(Result
) << " - cannot create event " << EventString
80 FullQualifiedEventString
= Fstr
;
86 StringRef
PerfEvent::name() const { return EventString
; }
88 bool PerfEvent::valid() const { return !FullQualifiedEventString
.empty(); }
90 const perf_event_attr
*PerfEvent::attribute() const { return Attr
; }
92 StringRef
PerfEvent::getPfmEventString() const {
93 return FullQualifiedEventString
;
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";
111 assert(FileDescriptor
!= -1 && "Unable to open event");
114 Counter::~Counter() { close(FileDescriptor
); }
116 void Counter::start() { ioctl(FileDescriptor
, PERF_EVENT_IOC_RESET
, 0); }
118 void Counter::stop() { ioctl(FileDescriptor
, PERF_EVENT_IOC_DISABLE
, 0); }
120 int64_t Counter::read() const {
121 auto ValueOrError
= readOrError();
123 if (!ValueOrError
.get().empty())
124 return ValueOrError
.get()[0];
125 errs() << "Counter has no reading\n";
127 errs() << ValueOrError
.takeError() << "\n";
131 llvm::Expected
<llvm::SmallVector
<int64_t, 4>>
132 Counter::readOrError(StringRef
/*unused*/) const {
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
);
143 int Counter::numValues() const { return 1; }
146 Counter::Counter(PerfEvent
&&Event
) : Event(std::move(Event
)) {}
148 Counter::~Counter() = default;
150 void Counter::start() {}
152 void Counter::stop() {}
154 int64_t Counter::read() const { return 42; }
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
);
162 int Counter::numValues() const { return 1; }
167 } // namespace exegesis