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 //===----------------------------------------------------------------------===//
8 
9 #include "PerfHelper.h"
10 #include "llvm/Config/config.h"
11 #include "llvm/Support/raw_ostream.h"
12 #ifdef HAVE_LIBPFM
13 #include "perfmon/perf_event.h"
14 #include "perfmon/pfmlib.h"
15 #include "perfmon/pfmlib_perf_event.h"
16 #endif
17 #include <cassert>
18 
19 namespace llvm {
20 namespace exegesis {
21 namespace pfm {
22 
23 #ifdef HAVE_LIBPFM
24 static bool isPfmError(int Code) { return Code != PFM_SUCCESS; }
25 #endif
26 
27 bool pfmInitialize() {
28 #ifdef HAVE_LIBPFM
29   return isPfmError(pfm_initialize());
30 #else
31   return true;
32 #endif
33 }
34 
35 void pfmTerminate() {
36 #ifdef HAVE_LIBPFM
37   pfm_terminate();
38 #endif
39 }
40 
41 PerfEvent::~PerfEvent() {
42 #ifdef HAVE_LIBPFM
43   delete Attr;
44   ;
45 #endif
46 }
47 
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 
55 PerfEvent::PerfEvent(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     errs() << pfm_strerror(Result) << " - cannot create event " << EventString
71            << "\n";
72   }
73   if (Fstr) {
74     FullQualifiedEventString = Fstr;
75     free(Fstr);
76   }
77 #endif
78 }
79 
80 StringRef PerfEvent::name() const { return EventString; }
81 
82 bool PerfEvent::valid() const { return !FullQualifiedEventString.empty(); }
83 
84 const perf_event_attr *PerfEvent::attribute() const { return Attr; }
85 
86 StringRef PerfEvent::getPfmEventString() const {
87   return FullQualifiedEventString;
88 }
89 
90 #ifdef HAVE_LIBPFM
91 Counter::Counter(PerfEvent &&E) : Event(std::move(E)){
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     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 
107 Counter::~Counter() { close(FileDescriptor); }
108 
109 void Counter::start() { ioctl(FileDescriptor, PERF_EVENT_IOC_RESET, 0); }
110 
111 void Counter::stop() { ioctl(FileDescriptor, PERF_EVENT_IOC_DISABLE, 0); }
112 
113 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     errs() << "Failed to read event counter\n";
119   }
120   return Count;
121 }
122 
123 #else
124 
125 Counter::Counter(PerfEvent &&Event) : Event(std::move(Event)) {}
126 
127 Counter::~Counter() = default;
128 
129 void Counter::start() {}
130 
131 void Counter::stop() {}
132 
133 int64_t Counter::read() const { return 42; }
134 
135 #endif
136 
137 } // namespace pfm
138 } // namespace exegesis
139 } // namespace llvm
140