diff options
author | Srinivasa D S <srinivasa@in.ibm.com> | 2008-07-25 04:46:04 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-25 13:53:30 -0400 |
commit | ef53d9c5e4da147ecaa43c44c5e5945eb83970a2 (patch) | |
tree | 3b596445e5d0613fda4b33a4ae96e0e3fffdcf1e /include/linux/kprobes.h | |
parent | 53a9600c634e3bfd6230e0597aca159bf4d4d010 (diff) |
kprobes: improve kretprobe scalability with hashed locking
Currently list of kretprobe instances are stored in kretprobe object (as
used_instances,free_instances) and in kretprobe hash table. We have one
global kretprobe lock to serialise the access to these lists. This causes
only one kretprobe handler to execute at a time. Hence affects system
performance, particularly on SMP systems and when return probe is set on
lot of functions (like on all systemcalls).
Solution proposed here gives fine-grain locks that performs better on SMP
system compared to present kretprobe implementation.
Solution:
1) Instead of having one global lock to protect kretprobe instances
present in kretprobe object and kretprobe hash table. We will have
two locks, one lock for protecting kretprobe hash table and another
lock for kretporbe object.
2) We hold lock present in kretprobe object while we modify kretprobe
instance in kretprobe object and we hold per-hash-list lock while
modifying kretprobe instances present in that hash list. To prevent
deadlock, we never grab a per-hash-list lock while holding a kretprobe
lock.
3) We can remove used_instances from struct kretprobe, as we can
track used instances of kretprobe instances using kretprobe hash
table.
Time duration for kernel compilation ("make -j 8") on a 8-way ppc64 system
with return probes set on all systemcalls looks like this.
cacheline non-cacheline Un-patched kernel
aligned patch aligned patch
===============================================================================
real 9m46.784s 9m54.412s 10m2.450s
user 40m5.715s 40m7.142s 40m4.273s
sys 2m57.754s 2m58.583s 3m17.430s
===========================================================
Time duration for kernel compilation ("make -j 8) on the same system, when
kernel is not probed.
=========================
real 9m26.389s
user 40m8.775s
sys 2m7.283s
=========================
Signed-off-by: Srinivasa DS <srinivasa@in.ibm.com>
Signed-off-by: Jim Keniston <jkenisto@us.ibm.com>
Acked-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
Cc: David S. Miller <davem@davemloft.net>
Cc: Masami Hiramatsu <mhiramat@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include/linux/kprobes.h')
-rw-r--r-- | include/linux/kprobes.h | 7 |
1 files changed, 4 insertions, 3 deletions
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h index 04a3556bdea6..0be7795655fa 100644 --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h | |||
@@ -157,11 +157,10 @@ struct kretprobe { | |||
157 | int nmissed; | 157 | int nmissed; |
158 | size_t data_size; | 158 | size_t data_size; |
159 | struct hlist_head free_instances; | 159 | struct hlist_head free_instances; |
160 | struct hlist_head used_instances; | 160 | spinlock_t lock; |
161 | }; | 161 | }; |
162 | 162 | ||
163 | struct kretprobe_instance { | 163 | struct kretprobe_instance { |
164 | struct hlist_node uflist; /* either on free list or used list */ | ||
165 | struct hlist_node hlist; | 164 | struct hlist_node hlist; |
166 | struct kretprobe *rp; | 165 | struct kretprobe *rp; |
167 | kprobe_opcode_t *ret_addr; | 166 | kprobe_opcode_t *ret_addr; |
@@ -201,7 +200,6 @@ static inline int init_test_probes(void) | |||
201 | } | 200 | } |
202 | #endif /* CONFIG_KPROBES_SANITY_TEST */ | 201 | #endif /* CONFIG_KPROBES_SANITY_TEST */ |
203 | 202 | ||
204 | extern spinlock_t kretprobe_lock; | ||
205 | extern struct mutex kprobe_mutex; | 203 | extern struct mutex kprobe_mutex; |
206 | extern int arch_prepare_kprobe(struct kprobe *p); | 204 | extern int arch_prepare_kprobe(struct kprobe *p); |
207 | extern void arch_arm_kprobe(struct kprobe *p); | 205 | extern void arch_arm_kprobe(struct kprobe *p); |
@@ -214,6 +212,9 @@ extern void kprobes_inc_nmissed_count(struct kprobe *p); | |||
214 | 212 | ||
215 | /* Get the kprobe at this addr (if any) - called with preemption disabled */ | 213 | /* Get the kprobe at this addr (if any) - called with preemption disabled */ |
216 | struct kprobe *get_kprobe(void *addr); | 214 | struct kprobe *get_kprobe(void *addr); |
215 | void kretprobe_hash_lock(struct task_struct *tsk, | ||
216 | struct hlist_head **head, unsigned long *flags); | ||
217 | void kretprobe_hash_unlock(struct task_struct *tsk, unsigned long *flags); | ||
217 | struct hlist_head * kretprobe_inst_table_head(struct task_struct *tsk); | 218 | struct hlist_head * kretprobe_inst_table_head(struct task_struct *tsk); |
218 | 219 | ||
219 | /* kprobe_running() will just return the current_kprobe on this CPU */ | 220 | /* kprobe_running() will just return the current_kprobe on this CPU */ |