mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-28 09:31:14 +00:00
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>
This commit is contained in:
parent
4b77a72977
commit
5622f295b5
3 changed files with 268 additions and 176 deletions
|
@ -691,6 +691,17 @@ struct perf_cpu_context {
|
|||
int recursion[4];
|
||||
};
|
||||
|
||||
struct perf_output_handle {
|
||||
struct perf_counter *counter;
|
||||
struct perf_mmap_data *data;
|
||||
unsigned long head;
|
||||
unsigned long offset;
|
||||
int nmi;
|
||||
int sample;
|
||||
int locked;
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PERF_COUNTERS
|
||||
|
||||
/*
|
||||
|
@ -722,16 +733,38 @@ extern int hw_perf_group_sched_in(struct perf_counter *group_leader,
|
|||
extern void perf_counter_update_userpage(struct perf_counter *counter);
|
||||
|
||||
struct perf_sample_data {
|
||||
struct pt_regs *regs;
|
||||
u64 type;
|
||||
|
||||
u64 ip;
|
||||
struct {
|
||||
u32 pid;
|
||||
u32 tid;
|
||||
} tid_entry;
|
||||
u64 time;
|
||||
u64 addr;
|
||||
u64 id;
|
||||
u64 stream_id;
|
||||
struct {
|
||||
u32 cpu;
|
||||
u32 reserved;
|
||||
} cpu_entry;
|
||||
u64 period;
|
||||
struct perf_callchain_entry *callchain;
|
||||
struct perf_raw_record *raw;
|
||||
};
|
||||
|
||||
extern void perf_output_sample(struct perf_output_handle *handle,
|
||||
struct perf_event_header *header,
|
||||
struct perf_sample_data *data,
|
||||
struct perf_counter *counter);
|
||||
extern void perf_prepare_sample(struct perf_event_header *header,
|
||||
struct perf_sample_data *data,
|
||||
struct perf_counter *counter,
|
||||
struct pt_regs *regs);
|
||||
|
||||
extern int perf_counter_overflow(struct perf_counter *counter, int nmi,
|
||||
struct perf_sample_data *data);
|
||||
extern void perf_counter_output(struct perf_counter *counter, int nmi,
|
||||
struct perf_sample_data *data);
|
||||
struct perf_sample_data *data,
|
||||
struct pt_regs *regs);
|
||||
|
||||
/*
|
||||
* 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,
|
|||
#define perf_instruction_pointer(regs) instruction_pointer(regs)
|
||||
#endif
|
||||
|
||||
extern int perf_output_begin(struct perf_output_handle *handle,
|
||||
struct perf_counter *counter, unsigned int size,
|
||||
int nmi, int sample);
|
||||
extern void perf_output_end(struct perf_output_handle *handle);
|
||||
extern void perf_output_copy(struct perf_output_handle *handle,
|
||||
const void *buf, unsigned int len);
|
||||
#else
|
||||
static inline void
|
||||
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) { }
|
|||
static inline void perf_counter_comm(struct task_struct *tsk) { }
|
||||
static inline void perf_counter_fork(struct task_struct *tsk) { }
|
||||
static inline void perf_counter_init(void) { }
|
||||
|
||||
static inline int
|
||||
perf_output_begin(struct perf_output_handle *handle, struct perf_counter *c,
|
||||
unsigned int size, int nmi, int sample) { }
|
||||
static inline void perf_output_end(struct perf_output_handle *handle) { }
|
||||
static inline void
|
||||
perf_output_copy(struct perf_output_handle *handle,
|
||||
const void *buf, unsigned int len) { }
|
||||
static inline void
|
||||
perf_output_sample(struct perf_output_handle *handle,
|
||||
struct perf_event_header *header,
|
||||
struct perf_sample_data *data,
|
||||
struct perf_counter *counter) { }
|
||||
static inline void
|
||||
perf_prepare_sample(struct perf_event_header *header,
|
||||
struct perf_sample_data *data,
|
||||
struct perf_counter *counter,
|
||||
struct pt_regs *regs) { }
|
||||
#endif
|
||||
|
||||
#define perf_output_put(handle, x) \
|
||||
perf_output_copy((handle), &(x), sizeof(x))
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* _LINUX_PERF_COUNTER_H */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue