aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/perf_counter.c
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2009-04-06 05:45:10 -0400
committerIngo Molnar <mingo@elte.hu>2009-04-07 04:49:00 -0400
commit4af4998b8aa35600f4c4a4f3c3a23baca6081d02 (patch)
treec980ff7f7c9f21acf873184ec9d63cfb6435a2a5 /kernel/perf_counter.c
parent4c9e25428ff46b968a30f1dfafdba550cb6e4141 (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.c78
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/* 256static 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 */
261static 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 */
274static void update_context_time(struct perf_counter_context *ctx, int update) 264static 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);