diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-12-11 08:59:31 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-12-11 09:45:55 -0500 |
commit | 1d1c7ddbfab358445a542715551301b7fc363e28 (patch) | |
tree | d4421834d109b206f39c2019ea039fd42ed22e1d /kernel | |
parent | bae43c9945ebeef15e7952e317efb02393d3bfc7 (diff) |
perf counters: add prctl interface to disable/enable counters
Add a way for self-monitoring tasks to disable/enable counters summarily,
via a prctl:
PR_TASK_PERF_COUNTERS_DISABLE 31
PR_TASK_PERF_COUNTERS_ENABLE 32
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/perf_counter.c | 86 | ||||
-rw-r--r-- | kernel/sys.c | 7 |
2 files changed, 86 insertions, 7 deletions
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index a0fe8474ee29..4e679b91d8bb 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c | |||
@@ -415,6 +415,9 @@ counter_sched_in(struct perf_counter *counter, | |||
415 | struct perf_counter_context *ctx, | 415 | struct perf_counter_context *ctx, |
416 | int cpu) | 416 | int cpu) |
417 | { | 417 | { |
418 | if (counter->active == -1) | ||
419 | return; | ||
420 | |||
418 | counter->hw_ops->hw_perf_counter_enable(counter); | 421 | counter->hw_ops->hw_perf_counter_enable(counter); |
419 | counter->active = 1; | 422 | counter->active = 1; |
420 | counter->oncpu = cpu; /* TODO: put 'cpu' into cpuctx->cpu */ | 423 | counter->oncpu = cpu; /* TODO: put 'cpu' into cpuctx->cpu */ |
@@ -479,6 +482,79 @@ void perf_counter_task_sched_in(struct task_struct *task, int cpu) | |||
479 | cpuctx->task_ctx = ctx; | 482 | cpuctx->task_ctx = ctx; |
480 | } | 483 | } |
481 | 484 | ||
485 | int perf_counter_task_disable(void) | ||
486 | { | ||
487 | struct task_struct *curr = current; | ||
488 | struct perf_counter_context *ctx = &curr->perf_counter_ctx; | ||
489 | struct perf_counter *counter; | ||
490 | u64 perf_flags; | ||
491 | int cpu; | ||
492 | |||
493 | if (likely(!ctx->nr_counters)) | ||
494 | return 0; | ||
495 | |||
496 | local_irq_disable(); | ||
497 | cpu = smp_processor_id(); | ||
498 | |||
499 | perf_counter_task_sched_out(curr, cpu); | ||
500 | |||
501 | spin_lock(&ctx->lock); | ||
502 | |||
503 | /* | ||
504 | * Disable all the counters: | ||
505 | */ | ||
506 | perf_flags = hw_perf_save_disable(); | ||
507 | |||
508 | list_for_each_entry(counter, &ctx->counter_list, list_entry) { | ||
509 | WARN_ON_ONCE(counter->active == 1); | ||
510 | counter->active = -1; | ||
511 | } | ||
512 | hw_perf_restore(perf_flags); | ||
513 | |||
514 | spin_unlock(&ctx->lock); | ||
515 | |||
516 | local_irq_enable(); | ||
517 | |||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | int perf_counter_task_enable(void) | ||
522 | { | ||
523 | struct task_struct *curr = current; | ||
524 | struct perf_counter_context *ctx = &curr->perf_counter_ctx; | ||
525 | struct perf_counter *counter; | ||
526 | u64 perf_flags; | ||
527 | int cpu; | ||
528 | |||
529 | if (likely(!ctx->nr_counters)) | ||
530 | return 0; | ||
531 | |||
532 | local_irq_disable(); | ||
533 | cpu = smp_processor_id(); | ||
534 | |||
535 | spin_lock(&ctx->lock); | ||
536 | |||
537 | /* | ||
538 | * Disable all the counters: | ||
539 | */ | ||
540 | perf_flags = hw_perf_save_disable(); | ||
541 | |||
542 | list_for_each_entry(counter, &ctx->counter_list, list_entry) { | ||
543 | if (counter->active != -1) | ||
544 | continue; | ||
545 | counter->active = 0; | ||
546 | } | ||
547 | hw_perf_restore(perf_flags); | ||
548 | |||
549 | spin_unlock(&ctx->lock); | ||
550 | |||
551 | perf_counter_task_sched_in(curr, cpu); | ||
552 | |||
553 | local_irq_enable(); | ||
554 | |||
555 | return 0; | ||
556 | } | ||
557 | |||
482 | void perf_counter_task_tick(struct task_struct *curr, int cpu) | 558 | void perf_counter_task_tick(struct task_struct *curr, int cpu) |
483 | { | 559 | { |
484 | struct perf_counter_context *ctx = &curr->perf_counter_ctx; | 560 | struct perf_counter_context *ctx = &curr->perf_counter_ctx; |
@@ -951,13 +1027,9 @@ perf_counter_alloc(struct perf_counter_hw_event *hw_event, | |||
951 | * @cpu: target cpu | 1027 | * @cpu: target cpu |
952 | * @group_fd: group leader counter fd | 1028 | * @group_fd: group leader counter fd |
953 | */ | 1029 | */ |
954 | asmlinkage int sys_perf_counter_open( | 1030 | asmlinkage int |
955 | 1031 | sys_perf_counter_open(struct perf_counter_hw_event *hw_event_uptr __user, | |
956 | struct perf_counter_hw_event *hw_event_uptr __user, | 1032 | pid_t pid, int cpu, int group_fd) |
957 | pid_t pid, | ||
958 | int cpu, | ||
959 | int group_fd) | ||
960 | |||
961 | { | 1033 | { |
962 | struct perf_counter *counter, *group_leader; | 1034 | struct perf_counter *counter, *group_leader; |
963 | struct perf_counter_hw_event hw_event; | 1035 | struct perf_counter_hw_event hw_event; |
diff --git a/kernel/sys.c b/kernel/sys.c index 31deba8f7d16..0f66633be319 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/prctl.h> | 14 | #include <linux/prctl.h> |
15 | #include <linux/highuid.h> | 15 | #include <linux/highuid.h> |
16 | #include <linux/fs.h> | 16 | #include <linux/fs.h> |
17 | #include <linux/perf_counter.h> | ||
17 | #include <linux/resource.h> | 18 | #include <linux/resource.h> |
18 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
19 | #include <linux/kexec.h> | 20 | #include <linux/kexec.h> |
@@ -1716,6 +1717,12 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
1716 | case PR_SET_TSC: | 1717 | case PR_SET_TSC: |
1717 | error = SET_TSC_CTL(arg2); | 1718 | error = SET_TSC_CTL(arg2); |
1718 | break; | 1719 | break; |
1720 | case PR_TASK_PERF_COUNTERS_DISABLE: | ||
1721 | error = perf_counter_task_disable(); | ||
1722 | break; | ||
1723 | case PR_TASK_PERF_COUNTERS_ENABLE: | ||
1724 | error = perf_counter_task_enable(); | ||
1725 | break; | ||
1719 | case PR_GET_TIMERSLACK: | 1726 | case PR_GET_TIMERSLACK: |
1720 | error = current->timer_slack_ns; | 1727 | error = current->timer_slack_ns; |
1721 | break; | 1728 | break; |