Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 18 Feb 2002 11:12:16 -0800 (PST)
From:      Matthew Dillon <dillon@apollo.backplane.com>
To:        current@freebsd.org
Subject:   Patch to improve mutex collision performance
Message-ID:  <200202181912.g1IJCGK32122@apollo.backplane.com>

next in thread | raw e-mail | index | archive | help
    While testing some Giant removal stuff I noticed that my current
    system sometimes got into an extremely non-optimal flip-flop situation
    between two processes contesting Giant on an SMP system which halved the
    syscall performance in the test.

    In my getuid test, for example, with Giant in place I was getting
    683Kcalls/sec with one process and 427Kcalls/sec with two.  Giant
    was being obtained in two places: in userret and in getuid().

    When I turned off Giant in getuid() the syscall performance actually
    went DOWN, to 250Kcalls/sec with two processes.  This was a totally
    unexpected result.

    It turns out that the two processes got into an extremely non-optimal 
    contested/sleep/wakeup situation, even though they do not actually have
    to sleep on Giant in this situation.

    The solution is to allow _mtx_lock_sleep() to spin instead of sleep in
    the situation where:  (1) there are no runnable processes other then
    the ones already running on a cpu, (2) interrupts are enabled, and 
    (3) the mutex in question is not contested (to avoid starving the thread
    contesting the mutex).  In this case we can spin.

    This will go in tonight if no problems arise.

							-Matt

Index: kern/kern_mutex.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_mutex.c,v
retrieving revision 1.80
diff -u -r1.80 kern_mutex.c
--- kern/kern_mutex.c	18 Feb 2002 17:51:47 -0000	1.80
+++ kern/kern_mutex.c	18 Feb 2002 19:11:17 -0000
@@ -287,7 +287,9 @@
 _mtx_lock_sleep(struct mtx *m, int opts, const char *file, int line)
 {
 	struct thread *td = curthread;
+#if 0
 	struct ksegrp *kg = td->td_ksegrp;
+#endif
 
 	if ((m->mtx_lock & MTX_FLAGMASK) == (uintptr_t)td) {
 		m->mtx_recurse++;
@@ -312,6 +314,22 @@
 		 * the sched_lock.
 		 */
 		if ((v = m->mtx_lock) == MTX_UNOWNED) {
			mtx_unlock_spin(&sched_lock);
			continue;
		}
+
+		/*
+		 * Check to see if there are any runnable processes.  If
+		 * there aren't and nobody is contesting the mutex (to avoid
+		 * starving a contester) and interrupts are enabled, then
+		 * we can safely spin.
+		 *
+		 * This prevents a silly-sleep-flip-flop situation on SMP
+		 * systems where two running processes need Giant (or any
+		 * other sleep mutex).
+		 */
+		if (td->td_critnest == 0 && (v & MTX_CONTESTED) == 0 &&
+		    procrunnable() == 0) {
+ 			mtx_unlock_spin(&sched_lock);
+ 			continue;
+ 		}

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200202181912.g1IJCGK32122>