PAPI  5.7.0.0
perf_helpers.h
Go to the documentation of this file.
1 /*****************************************************************/
2 /********* Begin perf_event low-level code ***********************/
3 /*****************************************************************/
4 
5 /* In case headers aren't new enough to have __NR_perf_event_open */
6 #ifndef __NR_perf_event_open
7 
8 #ifdef __powerpc__
9 #define __NR_perf_event_open 319
10 #elif defined(__x86_64__)
11 #define __NR_perf_event_open 298
12 #elif defined(__i386__)
13 #define __NR_perf_event_open 336
14 #elif defined(__arm__)
15 #define __NR_perf_event_open 364
16 #endif
17 
18 #endif
19 
20 static long
22  pid_t pid, int cpu, int group_fd, unsigned long flags )
23 {
24  int ret;
25 
26  ret = syscall( __NR_perf_event_open,
27  hw_event, pid, cpu, group_fd, flags );
28 
29  return ret;
30 }
31 
32 #if defined(__x86_64__) || defined(__i386__)
33 
34 
35 static inline unsigned long long rdtsc(void) {
36 
37  unsigned a,d;
38 
39  __asm__ volatile("rdtsc" : "=a" (a), "=d" (d));
40 
41  return ((unsigned long long)a) | (((unsigned long long)d) << 32);
42 }
43 
44 static inline unsigned long long rdpmc(unsigned int counter) {
45 
46  unsigned int low, high;
47 
48  __asm__ volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (counter));
49 
50  return (unsigned long long)low | ((unsigned long long)high) <<32;
51 }
52 
53 #define barrier() __asm__ volatile("" ::: "memory")
54 
55 /* based on the code in include/uapi/linux/perf_event.h */
56 static inline unsigned long long mmap_read_self(void *addr,
57  unsigned long long *en,
58  unsigned long long *ru) {
59 
60  struct perf_event_mmap_page *pc = addr;
61 
62  uint32_t seq, time_mult, time_shift, index, width;
63  int64_t count;
64  uint64_t enabled, running;
65  uint64_t cyc, time_offset;
66  int64_t pmc = 0;
67  uint64_t quot, rem;
68  uint64_t delta = 0;
69 
70 
71  do {
72  /* The kernel increments pc->lock any time */
73  /* perf_event_update_userpage() is called */
74  /* So by checking now, and the end, we */
75  /* can see if an update happened while we */
76  /* were trying to read things, and re-try */
77  /* if something changed */
78  /* The barrier ensures we get the most up to date */
79  /* version of the pc->lock variable */
80 
81  seq=pc->lock;
82  barrier();
83 
84  /* For multiplexing */
85  /* time_enabled is time the event was enabled */
86  enabled = pc->time_enabled;
87  /* time_running is time the event was actually running */
88  running = pc->time_running;
89 
90  /* if cap_user_time is set, we can use rdtsc */
91  /* to calculate more exact enabled/running time */
92  /* for more accurate multiplex calculations */
93  if ( (pc->cap_user_time) && (enabled != running)) {
94  cyc = rdtsc();
95  time_offset = pc->time_offset;
96  time_mult = pc->time_mult;
97  time_shift = pc->time_shift;
98 
99  quot=(cyc>>time_shift);
100  rem = cyc & (((uint64_t)1 << time_shift) - 1);
101  delta = time_offset + (quot * time_mult) +
102  ((rem * time_mult) >> time_shift);
103  }
104  enabled+=delta;
105 
106  /* actually do the measurement */
107 
108  /* Index of register to read */
109  /* 0 means stopped/not-active */
110  /* Need to subtract 1 to get actual index to rdpmc() */
111  index = pc->index;
112 
113  /* count is the value of the counter the last time */
114  /* the kernel read it */
115  /* If we don't sign extend it, we get large negative */
116  /* numbers which break if an IOC_RESET is done */
117  width = pc->pmc_width;
118  count = pc->offset;
119  count<<=(64-width);
120  count>>=(64-width);
121 
122  /* Ugh, libpfm4 perf_event.h has cap_usr_rdpmc */
123  /* while actual perf_event.h has cap_user_rdpmc */
124 
125  /* Only read if rdpmc enabled and event index valid */
126  /* Otherwise return the older (out of date?) count value */
127  if (pc->cap_usr_rdpmc && index) {
128 
129  /* Read counter value */
130  pmc = rdpmc(index-1);
131 
132  /* sign extend result */
133  pmc<<=(64-width);
134  pmc>>=(64-width);
135 
136  /* add current count into the existing kernel count */
137  count+=pmc;
138 
139  /* Only adjust if index is valid */
140  running+=delta;
141  } else {
142  /* Falling back because rdpmc not supported */
143  /* for this event. */
144  return 0xffffffffffffffffULL;
145  }
146 
147  barrier();
148 
149  } while (pc->lock != seq);
150 
151  if (en) *en=enabled;
152  if (ru) *ru=running;
153 
154  return count;
155 }
156 
157 #else
158 static inline unsigned long long mmap_read_self(void *addr,
159  unsigned long long *en,
160  unsigned long long *ru) {
161 
162  (void)addr;
163 
164  *en=0;
165  *ru=0;
166 
167  return (unsigned long long)(-1);
168 }
169 
170 #endif
171 
172 /* These functions are based on builtin-record.c in the */
173 /* kernel's tools/perf directory. */
174 /* This code is from a really ancient version of perf */
175 /* And should be updated/commented properly */
176 
177 
178 static uint64_t
180 {
181  struct perf_event_mmap_page *pc = pe->mmap_buf;
182  int head;
183 
184  if ( pc == NULL ) {
185  PAPIERROR( "perf_event_mmap_page is NULL" );
186  return 0;
187  }
188 
189  head = pc->data_head;
190  rmb();
191 
192  return head;
193 }
194 
195 static void
196 mmap_write_tail( pe_event_info_t *pe, uint64_t tail )
197 {
198  struct perf_event_mmap_page *pc = pe->mmap_buf;
199 
200  /* ensure all reads are done before we write the tail out. */
201  pc->data_tail = tail;
202 }
203 
204 /* Does the kernel define these somewhere? */
205 struct ip_event {
206  struct perf_event_header header;
207  uint64_t ip;
208 };
209 struct lost_event {
210  struct perf_event_header header;
211  uint64_t id;
212  uint64_t lost;
213 };
214 typedef union event_union {
215  struct perf_event_header header;
216  struct ip_event ip;
217  struct lost_event lost;
219 
220 /* Should re-write with comments if we ever figure out what's */
221 /* going on here. */
222 static void
224  int profile_index )
225 {
226  uint64_t head = mmap_read_head( pe );
227  uint64_t old = pe->tail;
228  unsigned char *data = ((unsigned char*)pe->mmap_buf) + getpagesize();
229  int diff;
230 
231  diff = head - old;
232  if ( diff < 0 ) {
233  SUBDBG( "WARNING: failed to keep up with mmap data. head = %" PRIu64
234  ", tail = %" PRIu64 ". Discarding samples.\n", head, old );
235  /* head points to a known good entry, start there. */
236  old = head;
237  }
238 
239  for( ; old != head; ) {
240  perf_sample_event_t *event = ( perf_sample_event_t * )& data[old & pe->mask];
241  perf_sample_event_t event_copy;
242  size_t size = event->header.size;
243 
244  /* Event straddles the mmap boundary -- header should always */
245  /* be inside due to u64 alignment of output. */
246  if ( ( old & pe->mask ) + size != ( ( old + size ) & pe->mask ) ) {
247  uint64_t offset = old;
248  uint64_t len = min( sizeof ( *event ), size ), cpy;
249  void *dst = &event_copy;
250 
251  do {
252  cpy = min( pe->mask + 1 - ( offset & pe->mask ), len );
253  memcpy( dst, &data[offset & pe->mask], cpy );
254  offset += cpy;
255  dst = ((unsigned char*)dst) + cpy;
256  len -= cpy;
257  } while ( len );
258 
259  event = &event_copy;
260  }
261  old += size;
262 
263  SUBDBG( "event->type = %08x\n", event->header.type );
264  SUBDBG( "event->size = %d\n", event->header.size );
265 
266  switch ( event->header.type ) {
267  case PERF_RECORD_SAMPLE:
268  _papi_hwi_dispatch_profile( ( *thr )->running_eventset[cidx],
269  ( caddr_t ) ( unsigned long ) event->ip.ip,
270  0, profile_index );
271  break;
272 
273  case PERF_RECORD_LOST:
274  SUBDBG( "Warning: because of a mmap buffer overrun, %" PRId64
275  " events were lost.\n"
276  "Loss was recorded when counter id %#"PRIx64
277  " overflowed.\n", event->lost.lost, event->lost.id );
278  break;
279  default:
280  SUBDBG( "Error: unexpected header type - %d\n",
281  event->header.type );
282  break;
283  }
284  }
285 
286  pe->tail = old;
287  mmap_write_tail( pe, old );
288 }
289 
290 
struct perf_event_header header
Definition: perf_helpers.h:215
static unsigned long long mmap_read_self(void *addr, unsigned long long *en, unsigned long long *ru)
Definition: perf_helpers.h:158
off64_t offset
Definition: iozone.c:1279
if(file==NULL) goto out
struct perf_event_header header
Definition: perf_helpers.h:206
struct perf_event_header header
Definition: perf_helpers.h:210
static int cidx
static int pid
#define SUBDBG(format, args...)
Definition: papi_debug.h:63
void PAPIERROR(char *format,...)
long long ret
Definition: iozone.c:1346
#define min(x, y)
Definition: darwin-common.h:4
static long sys_perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu, int group_fd, unsigned long flags)
Definition: perf_helpers.h:21
uint64_t id
Definition: perf_helpers.h:211
uint64_t ip
Definition: perf_helpers.h:207
static void mmap_read(int cidx, ThreadInfo_t **thr, pe_event_info_t *pe, int profile_index)
Definition: perf_helpers.h:223
void _papi_hwi_dispatch_profile(EventSetInfo_t *ESI, caddr_t pc, long long over, int profile_index)
Definition: extras.c:165
uint64_t rdpmc(int c)
Definition: vmware.c:93
uint64_t lost
Definition: perf_helpers.h:212
char * caddr_t
static void mmap_write_tail(pe_event_info_t *pe, uint64_t tail)
Definition: perf_helpers.h:196
static long count
static double a[MATRIX_SIZE][MATRIX_SIZE]
Definition: libmsr_basic.c:38
static uint64_t mmap_read_head(pe_event_info_t *pe)
Definition: perf_helpers.h:179