Commit a3d4fd7a authored by Ingo Molnar's avatar Ingo Molnar

Merge branch 'uprobes/core' of...

Merge branch 'uprobes/core' of git://git.kernel.org/pub/scm/linux/kernel/git/oleg/misc into perf/core

Improve uprobes performance by adding 'pre-filtering' support,
by Oleg Nesterov:

	# time perl -e 'syscall -1 for 1..100_000'
	real    0m0.040s
	user    0m0.027s
	sys     0m0.010s

	# perf probe -x /lib/libc.so.6 syscall
	# perf record -e probe_libc:syscall sleep 100 &

Before this series:

	# time perl -e 'syscall -1 for 1..100_000'
	real    0m1.714s
	user    0m0.103s
	sys     0m1.607s

After:

	# time perl -e 'syscall -1 for 1..100_000'
	real    0m0.037s
	user    0m0.013s
	sys     0m0.023s
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 661e5915 b2fe8ba6
...@@ -680,8 +680,10 @@ static bool __skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) ...@@ -680,8 +680,10 @@ static bool __skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
if (auprobe->insn[i] == 0x66) if (auprobe->insn[i] == 0x66)
continue; continue;
if (auprobe->insn[i] == 0x90) if (auprobe->insn[i] == 0x90) {
regs->ip += i + 1;
return true; return true;
}
break; break;
} }
......
...@@ -135,16 +135,21 @@ struct hw_perf_event { ...@@ -135,16 +135,21 @@ struct hw_perf_event {
struct { /* software */ struct { /* software */
struct hrtimer hrtimer; struct hrtimer hrtimer;
}; };
struct { /* tracepoint */
struct task_struct *tp_target;
/* for tp_event->class */
struct list_head tp_list;
};
#ifdef CONFIG_HAVE_HW_BREAKPOINT #ifdef CONFIG_HAVE_HW_BREAKPOINT
struct { /* breakpoint */ struct { /* breakpoint */
struct arch_hw_breakpoint info;
struct list_head bp_list;
/* /*
* Crufty hack to avoid the chicken and egg * Crufty hack to avoid the chicken and egg
* problem hw_breakpoint has with context * problem hw_breakpoint has with context
* creation and event initalization. * creation and event initalization.
*/ */
struct task_struct *bp_target; struct task_struct *bp_target;
struct arch_hw_breakpoint info;
struct list_head bp_list;
}; };
#endif #endif
}; };
......
...@@ -35,13 +35,20 @@ struct inode; ...@@ -35,13 +35,20 @@ struct inode;
# include <asm/uprobes.h> # include <asm/uprobes.h>
#endif #endif
#define UPROBE_HANDLER_REMOVE 1
#define UPROBE_HANDLER_MASK 1
enum uprobe_filter_ctx {
UPROBE_FILTER_REGISTER,
UPROBE_FILTER_UNREGISTER,
UPROBE_FILTER_MMAP,
};
struct uprobe_consumer { struct uprobe_consumer {
int (*handler)(struct uprobe_consumer *self, struct pt_regs *regs); int (*handler)(struct uprobe_consumer *self, struct pt_regs *regs);
/* bool (*filter)(struct uprobe_consumer *self,
* filter is optional; If a filter exists, handler is run enum uprobe_filter_ctx ctx,
* if and only if filter returns true. struct mm_struct *mm);
*/
bool (*filter)(struct uprobe_consumer *self, struct task_struct *task);
struct uprobe_consumer *next; struct uprobe_consumer *next;
}; };
...@@ -94,6 +101,7 @@ extern int __weak set_swbp(struct arch_uprobe *aup, struct mm_struct *mm, unsign ...@@ -94,6 +101,7 @@ extern int __weak set_swbp(struct arch_uprobe *aup, struct mm_struct *mm, unsign
extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr); extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr);
extern bool __weak is_swbp_insn(uprobe_opcode_t *insn); extern bool __weak is_swbp_insn(uprobe_opcode_t *insn);
extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc);
extern int uprobe_apply(struct inode *inode, loff_t offset, struct uprobe_consumer *uc, bool);
extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc);
extern int uprobe_mmap(struct vm_area_struct *vma); extern int uprobe_mmap(struct vm_area_struct *vma);
extern void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end); extern void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end);
...@@ -117,6 +125,11 @@ uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc) ...@@ -117,6 +125,11 @@ uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc)
{ {
return -ENOSYS; return -ENOSYS;
} }
static inline int
uprobe_apply(struct inode *inode, loff_t offset, struct uprobe_consumer *uc, bool add)
{
return -ENOSYS;
}
static inline void static inline void
uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc) uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc)
{ {
......
...@@ -6162,11 +6162,14 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, ...@@ -6162,11 +6162,14 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
if (task) { if (task) {
event->attach_state = PERF_ATTACH_TASK; event->attach_state = PERF_ATTACH_TASK;
if (attr->type == PERF_TYPE_TRACEPOINT)
event->hw.tp_target = task;
#ifdef CONFIG_HAVE_HW_BREAKPOINT #ifdef CONFIG_HAVE_HW_BREAKPOINT
/* /*
* hw_breakpoint is a bit difficult here.. * hw_breakpoint is a bit difficult here..
*/ */
if (attr->type == PERF_TYPE_BREAKPOINT) else if (attr->type == PERF_TYPE_BREAKPOINT)
event->hw.bp_target = task; event->hw.bp_target = task;
#endif #endif
} }
......
This diff is collapsed.
...@@ -712,6 +712,12 @@ static int ptrace_regset(struct task_struct *task, int req, unsigned int type, ...@@ -712,6 +712,12 @@ static int ptrace_regset(struct task_struct *task, int req, unsigned int type,
kiov->iov_len, kiov->iov_base); kiov->iov_len, kiov->iov_base);
} }
/*
* This is declared in linux/regset.h and defined in machine-dependent
* code. We put the export here, near the primary machine-neutral use,
* to ensure no machine forgets it.
*/
EXPORT_SYMBOL_GPL(task_user_regset_view);
#endif #endif
int ptrace_request(struct task_struct *child, long request, int ptrace_request(struct task_struct *child, long request,
......
...@@ -66,7 +66,6 @@ ...@@ -66,7 +66,6 @@
#define TP_FLAG_TRACE 1 #define TP_FLAG_TRACE 1
#define TP_FLAG_PROFILE 2 #define TP_FLAG_PROFILE 2
#define TP_FLAG_REGISTERED 4 #define TP_FLAG_REGISTERED 4
#define TP_FLAG_UPROBE 8
/* data_rloc: data relative location, compatible with u32 */ /* data_rloc: data relative location, compatible with u32 */
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment