diff options
author | Paul Mackerras <paulus@samba.org> | 2009-06-30 02:07:19 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-06-30 06:00:16 -0400 |
commit | 57e7986ed142417498155ebcd5eaf617ac37136d (patch) | |
tree | 81ce9acd79ee7e6383dfd5cdadc4e016a012990e | |
parent | 051ae7f7344f453616b6b10332d4d8e1d40ed823 (diff) |
perf_counter: Provide a way to enable counters on exec
This provides a way to mark a counter to be enabled on the next
exec. This is useful for measuring the total activity of a
program without including overhead from the process that
launches it.
This also changes the perf stat command to use this new
facility.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <19017.43927.838745.689203@cargo.ozlabs.ibm.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | include/linux/perf_counter.h | 3 | ||||
-rw-r--r-- | kernel/perf_counter.c | 50 | ||||
-rw-r--r-- | tools/perf/builtin-stat.c | 6 |
3 files changed, 55 insertions, 4 deletions
diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h index 3078e23c91eb..5e970c7d3fd5 100644 --- a/include/linux/perf_counter.h +++ b/include/linux/perf_counter.h | |||
@@ -179,8 +179,9 @@ struct perf_counter_attr { | |||
179 | comm : 1, /* include comm data */ | 179 | comm : 1, /* include comm data */ |
180 | freq : 1, /* use freq, not period */ | 180 | freq : 1, /* use freq, not period */ |
181 | inherit_stat : 1, /* per task counts */ | 181 | inherit_stat : 1, /* per task counts */ |
182 | enable_on_exec : 1, /* next exec enables */ | ||
182 | 183 | ||
183 | __reserved_1 : 52; | 184 | __reserved_1 : 51; |
184 | 185 | ||
185 | __u32 wakeup_events; /* wakeup every n events */ | 186 | __u32 wakeup_events; /* wakeup every n events */ |
186 | __u32 __reserved_2; | 187 | __u32 __reserved_2; |
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 66ab1e9d1294..d55a50da2347 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c | |||
@@ -1429,6 +1429,53 @@ void perf_counter_task_tick(struct task_struct *curr, int cpu) | |||
1429 | } | 1429 | } |
1430 | 1430 | ||
1431 | /* | 1431 | /* |
1432 | * Enable all of a task's counters that have been marked enable-on-exec. | ||
1433 | * This expects task == current. | ||
1434 | */ | ||
1435 | static void perf_counter_enable_on_exec(struct task_struct *task) | ||
1436 | { | ||
1437 | struct perf_counter_context *ctx; | ||
1438 | struct perf_counter *counter; | ||
1439 | unsigned long flags; | ||
1440 | int enabled = 0; | ||
1441 | |||
1442 | local_irq_save(flags); | ||
1443 | ctx = task->perf_counter_ctxp; | ||
1444 | if (!ctx || !ctx->nr_counters) | ||
1445 | goto out; | ||
1446 | |||
1447 | __perf_counter_task_sched_out(ctx); | ||
1448 | |||
1449 | spin_lock(&ctx->lock); | ||
1450 | |||
1451 | list_for_each_entry(counter, &ctx->counter_list, list_entry) { | ||
1452 | if (!counter->attr.enable_on_exec) | ||
1453 | continue; | ||
1454 | counter->attr.enable_on_exec = 0; | ||
1455 | if (counter->state >= PERF_COUNTER_STATE_INACTIVE) | ||
1456 | continue; | ||
1457 | counter->state = PERF_COUNTER_STATE_INACTIVE; | ||
1458 | counter->tstamp_enabled = | ||
1459 | ctx->time - counter->total_time_enabled; | ||
1460 | enabled = 1; | ||
1461 | } | ||
1462 | |||
1463 | /* | ||
1464 | * Unclone this context if we enabled any counter. | ||
1465 | */ | ||
1466 | if (enabled && ctx->parent_ctx) { | ||
1467 | put_ctx(ctx->parent_ctx); | ||
1468 | ctx->parent_ctx = NULL; | ||
1469 | } | ||
1470 | |||
1471 | spin_unlock(&ctx->lock); | ||
1472 | |||
1473 | perf_counter_task_sched_in(task, smp_processor_id()); | ||
1474 | out: | ||
1475 | local_irq_restore(flags); | ||
1476 | } | ||
1477 | |||
1478 | /* | ||
1432 | * Cross CPU call to read the hardware counter | 1479 | * Cross CPU call to read the hardware counter |
1433 | */ | 1480 | */ |
1434 | static void __perf_counter_read(void *info) | 1481 | static void __perf_counter_read(void *info) |
@@ -2949,6 +2996,9 @@ void perf_counter_comm(struct task_struct *task) | |||
2949 | { | 2996 | { |
2950 | struct perf_comm_event comm_event; | 2997 | struct perf_comm_event comm_event; |
2951 | 2998 | ||
2999 | if (task->perf_counter_ctxp) | ||
3000 | perf_counter_enable_on_exec(task); | ||
3001 | |||
2952 | if (!atomic_read(&nr_comm_counters)) | 3002 | if (!atomic_read(&nr_comm_counters)) |
2953 | return; | 3003 | return; |
2954 | 3004 | ||
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 201ef2367dcb..2e03524a1de0 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -116,8 +116,9 @@ static void create_perf_stat_counter(int counter, int pid) | |||
116 | fd[cpu][counter], strerror(errno)); | 116 | fd[cpu][counter], strerror(errno)); |
117 | } | 117 | } |
118 | } else { | 118 | } else { |
119 | attr->inherit = inherit; | 119 | attr->inherit = inherit; |
120 | attr->disabled = 1; | 120 | attr->disabled = 1; |
121 | attr->enable_on_exec = 1; | ||
121 | 122 | ||
122 | fd[0][counter] = sys_perf_counter_open(attr, pid, -1, -1, 0); | 123 | fd[0][counter] = sys_perf_counter_open(attr, pid, -1, -1, 0); |
123 | if (fd[0][counter] < 0 && verbose) | 124 | if (fd[0][counter] < 0 && verbose) |
@@ -262,7 +263,6 @@ static int run_perf_stat(int argc, const char **argv) | |||
262 | * Enable counters and exec the command: | 263 | * Enable counters and exec the command: |
263 | */ | 264 | */ |
264 | t0 = rdclock(); | 265 | t0 = rdclock(); |
265 | prctl(PR_TASK_PERF_COUNTERS_ENABLE); | ||
266 | 266 | ||
267 | close(go_pipe[1]); | 267 | close(go_pipe[1]); |
268 | wait(&status); | 268 | wait(&status); |