diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2011-11-21 05:43:53 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2011-12-21 05:01:13 -0500 |
commit | e3f3541c19c89a4daae39300defba68943301949 (patch) | |
tree | f3d6fe5c39dfee8045e7955e5637ae9ff9c0d4d5 /kernel/events | |
parent | 0c9d42ed4cee2aa1dfc3a260b741baae8615744f (diff) |
perf: Extend the mmap control page with time (TSC) fields
Extend the mmap control page with fields so that userspace can compute
time deltas relative to the provided time fields.
Currently only implemented for x86 with constant and nonstop TSC.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Cc: Arun Sharma <asharma@fb.com>
Link: http://lkml.kernel.org/n/tip-3u1jucza77j3wuvs0x2bic0f@git.kernel.org
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/events')
-rw-r--r-- | kernel/events/core.c | 21 |
1 files changed, 14 insertions, 7 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c index dcd4049e92fc..3a9c7d81afbf 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
@@ -3220,17 +3220,22 @@ static int perf_event_index(struct perf_event *event) | |||
3220 | } | 3220 | } |
3221 | 3221 | ||
3222 | static void calc_timer_values(struct perf_event *event, | 3222 | static void calc_timer_values(struct perf_event *event, |
3223 | u64 *now, | ||
3223 | u64 *enabled, | 3224 | u64 *enabled, |
3224 | u64 *running) | 3225 | u64 *running) |
3225 | { | 3226 | { |
3226 | u64 now, ctx_time; | 3227 | u64 ctx_time; |
3227 | 3228 | ||
3228 | now = perf_clock(); | 3229 | *now = perf_clock(); |
3229 | ctx_time = event->shadow_ctx_time + now; | 3230 | ctx_time = event->shadow_ctx_time + *now; |
3230 | *enabled = ctx_time - event->tstamp_enabled; | 3231 | *enabled = ctx_time - event->tstamp_enabled; |
3231 | *running = ctx_time - event->tstamp_running; | 3232 | *running = ctx_time - event->tstamp_running; |
3232 | } | 3233 | } |
3233 | 3234 | ||
3235 | void __weak perf_update_user_clock(struct perf_event_mmap_page *userpg, u64 now) | ||
3236 | { | ||
3237 | } | ||
3238 | |||
3234 | /* | 3239 | /* |
3235 | * Callers need to ensure there can be no nesting of this function, otherwise | 3240 | * Callers need to ensure there can be no nesting of this function, otherwise |
3236 | * the seqlock logic goes bad. We can not serialize this because the arch | 3241 | * the seqlock logic goes bad. We can not serialize this because the arch |
@@ -3240,7 +3245,7 @@ void perf_event_update_userpage(struct perf_event *event) | |||
3240 | { | 3245 | { |
3241 | struct perf_event_mmap_page *userpg; | 3246 | struct perf_event_mmap_page *userpg; |
3242 | struct ring_buffer *rb; | 3247 | struct ring_buffer *rb; |
3243 | u64 enabled, running; | 3248 | u64 enabled, running, now; |
3244 | 3249 | ||
3245 | rcu_read_lock(); | 3250 | rcu_read_lock(); |
3246 | /* | 3251 | /* |
@@ -3252,7 +3257,7 @@ void perf_event_update_userpage(struct perf_event *event) | |||
3252 | * because of locking issue as we can be called in | 3257 | * because of locking issue as we can be called in |
3253 | * NMI context | 3258 | * NMI context |
3254 | */ | 3259 | */ |
3255 | calc_timer_values(event, &enabled, &running); | 3260 | calc_timer_values(event, &now, &enabled, &running); |
3256 | rb = rcu_dereference(event->rb); | 3261 | rb = rcu_dereference(event->rb); |
3257 | if (!rb) | 3262 | if (!rb) |
3258 | goto unlock; | 3263 | goto unlock; |
@@ -3277,6 +3282,8 @@ void perf_event_update_userpage(struct perf_event *event) | |||
3277 | userpg->time_running = running + | 3282 | userpg->time_running = running + |
3278 | atomic64_read(&event->child_total_time_running); | 3283 | atomic64_read(&event->child_total_time_running); |
3279 | 3284 | ||
3285 | perf_update_user_clock(userpg, now); | ||
3286 | |||
3280 | barrier(); | 3287 | barrier(); |
3281 | ++userpg->lock; | 3288 | ++userpg->lock; |
3282 | preempt_enable(); | 3289 | preempt_enable(); |
@@ -3763,7 +3770,7 @@ static void perf_output_read_group(struct perf_output_handle *handle, | |||
3763 | static void perf_output_read(struct perf_output_handle *handle, | 3770 | static void perf_output_read(struct perf_output_handle *handle, |
3764 | struct perf_event *event) | 3771 | struct perf_event *event) |
3765 | { | 3772 | { |
3766 | u64 enabled = 0, running = 0; | 3773 | u64 enabled = 0, running = 0, now; |
3767 | u64 read_format = event->attr.read_format; | 3774 | u64 read_format = event->attr.read_format; |
3768 | 3775 | ||
3769 | /* | 3776 | /* |
@@ -3776,7 +3783,7 @@ static void perf_output_read(struct perf_output_handle *handle, | |||
3776 | * NMI context | 3783 | * NMI context |
3777 | */ | 3784 | */ |
3778 | if (read_format & PERF_FORMAT_TOTAL_TIMES) | 3785 | if (read_format & PERF_FORMAT_TOTAL_TIMES) |
3779 | calc_timer_values(event, &enabled, &running); | 3786 | calc_timer_values(event, &now, &enabled, &running); |
3780 | 3787 | ||
3781 | if (event->attr.read_format & PERF_FORMAT_GROUP) | 3788 | if (event->attr.read_format & PERF_FORMAT_GROUP) |
3782 | perf_output_read_group(handle, event, enabled, running); | 3789 | perf_output_read_group(handle, event, enabled, running); |