Subject: Re: new vfork(2) implementation
To: Computo Ergo Checksum <greywolf@starwolf.starwolf.com>
From: Jason Thorpe <thorpej@nas.nasa.gov>
List: current-users
Date: 01/03/1998 21:21:58
On Sat, 3 Jan 1998 20:07:19 -0800 
 greywolf@starwolf.starwolf.com (Computo Ergo Checksum) wrote:

 >  * Orignally, vfork was implemented because the address space was copied at
 >  * fork time.  This was a time consuming process, and a real waste if the
 >  * program were to immediately exec (which would then unmap the address space
 >  * so painstakenly copied just moments ago).  When copy-on-write was added
 >  * to BSD (when it got the Mach VM system)...
 > 
 > ...which appears to be, in itself, something of a travesty...

Mach VM has served its purpose.  Sure, a better VM system is waiting in
the wings, but Mach VM helped us get to where we are today (now, you have
to decide whether or not that's a good thing :-)

 > For those who aren't too familiar with the semantics of vfork(2) --
 > or, rather, how vfork() was *supposed* to work in the first place --
 > the first place any potential problems in version differences will
 > appear will likely be any of the shells.

Well, the only shell in our tree that uses vfork() is csh.  sh and ksh
don't; they use fork().  make uses vfork(), and the improvement there has
been quite noticeable.  (vfork() makes more of a difference if the process
is large in terms of address space use, and since make isn't very good
about managing memory.... :-)  gcc also uses vfork() to start its subprocesses
(e.g. cpp, as, ld, etc.), so one might notice an improvement there, as well.

The kernel now keeps statistics on how many forks total have been performed,
how many resulted in the parent being blocked (vfork()'s synchronization
semantics), and how many resulted in the child sharing address space with
the parent (vfork()'s address space sharing semantics).  You can get the
number of 4.4BSD-style vforks performed by subtracting "shared" from "blocked".

Anyhow, just rebuilding make and gcc, and then doing a "make build" on my
AlphaStation:

bishop:thorpej 1$ vmstat -f
42225 forks total
14476 forks blocked parent
7769 forks shared address space with parent
bishop:thorpej 2$ 

...as you can see, I installed make and gcc sometime after the machine had
been up for a bit :-)

 > I would like to extend my congratulations and a raucous, jovial, jesting
 > "It's about bloody _time_!" to Jason for undertaking vfork().  It's not
 > easy, but it's certainly long overdue.

Well, actually, it wasn't that hard :-)  Actually, the hardest bits
were really getting the pmap interfaces fixed up so that a process could
get a new address space while it is curproc (needed for when a vfork'd
child exec's).  Actually, that was more tedious, except for the VAX case,
because I actually had to make some changes to how that pmap works :-)

 > Hey, Jason, could you possibly do a fork() vs. vfork() stat comparison
 > to see how the times stack up?  The difference appears to be something
 > in the area of 20-30% for old vs. new vfork(), and i'd be interested in
 > seeing the savings versus a real fork()...

Well, unfortunately, it's not that simple.  In addition to the address
space sharing semantics, vfork() has _always_ provided a synchronization
semantic; the parent blocks until the child exits or exec's.  Lots of
programs depend on this, so it's really not possible to make that sort
of comparison.  And, really, the "block parent" was the ONLY difference
between fork() and vfork() in 4.4BSD (and NetBSD, until now).  So, the
4.4BSD vfork() vs. new (old :-) vfork() is really all you get :-)

Ciao.

Jason R. Thorpe                                       thorpej@nas.nasa.gov
NASA Ames Research Center                            Home: +1 408 866 1912
NAS: M/S 258-6                                       Work: +1 650 604 0935
Moffett Field, CA 94035                             Pager: +1 415 428 6939