• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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