Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 20 Feb 2018 02:18:30 +0000 (UTC)
From:      Mateusz Guzik <mjg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r329615 - head/sys/kern
Message-ID:  <201802200218.w1K2IU4r098041@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mjg
Date: Tue Feb 20 02:18:30 2018
New Revision: 329615
URL: https://svnweb.freebsd.org/changeset/base/329615

Log:
  Reduce contention on the proctree lock during heavy package build.
  
  There is a proctree -> allproc ordering established.
  
  Most of the time it is either xlock -> xlock or slock -> slock.
  
  On fork however there is a slock -> xlock pair which results in
  pathological wait times due to threads keeping proctree held for
  reading and all waiting on allproc. Switch this to xlock -> xlock.
  Longer term fix would get rid of proctree in this place to begin with.
  Right now it is necessary to walk the session/process group lists to
  determine which id is free. The walk can be avoided e.g. with bitmaps.
  
  The exit path used to have one place which dealt with allproc and
  then with proctree. Move the allproc acquire into the section protected
  by proctree. This reduces contention against threads waiting on proctree
  in the fork codepath - the fork proctree holder does not have to wait
  for allproc as often.
  
  Finally, move tidhash manipulation outside of the area protected by
  either of these locks. The removal from the hash was already unprotected.
  There is no legitimate reason to look up thread ids for a process still
  under construction.
  
  This results in about 50% wait time reduction during -j 128 package build.

Modified:
  head/sys/kern/kern_exit.c
  head/sys/kern/kern_fork.c

Modified: head/sys/kern/kern_exit.c
==============================================================================
--- head/sys/kern/kern_exit.c	Tue Feb 20 02:03:29 2018	(r329614)
+++ head/sys/kern/kern_exit.c	Tue Feb 20 02:18:30 2018	(r329615)
@@ -424,16 +424,6 @@ exit1(struct thread *td, int rval, int signo)
 	tidhash_remove(td);
 
 	/*
-	 * Remove proc from allproc queue and pidhash chain.
-	 * Place onto zombproc.  Unlink from parent's child list.
-	 */
-	sx_xlock(&allproc_lock);
-	LIST_REMOVE(p, p_list);
-	LIST_INSERT_HEAD(&zombproc, p, p_list);
-	LIST_REMOVE(p, p_hash);
-	sx_xunlock(&allproc_lock);
-
-	/*
 	 * Call machine-dependent code to release any
 	 * machine-dependent resources other than the address space.
 	 * The address space is released by "vmspace_exitfree(p)" in
@@ -443,12 +433,22 @@ exit1(struct thread *td, int rval, int signo)
 
 	WITNESS_WARN(WARN_PANIC, NULL, "process (pid %d) exiting", p->p_pid);
 
+	sx_xlock(&proctree_lock);
 	/*
+	 * Remove proc from allproc queue and pidhash chain.
+	 * Place onto zombproc.  Unlink from parent's child list.
+	 */
+	sx_xlock(&allproc_lock);
+	LIST_REMOVE(p, p_list);
+	LIST_INSERT_HEAD(&zombproc, p, p_list);
+	LIST_REMOVE(p, p_hash);
+	sx_xunlock(&allproc_lock);
+
+	/*
 	 * Reparent all children processes:
 	 * - traced ones to the original parent (or init if we are that parent)
 	 * - the rest to init
 	 */
-	sx_xlock(&proctree_lock);
 	q = LIST_FIRST(&p->p_children);
 	if (q != NULL)		/* only need this if any child is S_ZOMB */
 		wakeup(q->p_reaper);

Modified: head/sys/kern/kern_fork.c
==============================================================================
--- head/sys/kern/kern_fork.c	Tue Feb 20 02:03:29 2018	(r329614)
+++ head/sys/kern/kern_fork.c	Tue Feb 20 02:18:30 2018	(r329615)
@@ -394,7 +394,7 @@ do_fork(struct thread *td, struct fork_req *fr, struct
 	struct filedesc_to_leader *fdtol;
 	struct sigacts *newsigacts;
 
-	sx_assert(&proctree_lock, SX_SLOCKED);
+	sx_assert(&proctree_lock, SX_LOCKED);
 	sx_assert(&allproc_lock, SX_XLOCKED);
 
 	p1 = td->td_proc;
@@ -407,12 +407,11 @@ do_fork(struct thread *td, struct fork_req *fr, struct
 	LIST_INSERT_HEAD(&allproc, p2, p_list);
 	allproc_gen++;
 	LIST_INSERT_HEAD(PIDHASH(p2->p_pid), p2, p_hash);
-	tidhash_add(td2);
 	PROC_LOCK(p2);
 	PROC_LOCK(p1);
 
 	sx_xunlock(&allproc_lock);
-	sx_sunlock(&proctree_lock);
+	sx_xunlock(&proctree_lock);
 
 	bcopy(&p1->p_startcopy, &p2->p_startcopy,
 	    __rangeof(struct proc, p_startcopy, p_endcopy));
@@ -428,6 +427,8 @@ do_fork(struct thread *td, struct fork_req *fr, struct
 
 	PROC_UNLOCK(p2);
 
+	tidhash_add(td2);
+
 	/*
 	 * Malloc things while we don't hold any locks.
 	 */
@@ -954,7 +955,7 @@ fork1(struct thread *td, struct fork_req *fr)
 	STAILQ_INIT(&newproc->p_ktr);
 
 	/* We have to lock the process tree while we look for a pid. */
-	sx_slock(&proctree_lock);
+	sx_xlock(&proctree_lock);
 	sx_xlock(&allproc_lock);
 
 	/*
@@ -977,7 +978,7 @@ fork1(struct thread *td, struct fork_req *fr)
 
 	error = EAGAIN;
 	sx_xunlock(&allproc_lock);
-	sx_sunlock(&proctree_lock);
+	sx_xunlock(&proctree_lock);
 #ifdef MAC
 	mac_proc_destroy(newproc);
 #endif



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