1 //===-- PerfHelper.cpp ------------------------------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "PerfHelper.h"
11 #include "llvm/Config/config.h"
12 #include "llvm/Support/raw_ostream.h"
13 #ifdef HAVE_LIBPFM
14 #include "perfmon/perf_event.h"
15 #include "perfmon/pfmlib.h"
16 #include "perfmon/pfmlib_perf_event.h"
17 #endif
18 #include <cassert>
19
20 namespace exegesis {
21 namespace pfm {
22
23 #ifdef HAVE_LIBPFM
isPfmError(int Code)24 static bool isPfmError(int Code) { return Code != PFM_SUCCESS; }
25 #endif
26
pfmInitialize()27 bool pfmInitialize() {
28 #ifdef HAVE_LIBPFM
29 return isPfmError(pfm_initialize());
30 #else
31 return true;
32 #endif
33 }
34
pfmTerminate()35 void pfmTerminate() {
36 #ifdef HAVE_LIBPFM
37 pfm_terminate();
38 #endif
39 }
40
~PerfEvent()41 PerfEvent::~PerfEvent() {
42 #ifdef HAVE_LIBPFM
43 delete Attr;
44 ;
45 #endif
46 }
47
PerfEvent(PerfEvent && Other)48 PerfEvent::PerfEvent(PerfEvent &&Other)
49 : EventString(std::move(Other.EventString)),
50 FullQualifiedEventString(std::move(Other.FullQualifiedEventString)),
51 Attr(Other.Attr) {
52 Other.Attr = nullptr;
53 }
54
PerfEvent(llvm::StringRef PfmEventString)55 PerfEvent::PerfEvent(llvm::StringRef PfmEventString)
56 : EventString(PfmEventString.str()), Attr(nullptr) {
57 #ifdef HAVE_LIBPFM
58 char *Fstr = nullptr;
59 pfm_perf_encode_arg_t Arg = {};
60 Attr = new perf_event_attr();
61 Arg.attr = Attr;
62 Arg.fstr = &Fstr;
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
69 // crashing.
70 llvm::errs() << pfm_strerror(Result) << " - cannot create event "
71 << EventString << "\n";
72 }
73 if (Fstr) {
74 FullQualifiedEventString = Fstr;
75 free(Fstr);
76 }
77 #endif
78 }
79
name() const80 llvm::StringRef PerfEvent::name() const { return EventString; }
81
valid() const82 bool PerfEvent::valid() const { return !FullQualifiedEventString.empty(); }
83
attribute() const84 const perf_event_attr *PerfEvent::attribute() const { return Attr; }
85
getPfmEventString() const86 llvm::StringRef PerfEvent::getPfmEventString() const {
87 return FullQualifiedEventString;
88 }
89
90 #ifdef HAVE_LIBPFM
Counter(const PerfEvent & Event)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";
103 }
104 assert(FileDescriptor != -1 && "Unable to open event");
105 }
106
~Counter()107 Counter::~Counter() { close(FileDescriptor); }
108
start()109 void Counter::start() { ioctl(FileDescriptor, PERF_EVENT_IOC_RESET, 0); }
110
stop()111 void Counter::stop() { ioctl(FileDescriptor, PERF_EVENT_IOC_DISABLE, 0); }
112
read() const113 int64_t Counter::read() const {
114 int64_t Count = 0;
115 ssize_t ReadSize = ::read(FileDescriptor, &Count, sizeof(Count));
116 if (ReadSize != sizeof(Count)) {
117 Count = -1;
118 llvm::errs() << "Failed to read event counter\n";
119 }
120 return Count;
121 }
122
123 #else
124
Counter(const PerfEvent & Event)125 Counter::Counter(const PerfEvent &Event) {}
126
127 Counter::~Counter() = default;
128
start()129 void Counter::start() {}
130
stop()131 void Counter::stop() {}
132
read() const133 int64_t Counter::read() const { return 42; }
134
135 #endif
136
137 } // namespace pfm
138 } // namespace exegesis
139