Commit 1b5180b6 authored by Ingo Molnar's avatar Ingo Molnar Committed by Linus Torvalds

[PATCH] notifiers: fix blocking_notifier_call_chain() scalability

while lock-profiling the -rt kernel i noticed weird contention during
mmap-intense workloads, and the tracer showed the following gem, in one
of our MM hotpaths:

 threaded-2771  1....   65us : sys_munmap (sysenter_do_call)
 threaded-2771  1....   66us : profile_munmap (sys_munmap)
 threaded-2771  1....   66us : blocking_notifier_call_chain (profile_munmap)
 threaded-2771  1....   66us : rt_down_read (blocking_notifier_call_chain)

ouch! a global rw-semaphore taken in one of the most performance-
sensitive codepaths of the kernel.  And i dont even have oprofile
enabled! All distro kernels have CONFIG_PROFILING enabled, so this
scalability problem affects the majority of Linux users.

The fix is to enhance blocking_notifier_call_chain() to only take the
lock if there appears to be work on the call-chain.

With this patch applied i get nicely saturated system, and much higher
munmap performance, on SMP systems.

And as a bonus this also fixes a similar scalability bottleneck in the
thread-exit codepath: profile_task_exit() ...
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Acked-by: default avatarPeter Zijlstra <a.p.zijlstra@chello.nl>
Acked-by: default avatarNick Piggin <nickpiggin@yahoo.com.au>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent b53d0b91
...@@ -323,11 +323,18 @@ EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister); ...@@ -323,11 +323,18 @@ EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister);
int blocking_notifier_call_chain(struct blocking_notifier_head *nh, int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
unsigned long val, void *v) unsigned long val, void *v)
{ {
int ret; int ret = NOTIFY_DONE;
down_read(&nh->rwsem); /*
ret = notifier_call_chain(&nh->head, val, v); * We check the head outside the lock, but if this access is
up_read(&nh->rwsem); * racy then it does not matter what the result of the test
* is, we re-check the list after having taken the lock anyway:
*/
if (rcu_dereference(nh->head)) {
down_read(&nh->rwsem);
ret = notifier_call_chain(&nh->head, val, v);
up_read(&nh->rwsem);
}
return ret; return ret;
} }
......
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