diff options
author | David S. Miller <davem@davemloft.net> | 2009-09-30 00:27:06 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-09-30 00:27:06 -0400 |
commit | d17513889a8b754c5872b6b46e6f7822338a0b79 (patch) | |
tree | ddf3d70d4bb3c0a565b4d229cb7cd204c13edb6b /arch/sparc/kernel/perf_event.c | |
parent | 6e804251d119bbd5522d76bdb0f48f5c9a7abf51 (diff) |
sparc64: Cache per-cpu %pcr register value in perf code.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/kernel/perf_event.c')
-rw-r--r-- | arch/sparc/kernel/perf_event.c | 59 |
1 files changed, 42 insertions, 17 deletions
diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c index 32fc974bf8b5..04db92743896 100644 --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c | |||
@@ -56,7 +56,8 @@ struct cpu_hw_events { | |||
56 | struct perf_event *events[MAX_HWEVENTS]; | 56 | struct perf_event *events[MAX_HWEVENTS]; |
57 | unsigned long used_mask[BITS_TO_LONGS(MAX_HWEVENTS)]; | 57 | unsigned long used_mask[BITS_TO_LONGS(MAX_HWEVENTS)]; |
58 | unsigned long active_mask[BITS_TO_LONGS(MAX_HWEVENTS)]; | 58 | unsigned long active_mask[BITS_TO_LONGS(MAX_HWEVENTS)]; |
59 | int enabled; | 59 | u64 pcr; |
60 | int enabled; | ||
60 | }; | 61 | }; |
61 | DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { .enabled = 1, }; | 62 | DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { .enabled = 1, }; |
62 | 63 | ||
@@ -464,21 +465,30 @@ static u64 nop_for_index(int idx) | |||
464 | sparc_pmu->lower_nop, idx); | 465 | sparc_pmu->lower_nop, idx); |
465 | } | 466 | } |
466 | 467 | ||
467 | static inline void sparc_pmu_enable_event(struct hw_perf_event *hwc, int idx) | 468 | static inline void sparc_pmu_enable_event(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc, int idx) |
468 | { | 469 | { |
469 | u64 val, mask = mask_for_index(idx); | 470 | u64 val, mask = mask_for_index(idx); |
470 | 471 | ||
471 | val = pcr_ops->read(); | 472 | val = cpuc->pcr; |
472 | pcr_ops->write((val & ~mask) | hwc->config); | 473 | val &= ~mask; |
474 | val |= hwc->config; | ||
475 | cpuc->pcr = val; | ||
476 | |||
477 | pcr_ops->write(cpuc->pcr); | ||
473 | } | 478 | } |
474 | 479 | ||
475 | static inline void sparc_pmu_disable_event(struct hw_perf_event *hwc, int idx) | 480 | static inline void sparc_pmu_disable_event(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc, int idx) |
476 | { | 481 | { |
477 | u64 mask = mask_for_index(idx); | 482 | u64 mask = mask_for_index(idx); |
478 | u64 nop = nop_for_index(idx); | 483 | u64 nop = nop_for_index(idx); |
479 | u64 val = pcr_ops->read(); | 484 | u64 val; |
480 | 485 | ||
481 | pcr_ops->write((val & ~mask) | nop); | 486 | val = cpuc->pcr; |
487 | val &= ~mask; | ||
488 | val |= nop; | ||
489 | cpuc->pcr = val; | ||
490 | |||
491 | pcr_ops->write(cpuc->pcr); | ||
482 | } | 492 | } |
483 | 493 | ||
484 | void hw_perf_enable(void) | 494 | void hw_perf_enable(void) |
@@ -493,7 +503,7 @@ void hw_perf_enable(void) | |||
493 | cpuc->enabled = 1; | 503 | cpuc->enabled = 1; |
494 | barrier(); | 504 | barrier(); |
495 | 505 | ||
496 | val = pcr_ops->read(); | 506 | val = cpuc->pcr; |
497 | 507 | ||
498 | for (i = 0; i < MAX_HWEVENTS; i++) { | 508 | for (i = 0; i < MAX_HWEVENTS; i++) { |
499 | struct perf_event *cp = cpuc->events[i]; | 509 | struct perf_event *cp = cpuc->events[i]; |
@@ -505,7 +515,9 @@ void hw_perf_enable(void) | |||
505 | val |= hwc->config_base; | 515 | val |= hwc->config_base; |
506 | } | 516 | } |
507 | 517 | ||
508 | pcr_ops->write(val); | 518 | cpuc->pcr = val; |
519 | |||
520 | pcr_ops->write(cpuc->pcr); | ||
509 | } | 521 | } |
510 | 522 | ||
511 | void hw_perf_disable(void) | 523 | void hw_perf_disable(void) |
@@ -518,10 +530,12 @@ void hw_perf_disable(void) | |||
518 | 530 | ||
519 | cpuc->enabled = 0; | 531 | cpuc->enabled = 0; |
520 | 532 | ||
521 | val = pcr_ops->read(); | 533 | val = cpuc->pcr; |
522 | val &= ~(PCR_UTRACE | PCR_STRACE | | 534 | val &= ~(PCR_UTRACE | PCR_STRACE | |
523 | sparc_pmu->hv_bit | sparc_pmu->irq_bit); | 535 | sparc_pmu->hv_bit | sparc_pmu->irq_bit); |
524 | pcr_ops->write(val); | 536 | cpuc->pcr = val; |
537 | |||
538 | pcr_ops->write(cpuc->pcr); | ||
525 | } | 539 | } |
526 | 540 | ||
527 | static u32 read_pmc(int idx) | 541 | static u32 read_pmc(int idx) |
@@ -593,13 +607,13 @@ static int sparc_pmu_enable(struct perf_event *event) | |||
593 | if (test_and_set_bit(idx, cpuc->used_mask)) | 607 | if (test_and_set_bit(idx, cpuc->used_mask)) |
594 | return -EAGAIN; | 608 | return -EAGAIN; |
595 | 609 | ||
596 | sparc_pmu_disable_event(hwc, idx); | 610 | sparc_pmu_disable_event(cpuc, hwc, idx); |
597 | 611 | ||
598 | cpuc->events[idx] = event; | 612 | cpuc->events[idx] = event; |
599 | set_bit(idx, cpuc->active_mask); | 613 | set_bit(idx, cpuc->active_mask); |
600 | 614 | ||
601 | sparc_perf_event_set_period(event, hwc, idx); | 615 | sparc_perf_event_set_period(event, hwc, idx); |
602 | sparc_pmu_enable_event(hwc, idx); | 616 | sparc_pmu_enable_event(cpuc, hwc, idx); |
603 | perf_event_update_userpage(event); | 617 | perf_event_update_userpage(event); |
604 | return 0; | 618 | return 0; |
605 | } | 619 | } |
@@ -635,7 +649,7 @@ static void sparc_pmu_disable(struct perf_event *event) | |||
635 | int idx = hwc->idx; | 649 | int idx = hwc->idx; |
636 | 650 | ||
637 | clear_bit(idx, cpuc->active_mask); | 651 | clear_bit(idx, cpuc->active_mask); |
638 | sparc_pmu_disable_event(hwc, idx); | 652 | sparc_pmu_disable_event(cpuc, hwc, idx); |
639 | 653 | ||
640 | barrier(); | 654 | barrier(); |
641 | 655 | ||
@@ -649,18 +663,29 @@ static void sparc_pmu_disable(struct perf_event *event) | |||
649 | static void sparc_pmu_read(struct perf_event *event) | 663 | static void sparc_pmu_read(struct perf_event *event) |
650 | { | 664 | { |
651 | struct hw_perf_event *hwc = &event->hw; | 665 | struct hw_perf_event *hwc = &event->hw; |
666 | |||
652 | sparc_perf_event_update(event, hwc, hwc->idx); | 667 | sparc_perf_event_update(event, hwc, hwc->idx); |
653 | } | 668 | } |
654 | 669 | ||
655 | static void sparc_pmu_unthrottle(struct perf_event *event) | 670 | static void sparc_pmu_unthrottle(struct perf_event *event) |
656 | { | 671 | { |
672 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | ||
657 | struct hw_perf_event *hwc = &event->hw; | 673 | struct hw_perf_event *hwc = &event->hw; |
658 | sparc_pmu_enable_event(hwc, hwc->idx); | 674 | |
675 | sparc_pmu_enable_event(cpuc, hwc, hwc->idx); | ||
659 | } | 676 | } |
660 | 677 | ||
661 | static atomic_t active_events = ATOMIC_INIT(0); | 678 | static atomic_t active_events = ATOMIC_INIT(0); |
662 | static DEFINE_MUTEX(pmc_grab_mutex); | 679 | static DEFINE_MUTEX(pmc_grab_mutex); |
663 | 680 | ||
681 | static void perf_stop_nmi_watchdog(void *unused) | ||
682 | { | ||
683 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | ||
684 | |||
685 | stop_nmi_watchdog(NULL); | ||
686 | cpuc->pcr = pcr_ops->read(); | ||
687 | } | ||
688 | |||
664 | void perf_event_grab_pmc(void) | 689 | void perf_event_grab_pmc(void) |
665 | { | 690 | { |
666 | if (atomic_inc_not_zero(&active_events)) | 691 | if (atomic_inc_not_zero(&active_events)) |
@@ -669,7 +694,7 @@ void perf_event_grab_pmc(void) | |||
669 | mutex_lock(&pmc_grab_mutex); | 694 | mutex_lock(&pmc_grab_mutex); |
670 | if (atomic_read(&active_events) == 0) { | 695 | if (atomic_read(&active_events) == 0) { |
671 | if (atomic_read(&nmi_active) > 0) { | 696 | if (atomic_read(&nmi_active) > 0) { |
672 | on_each_cpu(stop_nmi_watchdog, NULL, 1); | 697 | on_each_cpu(perf_stop_nmi_watchdog, NULL, 1); |
673 | BUG_ON(atomic_read(&nmi_active) != 0); | 698 | BUG_ON(atomic_read(&nmi_active) != 0); |
674 | } | 699 | } |
675 | atomic_inc(&active_events); | 700 | atomic_inc(&active_events); |
@@ -978,7 +1003,7 @@ static int __kprobes perf_event_nmi_handler(struct notifier_block *self, | |||
978 | continue; | 1003 | continue; |
979 | 1004 | ||
980 | if (perf_event_overflow(event, 1, &data, regs)) | 1005 | if (perf_event_overflow(event, 1, &data, regs)) |
981 | sparc_pmu_disable_event(hwc, idx); | 1006 | sparc_pmu_disable_event(cpuc, hwc, idx); |
982 | } | 1007 | } |
983 | 1008 | ||
984 | return NOTIFY_STOP; | 1009 | return NOTIFY_STOP; |