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/perf_counter.h | |
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/perf_counter.h')
-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 */ |