diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2009-04-06 05:45:10 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-04-07 04:49:00 -0400 |
commit | 4af4998b8aa35600f4c4a4f3c3a23baca6081d02 (patch) | |
tree | c980ff7f7c9f21acf873184ec9d63cfb6435a2a5 /kernel/perf_counter.c | |
parent | 4c9e25428ff46b968a30f1dfafdba550cb6e4141 (diff) |
perf_counter: rework context time
Since perf_counter_context is switched along with tasks, we can
maintain the context time without using the task runtime clock.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
LKML-Reference: <20090406094518.353552838@chello.nl>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/perf_counter.c')
-rw-r--r-- | kernel/perf_counter.c | 78 |
1 files changed, 34 insertions, 44 deletions
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 8c8eaf0625f9..84d85ab4e161 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c | |||
@@ -117,7 +117,7 @@ counter_sched_out(struct perf_counter *counter, | |||
117 | return; | 117 | return; |
118 | 118 | ||
119 | counter->state = PERF_COUNTER_STATE_INACTIVE; | 119 | counter->state = PERF_COUNTER_STATE_INACTIVE; |
120 | counter->tstamp_stopped = ctx->time_now; | 120 | counter->tstamp_stopped = ctx->time; |
121 | counter->hw_ops->disable(counter); | 121 | counter->hw_ops->disable(counter); |
122 | counter->oncpu = -1; | 122 | counter->oncpu = -1; |
123 | 123 | ||
@@ -253,27 +253,20 @@ retry: | |||
253 | spin_unlock_irq(&ctx->lock); | 253 | spin_unlock_irq(&ctx->lock); |
254 | } | 254 | } |
255 | 255 | ||
256 | /* | 256 | static inline u64 perf_clock(void) |
257 | * Get the current time for this context. | ||
258 | * If this is a task context, we use the task's task clock, | ||
259 | * or for a per-cpu context, we use the cpu clock. | ||
260 | */ | ||
261 | static u64 get_context_time(struct perf_counter_context *ctx, int update) | ||
262 | { | 257 | { |
263 | struct task_struct *curr = ctx->task; | 258 | return cpu_clock(smp_processor_id()); |
264 | |||
265 | if (!curr) | ||
266 | return cpu_clock(smp_processor_id()); | ||
267 | |||
268 | return __task_delta_exec(curr, update) + curr->se.sum_exec_runtime; | ||
269 | } | 259 | } |
270 | 260 | ||
271 | /* | 261 | /* |
272 | * Update the record of the current time in a context. | 262 | * Update the record of the current time in a context. |
273 | */ | 263 | */ |
274 | static void update_context_time(struct perf_counter_context *ctx, int update) | 264 | static void update_context_time(struct perf_counter_context *ctx) |
275 | { | 265 | { |
276 | ctx->time_now = get_context_time(ctx, update) - ctx->time_lost; | 266 | u64 now = perf_clock(); |
267 | |||
268 | ctx->time += now - ctx->timestamp; | ||
269 | ctx->timestamp = now; | ||
277 | } | 270 | } |
278 | 271 | ||
279 | /* | 272 | /* |
@@ -284,15 +277,17 @@ static void update_counter_times(struct perf_counter *counter) | |||
284 | struct perf_counter_context *ctx = counter->ctx; | 277 | struct perf_counter_context *ctx = counter->ctx; |
285 | u64 run_end; | 278 | u64 run_end; |
286 | 279 | ||
287 | if (counter->state >= PERF_COUNTER_STATE_INACTIVE) { | 280 | if (counter->state < PERF_COUNTER_STATE_INACTIVE) |
288 | counter->total_time_enabled = ctx->time_now - | 281 | return; |
289 | counter->tstamp_enabled; | 282 | |
290 | if (counter->state == PERF_COUNTER_STATE_INACTIVE) | 283 | counter->total_time_enabled = ctx->time - counter->tstamp_enabled; |
291 | run_end = counter->tstamp_stopped; | 284 | |
292 | else | 285 | if (counter->state == PERF_COUNTER_STATE_INACTIVE) |
293 | run_end = ctx->time_now; | 286 | run_end = counter->tstamp_stopped; |
294 | counter->total_time_running = run_end - counter->tstamp_running; | 287 | else |
295 | } | 288 | run_end = ctx->time; |
289 | |||
290 | counter->total_time_running = run_end - counter->tstamp_running; | ||
296 | } | 291 | } |
297 | 292 | ||
298 | /* | 293 | /* |
@@ -332,7 +327,7 @@ static void __perf_counter_disable(void *info) | |||
332 | * If it is in error state, leave it in error state. | 327 | * If it is in error state, leave it in error state. |
333 | */ | 328 | */ |
334 | if (counter->state >= PERF_COUNTER_STATE_INACTIVE) { | 329 | if (counter->state >= PERF_COUNTER_STATE_INACTIVE) { |
335 | update_context_time(ctx, 1); | 330 | update_context_time(ctx); |
336 | update_counter_times(counter); | 331 | update_counter_times(counter); |
337 | if (counter == counter->group_leader) | 332 | if (counter == counter->group_leader) |
338 | group_sched_out(counter, cpuctx, ctx); | 333 | group_sched_out(counter, cpuctx, ctx); |
@@ -426,7 +421,7 @@ counter_sched_in(struct perf_counter *counter, | |||
426 | return -EAGAIN; | 421 | return -EAGAIN; |
427 | } | 422 | } |
428 | 423 | ||
429 | counter->tstamp_running += ctx->time_now - counter->tstamp_stopped; | 424 | counter->tstamp_running += ctx->time - counter->tstamp_stopped; |
430 | 425 | ||
431 | if (!is_software_counter(counter)) | 426 | if (!is_software_counter(counter)) |
432 | cpuctx->active_oncpu++; | 427 | cpuctx->active_oncpu++; |
@@ -493,9 +488,9 @@ static void add_counter_to_ctx(struct perf_counter *counter, | |||
493 | list_add_counter(counter, ctx); | 488 | list_add_counter(counter, ctx); |
494 | ctx->nr_counters++; | 489 | ctx->nr_counters++; |
495 | counter->prev_state = PERF_COUNTER_STATE_OFF; | 490 | counter->prev_state = PERF_COUNTER_STATE_OFF; |
496 | counter->tstamp_enabled = ctx->time_now; | 491 | counter->tstamp_enabled = ctx->time; |
497 | counter->tstamp_running = ctx->time_now; | 492 | counter->tstamp_running = ctx->time; |
498 | counter->tstamp_stopped = ctx->time_now; | 493 | counter->tstamp_stopped = ctx->time; |
499 | } | 494 | } |
500 | 495 | ||
501 | /* | 496 | /* |
@@ -522,7 +517,7 @@ static void __perf_install_in_context(void *info) | |||
522 | 517 | ||
523 | curr_rq_lock_irq_save(&flags); | 518 | curr_rq_lock_irq_save(&flags); |
524 | spin_lock(&ctx->lock); | 519 | spin_lock(&ctx->lock); |
525 | update_context_time(ctx, 1); | 520 | update_context_time(ctx); |
526 | 521 | ||
527 | /* | 522 | /* |
528 | * Protect the list operation against NMI by disabling the | 523 | * Protect the list operation against NMI by disabling the |
@@ -648,13 +643,13 @@ static void __perf_counter_enable(void *info) | |||
648 | 643 | ||
649 | curr_rq_lock_irq_save(&flags); | 644 | curr_rq_lock_irq_save(&flags); |
650 | spin_lock(&ctx->lock); | 645 | spin_lock(&ctx->lock); |
651 | update_context_time(ctx, 1); | 646 | update_context_time(ctx); |
652 | 647 | ||
653 | counter->prev_state = counter->state; | 648 | counter->prev_state = counter->state; |
654 | if (counter->state >= PERF_COUNTER_STATE_INACTIVE) | 649 | if (counter->state >= PERF_COUNTER_STATE_INACTIVE) |
655 | goto unlock; | 650 | goto unlock; |
656 | counter->state = PERF_COUNTER_STATE_INACTIVE; | 651 | counter->state = PERF_COUNTER_STATE_INACTIVE; |
657 | counter->tstamp_enabled = ctx->time_now - counter->total_time_enabled; | 652 | counter->tstamp_enabled = ctx->time - counter->total_time_enabled; |
658 | 653 | ||
659 | /* | 654 | /* |
660 | * If the counter is in a group and isn't the group leader, | 655 | * If the counter is in a group and isn't the group leader, |
@@ -737,8 +732,8 @@ static void perf_counter_enable(struct perf_counter *counter) | |||
737 | */ | 732 | */ |
738 | if (counter->state == PERF_COUNTER_STATE_OFF) { | 733 | if (counter->state == PERF_COUNTER_STATE_OFF) { |
739 | counter->state = PERF_COUNTER_STATE_INACTIVE; | 734 | counter->state = PERF_COUNTER_STATE_INACTIVE; |
740 | counter->tstamp_enabled = ctx->time_now - | 735 | counter->tstamp_enabled = |
741 | counter->total_time_enabled; | 736 | ctx->time - counter->total_time_enabled; |
742 | } | 737 | } |
743 | out: | 738 | out: |
744 | spin_unlock_irq(&ctx->lock); | 739 | spin_unlock_irq(&ctx->lock); |
@@ -778,7 +773,7 @@ void __perf_counter_sched_out(struct perf_counter_context *ctx, | |||
778 | ctx->is_active = 0; | 773 | ctx->is_active = 0; |
779 | if (likely(!ctx->nr_counters)) | 774 | if (likely(!ctx->nr_counters)) |
780 | goto out; | 775 | goto out; |
781 | update_context_time(ctx, 0); | 776 | update_context_time(ctx); |
782 | 777 | ||
783 | flags = hw_perf_save_disable(); | 778 | flags = hw_perf_save_disable(); |
784 | if (ctx->nr_active) { | 779 | if (ctx->nr_active) { |
@@ -883,12 +878,7 @@ __perf_counter_sched_in(struct perf_counter_context *ctx, | |||
883 | if (likely(!ctx->nr_counters)) | 878 | if (likely(!ctx->nr_counters)) |
884 | goto out; | 879 | goto out; |
885 | 880 | ||
886 | /* | 881 | ctx->timestamp = perf_clock(); |
887 | * Add any time since the last sched_out to the lost time | ||
888 | * so it doesn't get included in the total_time_enabled and | ||
889 | * total_time_running measures for counters in the context. | ||
890 | */ | ||
891 | ctx->time_lost = get_context_time(ctx, 0) - ctx->time_now; | ||
892 | 882 | ||
893 | flags = hw_perf_save_disable(); | 883 | flags = hw_perf_save_disable(); |
894 | 884 | ||
@@ -1043,8 +1033,8 @@ int perf_counter_task_enable(void) | |||
1043 | if (counter->state > PERF_COUNTER_STATE_OFF) | 1033 | if (counter->state > PERF_COUNTER_STATE_OFF) |
1044 | continue; | 1034 | continue; |
1045 | counter->state = PERF_COUNTER_STATE_INACTIVE; | 1035 | counter->state = PERF_COUNTER_STATE_INACTIVE; |
1046 | counter->tstamp_enabled = ctx->time_now - | 1036 | counter->tstamp_enabled = |
1047 | counter->total_time_enabled; | 1037 | ctx->time - counter->total_time_enabled; |
1048 | counter->hw_event.disabled = 0; | 1038 | counter->hw_event.disabled = 0; |
1049 | } | 1039 | } |
1050 | hw_perf_restore(perf_flags); | 1040 | hw_perf_restore(perf_flags); |
@@ -1113,7 +1103,7 @@ static void __read(void *info) | |||
1113 | 1103 | ||
1114 | curr_rq_lock_irq_save(&flags); | 1104 | curr_rq_lock_irq_save(&flags); |
1115 | if (ctx->is_active) | 1105 | if (ctx->is_active) |
1116 | update_context_time(ctx, 1); | 1106 | update_context_time(ctx); |
1117 | counter->hw_ops->read(counter); | 1107 | counter->hw_ops->read(counter); |
1118 | update_counter_times(counter); | 1108 | update_counter_times(counter); |
1119 | curr_rq_unlock_irq_restore(&flags); | 1109 | curr_rq_unlock_irq_restore(&flags); |