aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-12-11 08:59:31 -0500
committerIngo Molnar <mingo@elte.hu>2008-12-11 09:45:55 -0500
commit1d1c7ddbfab358445a542715551301b7fc363e28 (patch)
treed4421834d109b206f39c2019ea039fd42ed22e1d /kernel
parentbae43c9945ebeef15e7952e317efb02393d3bfc7 (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.c86
-rw-r--r--kernel/sys.c7
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
485int 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
521int 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
482void perf_counter_task_tick(struct task_struct *curr, int cpu) 558void 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 */
954asmlinkage int sys_perf_counter_open( 1030asmlinkage int
955 1031sys_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;