gem5  v20.1.0.0
perfevent.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012 ARM Limited
3  * All rights reserved
4  *
5  * The license below extends only to copyright in the software and shall
6  * not be construed as granting a license to any other intellectual
7  * property including but not limited to intellectual property relating
8  * to a hardware implementation of the functionality of the software
9  * licensed hereunder. You may use the software subject to the license
10  * terms below provided that you ensure that this notice is replicated
11  * unmodified and in its entirety in all distributions of the software,
12  * modified or unmodified, in source code or in binary form.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions are
16  * met: redistributions of source code must retain the above copyright
17  * notice, this list of conditions and the following disclaimer;
18  * redistributions in binary form must reproduce the above copyright
19  * notice, this list of conditions and the following disclaimer in the
20  * documentation and/or other materials provided with the distribution;
21  * neither the name of the copyright holders nor the names of its
22  * contributors may be used to endorse or promote products derived from
23  * this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 #include <fcntl.h>
39 #include <sys/ioctl.h>
40 #include <sys/mman.h>
41 #include <sys/syscall.h>
42 #include <sys/types.h>
43 #include <syscall.h>
44 #include <unistd.h>
45 
46 #include <cassert>
47 #include <cerrno>
48 #include <csignal>
49 #include <cstring>
50 
51 #include "base/logging.hh"
52 #include "perfevent.hh"
53 
55 {
56  memset(&attr, 0, sizeof(attr));
57 
58  attr.size = PERF_ATTR_SIZE_VER0;
59  attr.type = type;
60  attr.config = config;
61 }
62 
64 {
65 }
66 
67 
69  : fd(-1), ringBuffer(NULL), pageSize(-1)
70 {
71  attach(config, tid, -1);
72 }
73 
75  pid_t tid, const PerfKvmCounter &parent)
76  : fd(-1), ringBuffer(NULL), pageSize(-1)
77 {
78  attach(config, tid, parent);
79 }
80 
82  : fd(-1), ringBuffer(NULL), pageSize(-1)
83 {
84 }
85 
87 {
88  if (attached())
89  detach();
90 }
91 
92 void
94 {
95  assert(attached());
96 
97  if (munmap(ringBuffer, ringNumPages * pageSize) == -1)
98  warn("PerfKvmCounter: Failed to unmap ring buffer (%i)\n",
99  errno);
100  close(fd);
101 
102  fd = -1;
103  ringBuffer = NULL;
104 }
105 
106 void
108 {
109  if (ioctl(PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1)
110  panic("KVM: Failed to enable performance counters (%i)\n", errno);
111 }
112 
113 void
115 {
116  if (ioctl(PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1)
117  panic("KVM: Failed to disable performance counters (%i)\n", errno);
118 }
119 
120 void
121 PerfKvmCounter::period(uint64_t period)
122 {
123  if (ioctl(PERF_EVENT_IOC_PERIOD, &period) == -1)
124  panic("KVM: Failed to set period of performance counter (%i)\n", errno);
125 }
126 
127 void
129 {
130  if (ioctl(PERF_EVENT_IOC_REFRESH, refresh) == -1)
131  panic("KVM: Failed to refresh performance counter (%i)\n", errno);
132 }
133 
134 uint64_t
136 {
137  uint64_t value;
138 
139  read(&value, sizeof(uint64_t));
140  return value;
141 }
142 
143 void
144 PerfKvmCounter::enableSignals(pid_t tid, int signal)
145 {
146  struct f_owner_ex sigowner;
147 
148  sigowner.type = F_OWNER_TID;
149  sigowner.pid = tid;
150 
151  if (fcntl(F_SETOWN_EX, &sigowner) == -1 ||
152  fcntl(F_SETSIG, signal) == -1 ||
153  fcntl(F_SETFL, O_ASYNC) == -1)
154  panic("PerfKvmCounter: Failed to enable signals for counter (%i)\n",
155  errno);
156 }
157 
158 void
160  pid_t tid, int group_fd)
161 {
162  assert(!attached());
163 
164  fd = syscall(__NR_perf_event_open,
165  &config.attr, tid,
166  -1, // CPU (-1 => Any CPU that the task happens to run on)
167  group_fd,
168  0); // Flags
169  if (fd == -1)
170  {
171  if (errno == EACCES)
172  {
173  panic("PerfKvmCounter::attach recieved error EACCESS\n"
174  " This error may be caused by a too restrictive setting\n"
175  " in the file '/proc/sys/kernel/perf_event_paranoid'\n"
176  " The default value was changed to 2 in kernel 4.6\n"
177  " A value greater than 1 prevents gem5 from making\n"
178  " the syscall to perf_event_open");
179  }
180  panic("PerfKvmCounter::attach failed (%i)\n", errno);
181  }
182 
183  mmapPerf(1);
184 }
185 
186 pid_t
188 {
189  return syscall(__NR_gettid);
190 }
191 
192 void
194 {
195  assert(attached());
196  assert(ringBuffer == NULL);
197 
198  if (pageSize == -1) {
199  pageSize = sysconf(_SC_PAGE_SIZE);
200  if (pageSize == -1)
201  panic("PerfKvmCounter: Failed to determine page size (%i)\n",
202  errno);
203  }
204 
205  ringNumPages = pages + 1;
206  ringBuffer = (struct perf_event_mmap_page *)mmap(
207  NULL, ringNumPages * 4096,
208  PROT_READ | PROT_WRITE, MAP_SHARED,
209  fd, 0);
210  if (ringBuffer == MAP_FAILED)
211  panic("PerfKvmCounter: MMAP failed (%i)\n",
212  errno);
213 }
214 
215 int
216 PerfKvmCounter::fcntl(int cmd, long p1)
217 {
218  assert(attached());
219  return ::fcntl(fd, cmd, p1);
220 }
221 
222 int
223 PerfKvmCounter::ioctl(int request, long p1)
224 {
225  assert(attached());
226  return ::ioctl(fd, request, p1);
227 }
228 
229 void
230 PerfKvmCounter::read(void *buf, size_t size) const
231 {
232  char *_buf = (char *)buf;
233  size_t _size = size;
234 
235  assert(attached());
236 
237  do {
238  ssize_t ret;
239  ret = ::read(fd, _buf, _size);
240  switch (ret) {
241  case -1:
242  if (errno != EAGAIN)
243  panic("PerfKvmCounter::read failed (%i)\n", errno);
244  break;
245 
246  case 0:
247  panic("PerfKvmCounter::read unexpected EOF.\n");
248 
249  default:
250  _size -= ret;
251  _buf += ret;
252  break;
253  }
254  } while (_size);
255 }
PerfKvmCounter
An instance of a performance counter.
Definition: perfevent.hh:168
warn
#define warn(...)
Definition: logging.hh:239
PerfKvmCounterConfig::PerfKvmCounterConfig
PerfKvmCounterConfig(uint32_t type, uint64_t config)
Initialize PerfEvent counter configuration structure.
Definition: perfevent.cc:54
PerfKvmCounter::sysGettid
pid_t sysGettid()
Get the TID of the current thread.
Definition: perfevent.cc:187
PerfKvmCounter::mmapPerf
void mmapPerf(int pages)
MMAP the PerfEvent file descriptor.
Definition: perfevent.cc:193
PerfKvmCounter::fd
int fd
PerfEvent file descriptor associated with counter.
Definition: perfevent.hh:370
ArmISA::fd
Bitfield< 14, 12 > fd
Definition: types.hh:159
type
uint8_t type
Definition: inet.hh:421
PerfKvmCounter::detach
void detach()
Detach a counter from PerfEvent.
Definition: perfevent.cc:93
PerfKvmCounterConfig::attr
struct perf_event_attr attr
Underlying perf_event_attr structure describing the counter.
Definition: perfevent.hh:162
PerfKvmCounter::fcntl
int fcntl(int cmd, long p1)
PerfEvent fnctl interface.
Definition: perfevent.cc:216
PerfKvmCounter::pageSize
long pageSize
Cached host page size.
Definition: perfevent.hh:378
PerfKvmCounter::ringBuffer
struct perf_event_mmap_page * ringBuffer
Memory mapped PerfEvent sample ring buffer.
Definition: perfevent.hh:373
PerfKvmCounterConfig
PerfEvent counter configuration.
Definition: perfevent.hh:51
PerfKvmCounter::period
void period(uint64_t period)
Update the period of an overflow counter.
Definition: perfevent.cc:121
PerfKvmCounter::enableSignals
void enableSignals(pid_t tid, int signal)
Enable signal delivery to a thread on counter overflow.
Definition: perfevent.cc:144
PerfKvmCounter::start
void start()
Start counting.
Definition: perfevent.cc:107
perfevent.hh
PerfKvmCounter::stop
void stop()
Stop counting.
Definition: perfevent.cc:114
PerfKvmCounter::read
uint64_t read() const
Read the current value of a counter.
Definition: perfevent.cc:135
PerfKvmCounter::PerfKvmCounter
PerfKvmCounter()
Create a new counter, but don't attach it.
Definition: perfevent.cc:81
logging.hh
PerfKvmCounter::attached
bool attached() const
Check if a counter is attached.
Definition: perfevent.hh:228
PerfKvmCounter::attach
void attach(PerfKvmCounterConfig &config, pid_t tid)
Attach a counter.
Definition: perfevent.hh:204
PerfKvmCounterConfig::~PerfKvmCounterConfig
~PerfKvmCounterConfig()
Definition: perfevent.cc:63
PerfKvmCounter::~PerfKvmCounter
~PerfKvmCounter()
Definition: perfevent.cc:86
PerfKvmCounter::ringNumPages
int ringNumPages
Total number of pages in ring buffer.
Definition: perfevent.hh:375
panic
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:171
PerfKvmCounter::refresh
void refresh(int refresh)
Enable a counter for a fixed number of events.
Definition: perfevent.cc:128
PerfKvmCounter::ioctl
int ioctl(int request, long p1)
PerfEvent ioctl interface.
Definition: perfevent.cc:223

Generated on Wed Sep 30 2020 14:02:08 for gem5 by doxygen 1.8.17