diff options
Diffstat (limited to 'include/linux/perf_event.h')
-rw-r--r-- | include/linux/perf_event.h | 90 |
1 files changed, 80 insertions, 10 deletions
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index bd9f55a5958d..ddbb6a901f65 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
@@ -299,18 +299,31 @@ struct perf_event_mmap_page { | |||
299 | /* | 299 | /* |
300 | * Bits needed to read the hw events in user-space. | 300 | * Bits needed to read the hw events in user-space. |
301 | * | 301 | * |
302 | * u32 seq; | 302 | * u32 seq, time_mult, time_shift, idx, width; |
303 | * s64 count; | 303 | * u64 count, enabled, running; |
304 | * u64 cyc, time_offset; | ||
305 | * s64 pmc = 0; | ||
304 | * | 306 | * |
305 | * do { | 307 | * do { |
306 | * seq = pc->lock; | 308 | * seq = pc->lock; |
307 | * | ||
308 | * barrier() | 309 | * barrier() |
309 | * if (pc->index) { | 310 | * |
310 | * count = pmc_read(pc->index - 1); | 311 | * enabled = pc->time_enabled; |
311 | * count += pc->offset; | 312 | * running = pc->time_running; |
312 | * } else | 313 | * |
313 | * goto regular_read; | 314 | * if (pc->cap_usr_time && enabled != running) { |
315 | * cyc = rdtsc(); | ||
316 | * time_offset = pc->time_offset; | ||
317 | * time_mult = pc->time_mult; | ||
318 | * time_shift = pc->time_shift; | ||
319 | * } | ||
320 | * | ||
321 | * idx = pc->index; | ||
322 | * count = pc->offset; | ||
323 | * if (pc->cap_usr_rdpmc && idx) { | ||
324 | * width = pc->pmc_width; | ||
325 | * pmc = rdpmc(idx - 1); | ||
326 | * } | ||
314 | * | 327 | * |
315 | * barrier(); | 328 | * barrier(); |
316 | * } while (pc->lock != seq); | 329 | * } while (pc->lock != seq); |
@@ -323,14 +336,57 @@ struct perf_event_mmap_page { | |||
323 | __s64 offset; /* add to hardware event value */ | 336 | __s64 offset; /* add to hardware event value */ |
324 | __u64 time_enabled; /* time event active */ | 337 | __u64 time_enabled; /* time event active */ |
325 | __u64 time_running; /* time event on cpu */ | 338 | __u64 time_running; /* time event on cpu */ |
326 | __u32 time_mult, time_shift; | 339 | union { |
340 | __u64 capabilities; | ||
341 | __u64 cap_usr_time : 1, | ||
342 | cap_usr_rdpmc : 1, | ||
343 | cap_____res : 62; | ||
344 | }; | ||
345 | |||
346 | /* | ||
347 | * If cap_usr_rdpmc this field provides the bit-width of the value | ||
348 | * read using the rdpmc() or equivalent instruction. This can be used | ||
349 | * to sign extend the result like: | ||
350 | * | ||
351 | * pmc <<= 64 - width; | ||
352 | * pmc >>= 64 - width; // signed shift right | ||
353 | * count += pmc; | ||
354 | */ | ||
355 | __u16 pmc_width; | ||
356 | |||
357 | /* | ||
358 | * If cap_usr_time the below fields can be used to compute the time | ||
359 | * delta since time_enabled (in ns) using rdtsc or similar. | ||
360 | * | ||
361 | * u64 quot, rem; | ||
362 | * u64 delta; | ||
363 | * | ||
364 | * quot = (cyc >> time_shift); | ||
365 | * rem = cyc & ((1 << time_shift) - 1); | ||
366 | * delta = time_offset + quot * time_mult + | ||
367 | * ((rem * time_mult) >> time_shift); | ||
368 | * | ||
369 | * Where time_offset,time_mult,time_shift and cyc are read in the | ||
370 | * seqcount loop described above. This delta can then be added to | ||
371 | * enabled and possible running (if idx), improving the scaling: | ||
372 | * | ||
373 | * enabled += delta; | ||
374 | * if (idx) | ||
375 | * running += delta; | ||
376 | * | ||
377 | * quot = count / running; | ||
378 | * rem = count % running; | ||
379 | * count = quot * enabled + (rem * enabled) / running; | ||
380 | */ | ||
381 | __u16 time_shift; | ||
382 | __u32 time_mult; | ||
327 | __u64 time_offset; | 383 | __u64 time_offset; |
328 | 384 | ||
329 | /* | 385 | /* |
330 | * Hole for extension of the self monitor capabilities | 386 | * Hole for extension of the self monitor capabilities |
331 | */ | 387 | */ |
332 | 388 | ||
333 | __u64 __reserved[121]; /* align to 1k */ | 389 | __u64 __reserved[120]; /* align to 1k */ |
334 | 390 | ||
335 | /* | 391 | /* |
336 | * Control data for the mmap() data buffer. | 392 | * Control data for the mmap() data buffer. |
@@ -550,6 +606,7 @@ struct perf_guest_info_callbacks { | |||
550 | #include <linux/irq_work.h> | 606 | #include <linux/irq_work.h> |
551 | #include <linux/static_key.h> | 607 | #include <linux/static_key.h> |
552 | #include <linux/atomic.h> | 608 | #include <linux/atomic.h> |
609 | #include <linux/sysfs.h> | ||
553 | #include <asm/local.h> | 610 | #include <asm/local.h> |
554 | 611 | ||
555 | #define PERF_MAX_STACK_DEPTH 255 | 612 | #define PERF_MAX_STACK_DEPTH 255 |
@@ -1291,5 +1348,18 @@ do { \ | |||
1291 | register_cpu_notifier(&fn##_nb); \ | 1348 | register_cpu_notifier(&fn##_nb); \ |
1292 | } while (0) | 1349 | } while (0) |
1293 | 1350 | ||
1351 | |||
1352 | #define PMU_FORMAT_ATTR(_name, _format) \ | ||
1353 | static ssize_t \ | ||
1354 | _name##_show(struct device *dev, \ | ||
1355 | struct device_attribute *attr, \ | ||
1356 | char *page) \ | ||
1357 | { \ | ||
1358 | BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE); \ | ||
1359 | return sprintf(page, _format "\n"); \ | ||
1360 | } \ | ||
1361 | \ | ||
1362 | static struct device_attribute format_attr_##_name = __ATTR_RO(_name) | ||
1363 | |||
1294 | #endif /* __KERNEL__ */ | 1364 | #endif /* __KERNEL__ */ |
1295 | #endif /* _LINUX_PERF_EVENT_H */ | 1365 | #endif /* _LINUX_PERF_EVENT_H */ |