aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/perf_counter.h4
-rw-r--r--include/linux/prctl.h3
-rw-r--r--kernel/perf_counter.c86
-rw-r--r--kernel/sys.c7
4 files changed, 93 insertions, 7 deletions
diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h
index 30c0ec8c1ee..97d86c293ee 100644
--- a/include/linux/perf_counter.h
+++ b/include/linux/perf_counter.h
@@ -213,6 +213,8 @@ extern u64 hw_perf_save_disable(void);
213extern void hw_perf_restore(u64 ctrl); 213extern void hw_perf_restore(u64 ctrl);
214extern void atomic64_counter_set(struct perf_counter *counter, u64 val64); 214extern void atomic64_counter_set(struct perf_counter *counter, u64 val64);
215extern u64 atomic64_counter_read(struct perf_counter *counter); 215extern u64 atomic64_counter_read(struct perf_counter *counter);
216extern int perf_counter_task_disable(void);
217extern int perf_counter_task_enable(void);
216 218
217#else 219#else
218static inline void 220static inline void
@@ -226,6 +228,8 @@ static inline void perf_counter_notify(struct pt_regs *regs) { }
226static inline void perf_counter_print_debug(void) { } 228static inline void perf_counter_print_debug(void) { }
227static inline void hw_perf_restore(u64 ctrl) { } 229static inline void hw_perf_restore(u64 ctrl) { }
228static inline u64 hw_perf_save_disable(void) { return 0; } 230static inline u64 hw_perf_save_disable(void) { return 0; }
231static inline int perf_counter_task_disable(void) { return -EINVAL; }
232static inline int perf_counter_task_enable(void) { return -EINVAL; }
229#endif 233#endif
230 234
231#endif /* _LINUX_PERF_COUNTER_H */ 235#endif /* _LINUX_PERF_COUNTER_H */
diff --git a/include/linux/prctl.h b/include/linux/prctl.h
index 48d887e3c6e..b00df4c79c6 100644
--- a/include/linux/prctl.h
+++ b/include/linux/prctl.h
@@ -85,4 +85,7 @@
85#define PR_SET_TIMERSLACK 29 85#define PR_SET_TIMERSLACK 29
86#define PR_GET_TIMERSLACK 30 86#define PR_GET_TIMERSLACK 30
87 87
88#define PR_TASK_PERF_COUNTERS_DISABLE 31
89#define PR_TASK_PERF_COUNTERS_ENABLE 32
90
88#endif /* _LINUX_PRCTL_H */ 91#endif /* _LINUX_PRCTL_H */
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c
index a0fe8474ee2..4e679b91d8b 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 31deba8f7d1..0f66633be31 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;