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/raw_ostream.h"
13 #include "perfmon/perf_event.h"
14 #include "perfmon/pfmlib.h"
15 #include "perfmon/pfmlib_perf_event.h"
24 static bool isPfmError(int Code
) { return Code
!= PFM_SUCCESS
; }
27 bool pfmInitialize() {
29 return isPfmError(pfm_initialize());
41 PerfEvent::~PerfEvent() {
48 PerfEvent::PerfEvent(PerfEvent
&&Other
)
49 : EventString(std::move(Other
.EventString
)),
50 FullQualifiedEventString(std::move(Other
.FullQualifiedEventString
)),
55 PerfEvent::PerfEvent(llvm::StringRef PfmEventString
)
56 : EventString(PfmEventString
.str()), Attr(nullptr) {
59 pfm_perf_encode_arg_t Arg
= {};
60 Attr
= new perf_event_attr();
63 Arg
.size
= sizeof(pfm_perf_encode_arg_t
);
64 const int Result
= pfm_get_os_event_encoding(EventString
.c_str(), PFM_PLM3
,
65 PFM_OS_PERF_EVENT
, &Arg
);
66 if (isPfmError(Result
)) {
67 // We don't know beforehand which counters are available (e.g. 6 uops ports
68 // on Sandybridge but 8 on Haswell) so we report the missing counter without
70 llvm::errs() << pfm_strerror(Result
) << " - cannot create event "
71 << EventString
<< "\n";
74 FullQualifiedEventString
= Fstr
;
80 llvm::StringRef
PerfEvent::name() const { return EventString
; }
82 bool PerfEvent::valid() const { return !FullQualifiedEventString
.empty(); }
84 const perf_event_attr
*PerfEvent::attribute() const { return Attr
; }
86 llvm::StringRef
PerfEvent::getPfmEventString() const {
87 return FullQualifiedEventString
;
91 Counter::Counter(const PerfEvent
&Event
) {
92 assert(Event
.valid());
93 const pid_t Pid
= 0; // measure current process/thread.
94 const int Cpu
= -1; // measure any processor.
95 const int GroupFd
= -1; // no grouping of counters.
96 const uint32_t Flags
= 0;
97 perf_event_attr AttrCopy
= *Event
.attribute();
98 FileDescriptor
= perf_event_open(&AttrCopy
, Pid
, Cpu
, GroupFd
, Flags
);
99 if (FileDescriptor
== -1) {
100 llvm::errs() << "Unable to open event, make sure your kernel allows user "
101 "space perf monitoring.\nYou may want to try:\n$ sudo sh "
102 "-c 'echo -1 > /proc/sys/kernel/perf_event_paranoid'\n";
104 assert(FileDescriptor
!= -1 && "Unable to open event");
107 Counter::~Counter() { close(FileDescriptor
); }
109 void Counter::start() { ioctl(FileDescriptor
, PERF_EVENT_IOC_RESET
, 0); }
111 void Counter::stop() { ioctl(FileDescriptor
, PERF_EVENT_IOC_DISABLE
, 0); }
113 int64_t Counter::read() const {
115 ssize_t ReadSize
= ::read(FileDescriptor
, &Count
, sizeof(Count
));
116 if (ReadSize
!= sizeof(Count
)) {
118 llvm::errs() << "Failed to read event counter\n";
125 Counter::Counter(const PerfEvent
&Event
) {}
127 Counter::~Counter() = default;
129 void Counter::start() {}
131 void Counter::stop() {}
133 int64_t Counter::read() const { return 42; }
138 } // namespace exegesis