diff options
| author | Markus Metzger <markus.t.metzger@intel.com> | 2009-09-15 07:00:23 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2009-09-18 14:43:20 -0400 |
| commit | 5622f295b53fb60dbf9bed3e2c89d182490a8b7f (patch) | |
| tree | 8279554bddd1607d53dc06e97f4b5a1d0c085ccd /include/linux | |
| parent | 4b77a7297795229eca96c41e1709a3c87909fabe (diff) | |
x86, perf_counter, bts: Optimize BTS overflow handling
Draining the BTS buffer on a buffer overflow interrupt takes too
long resulting in a kernel lockup when tracing the kernel.
Restructure perf_counter sampling into sample creation and sample
output.
Prepare a single reference sample for BTS sampling and update the
from and to address fields when draining the BTS buffer. Drain the
entire BTS buffer between a single perf_output_begin() /
perf_output_end() pair.
Signed-off-by: Markus Metzger <markus.t.metzger@intel.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <20090915130023.A16204@sedona.ch.intel.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/perf_counter.h | 68 |
1 files changed, 64 insertions, 4 deletions
diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h index 6c1ef72ea501..c7375f97aa19 100644 --- a/include/linux/perf_counter.h +++ b/include/linux/perf_counter.h | |||
| @@ -691,6 +691,17 @@ struct perf_cpu_context { | |||
| 691 | int recursion[4]; | 691 | int recursion[4]; |
| 692 | }; | 692 | }; |
| 693 | 693 | ||
| 694 | struct perf_output_handle { | ||
| 695 | struct perf_counter *counter; | ||
| 696 | struct perf_mmap_data *data; | ||
| 697 | unsigned long head; | ||
| 698 | unsigned long offset; | ||
| 699 | int nmi; | ||
| 700 | int sample; | ||
| 701 | int locked; | ||
| 702 | unsigned long flags; | ||
| 703 | }; | ||
| 704 | |||
| 694 | #ifdef CONFIG_PERF_COUNTERS | 705 | #ifdef CONFIG_PERF_COUNTERS |
| 695 | 706 | ||
| 696 | /* | 707 | /* |
| @@ -722,16 +733,38 @@ extern int hw_perf_group_sched_in(struct perf_counter *group_leader, | |||
| 722 | extern void perf_counter_update_userpage(struct perf_counter *counter); | 733 | extern void perf_counter_update_userpage(struct perf_counter *counter); |
| 723 | 734 | ||
| 724 | struct perf_sample_data { | 735 | struct perf_sample_data { |
| 725 | struct pt_regs *regs; | 736 | u64 type; |
| 737 | |||
| 738 | u64 ip; | ||
| 739 | struct { | ||
| 740 | u32 pid; | ||
| 741 | u32 tid; | ||
| 742 | } tid_entry; | ||
| 743 | u64 time; | ||
| 726 | u64 addr; | 744 | u64 addr; |
| 745 | u64 id; | ||
| 746 | u64 stream_id; | ||
| 747 | struct { | ||
| 748 | u32 cpu; | ||
| 749 | u32 reserved; | ||
| 750 | } cpu_entry; | ||
| 727 | u64 period; | 751 | u64 period; |
| 752 | struct perf_callchain_entry *callchain; | ||
| 728 | struct perf_raw_record *raw; | 753 | struct perf_raw_record *raw; |
| 729 | }; | 754 | }; |
| 730 | 755 | ||
| 756 | extern void perf_output_sample(struct perf_output_handle *handle, | ||
| 757 | struct perf_event_header *header, | ||
| 758 | struct perf_sample_data *data, | ||
| 759 | struct perf_counter *counter); | ||
| 760 | extern void perf_prepare_sample(struct perf_event_header *header, | ||
| 761 | struct perf_sample_data *data, | ||
| 762 | struct perf_counter *counter, | ||
| 763 | struct pt_regs *regs); | ||
| 764 | |||
| 731 | extern int perf_counter_overflow(struct perf_counter *counter, int nmi, | 765 | extern int perf_counter_overflow(struct perf_counter *counter, int nmi, |
| 732 | struct perf_sample_data *data); | 766 | struct perf_sample_data *data, |
| 733 | extern void perf_counter_output(struct perf_counter *counter, int nmi, | 767 | struct pt_regs *regs); |
| 734 | struct perf_sample_data *data); | ||
| 735 | 768 | ||
| 736 | /* | 769 | /* |
| 737 | * Return 1 for a software counter, 0 for a hardware counter | 770 | * Return 1 for a software counter, 0 for a hardware counter |
| @@ -781,6 +814,12 @@ extern void perf_tpcounter_event(int event_id, u64 addr, u64 count, | |||
| 781 | #define perf_instruction_pointer(regs) instruction_pointer(regs) | 814 | #define perf_instruction_pointer(regs) instruction_pointer(regs) |
| 782 | #endif | 815 | #endif |
| 783 | 816 | ||
| 817 | extern int perf_output_begin(struct perf_output_handle *handle, | ||
| 818 | struct perf_counter *counter, unsigned int size, | ||
| 819 | int nmi, int sample); | ||
| 820 | extern void perf_output_end(struct perf_output_handle *handle); | ||
| 821 | extern void perf_output_copy(struct perf_output_handle *handle, | ||
| 822 | const void *buf, unsigned int len); | ||
| 784 | #else | 823 | #else |
| 785 | static inline void | 824 | static inline void |
| 786 | perf_counter_task_sched_in(struct task_struct *task, int cpu) { } | 825 | perf_counter_task_sched_in(struct task_struct *task, int cpu) { } |
| @@ -807,7 +846,28 @@ static inline void perf_counter_mmap(struct vm_area_struct *vma) { } | |||
| 807 | static inline void perf_counter_comm(struct task_struct *tsk) { } | 846 | static inline void perf_counter_comm(struct task_struct *tsk) { } |
| 808 | static inline void perf_counter_fork(struct task_struct *tsk) { } | 847 | static inline void perf_counter_fork(struct task_struct *tsk) { } |
| 809 | static inline void perf_counter_init(void) { } | 848 | static inline void perf_counter_init(void) { } |
| 849 | |||
| 850 | static inline int | ||
| 851 | perf_output_begin(struct perf_output_handle *handle, struct perf_counter *c, | ||
| 852 | unsigned int size, int nmi, int sample) { } | ||
| 853 | static inline void perf_output_end(struct perf_output_handle *handle) { } | ||
| 854 | static inline void | ||
| 855 | perf_output_copy(struct perf_output_handle *handle, | ||
| 856 | const void *buf, unsigned int len) { } | ||
| 857 | static inline void | ||
| 858 | perf_output_sample(struct perf_output_handle *handle, | ||
| 859 | struct perf_event_header *header, | ||
| 860 | struct perf_sample_data *data, | ||
| 861 | struct perf_counter *counter) { } | ||
| 862 | static inline void | ||
| 863 | perf_prepare_sample(struct perf_event_header *header, | ||
| 864 | struct perf_sample_data *data, | ||
| 865 | struct perf_counter *counter, | ||
| 866 | struct pt_regs *regs) { } | ||
| 810 | #endif | 867 | #endif |
| 811 | 868 | ||
| 869 | #define perf_output_put(handle, x) \ | ||
| 870 | perf_output_copy((handle), &(x), sizeof(x)) | ||
| 871 | |||
| 812 | #endif /* __KERNEL__ */ | 872 | #endif /* __KERNEL__ */ |
| 813 | #endif /* _LINUX_PERF_COUNTER_H */ | 873 | #endif /* _LINUX_PERF_COUNTER_H */ |
