Commit eacd3ecc authored by Matt Fleming's avatar Matt Fleming Committed by Ingo Molnar

perf: Add ->count() function to read per-package counters

For PMU drivers that record per-package counters, the ->count variable
cannot be used to record an accurate aggregated value, since it's not
possible to perform SMP cross-calls to cpus on other packages from the
context in which we update ->count.

Introduce a new optional ->count() accessor function that can be used to
customize how values are collected. If a PMU driver doesn't provide a
->count() function, we fallback to the existing code.

There is necessarily a window of staleness with this approach because
the task that generated the counter value may not have been scheduled by
the cpu recently.

An alternative and more complex approach would be to use a hrtimer to
periodically refresh the values from a more permissive scheduling
context. So, we're trading off complexity for accuracy.
Signed-off-by: default avatarMatt Fleming <matt.fleming@intel.com>
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Kanaka Juvva <kanaka.d.juvva@intel.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Vikas Shivappa <vikas.shivappa@linux.intel.com>
Link: http://lkml.kernel.org/r/1422038748-21397-3-git-send-email-matt@codeblueprint.co.ukSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 39bed6cb
...@@ -272,6 +272,11 @@ struct pmu { ...@@ -272,6 +272,11 @@ struct pmu {
*/ */
size_t task_ctx_size; size_t task_ctx_size;
/*
* Return the count value for a counter.
*/
u64 (*count) (struct perf_event *event); /*optional*/
}; };
/** /**
...@@ -770,6 +775,11 @@ static inline void perf_event_task_sched_out(struct task_struct *prev, ...@@ -770,6 +775,11 @@ static inline void perf_event_task_sched_out(struct task_struct *prev,
__perf_event_task_sched_out(prev, next); __perf_event_task_sched_out(prev, next);
} }
static inline u64 __perf_event_count(struct perf_event *event)
{
return local64_read(&event->count) + atomic64_read(&event->child_count);
}
extern void perf_event_mmap(struct vm_area_struct *vma); extern void perf_event_mmap(struct vm_area_struct *vma);
extern struct perf_guest_info_callbacks *perf_guest_cbs; extern struct perf_guest_info_callbacks *perf_guest_cbs;
extern int perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *callbacks); extern int perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *callbacks);
......
...@@ -3194,7 +3194,10 @@ static void __perf_event_read(void *info) ...@@ -3194,7 +3194,10 @@ static void __perf_event_read(void *info)
static inline u64 perf_event_count(struct perf_event *event) static inline u64 perf_event_count(struct perf_event *event)
{ {
return local64_read(&event->count) + atomic64_read(&event->child_count); if (event->pmu->count)
return event->pmu->count(event);
return __perf_event_count(event);
} }
static u64 perf_event_read(struct perf_event *event) static u64 perf_event_read(struct perf_event *event)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment