You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Dean Gaudet <dg...@arctic.org> on 1997/12/21 23:25:32 UTC

another misc speedup: three fewer syscalls

Just cleaning up my source trees, seeing what patches I've got lying
around that I've never posted...

This is a method of eliminating the SIGUSR1 manipulation during a
request... removing three system calls from the request.  It's only been
lightly tested, but doesn't seem to improve performance that much so I
didn't bother pursuing it.  I mention this on the perf-tuning page when
I'm explaining how to get rid of more syscalls. 

The reason for the complexity is that the accept() needs to be aborted
cleanly -- we cannot have a race condition there at all, if we get a
socket from accept() then we absolutely need to process it.  So we
indirect things such that during accept() a SIGUSR2 will be raised after
the SIGUSR1, and the SIGUSR2 will cause accept() to return EINTR if we
haven't yet received a socket.  Otherwise we'll ignore the SIGUSR2 as well
and continue processing. 

Dean

Index: http_main.c
===================================================================
RCS file: /export/home/cvs/apachen/src/main/http_main.c,v
retrieving revision 1.258
diff -u -r1.258 http_main.c
--- http_main.c	1997/12/21 01:54:39	1.258
+++ http_main.c	1997/12/21 22:07:35
@@ -2053,15 +2053,34 @@
     }
 }
 
-static int volatile usr1_just_die = 1;
+enum usr1_actions {
+    USR1_DEFERRED,
+    USR1_JUST_DIE,
+    USR1_RAISE_USR2
+};
+static enum usr1_actions volatile usr1_action = USR1_JUST_DIE;
 static int volatile deferred_die;
 
 static void usr1_handler(int sig)
 {
-    if (usr1_just_die) {
-	just_die(sig);
-    }
     deferred_die = 1;
+    switch (usr1_action) {
+    case USR1_DEFERRED:
+	break;
+
+    case USR1_JUST_DIE:
+	just_die (sig);
+	break;
+
+    case USR1_RAISE_USR2:
+	raise (SIGUSR2);
+	break;
+    }
+}
+
+static void usr2_handler (int sig)
+{
+    /* nothing to do, we're just causing an EINTR */
 }
 
 /* volatile just in case */
@@ -2798,9 +2817,21 @@
     ap_setjmp(jmpbuffer);
 #ifndef __EMX__
     signal(SIGURG, timeout);
-#endif
-    signal(SIGPIPE, timeout);
+#endif    
+    signal(SIGPIPE, timeout);  
     signal(SIGALRM, alrm_handler);
+    {
+	struct sigaction act;
+
+	act.sa_handler = usr1_handler;
+	sigemptyset(&act.sa_mask);
+	act.sa_flags = SA_RESTART;
+#ifdef  SA_INTERRUPT    /* SunOS */
+	act.sa_flags |= SA_INTERRUPT;
+#endif
+	sigaction(SIGUSR1, &act, NULL);
+    }
+    signal(SIGUSR2, usr2_handler);
 
     while (1) {
 	BUFF *conn_io;
@@ -2810,8 +2841,7 @@
 	 * we can exit cleanly.  Since we're between connections right
 	 * now it's the right time to exit, but we might be blocked in a
 	 * system call when the graceful restart request is made. */
-	usr1_just_die = 1;
-	signal(SIGUSR1, usr1_handler);
+	usr1_action = USR1_JUST_DIE;
 
 	/*
 	 * (Re)initialize this child to a pre-connection state.
@@ -2876,10 +2906,10 @@
 	     * defer the exit
 	     */
 	    deferred_die = 0;
-	    usr1_just_die = 0;
-	    for (;;) {
-		clen = sizeof(sa_client);
-		csd = accept(sd, &sa_client, &clen);
+	    usr1_action = USR1_RAISE_USR2;
+            for (;;) {
+                clen = sizeof(sa_client);
+                csd  = accept(sd, &sa_client, &clen);
 		if (csd >= 0 || errno != EINTR)
 		    break;
 		if (deferred_die) {
@@ -2904,7 +2934,7 @@
 	    }
 
 	    /* go around again, safe to die */
-	    usr1_just_die = 1;
+	    usr1_action = USR1_JUST_DIE;
 	    if (deferred_die) {
 		/* ok maybe not, see ya later */
 		clean_child_exit(0);
@@ -2923,7 +2953,7 @@
 	/* We've got a socket, let's at least process one request off the
 	 * socket before we accept a graceful restart request.
 	 */
-	signal(SIGUSR1, SIG_IGN);
+	usr1_action = USR1_DEFERRED;
 
 	note_cleanups_for_fd(ptrans, csd);
 
@@ -2978,9 +3008,7 @@
 
 	while ((r = read_request(current_conn)) != NULL) {
 
-	    /* read_request_line has already done a
-	     * signal (SIGUSR1, SIG_IGN);
-	     */
+	    usr1_action = USR1_DEFERRED;
 
 	    (void) update_child_status(my_child_num, SERVER_BUSY_WRITE, r);
 
@@ -3016,9 +3044,8 @@
 	     * connections to close before receiving a response because
 	     * of network latencies and server timeouts.
 	     */
-	    usr1_just_die = 1;
-	    signal(SIGUSR1, usr1_handler);
-	}
+	    usr1_action = USR1_RAISE_USR2;
+        }
 
 	/*
 	 * Close the connection, being careful to send out whatever is still
Index: http_protocol.c
===================================================================
RCS file: /export/home/cvs/apachen/src/main/http_protocol.c,v
retrieving revision 1.171
diff -u -r1.171 http_protocol.c
--- http_protocol.c	1997/12/21 08:18:16	1.171
+++ http_protocol.c	1997/12/21 22:07:37
@@ -709,7 +709,7 @@
         }
     }
     /* we've probably got something to do, ignore graceful restart requests */
-#ifdef SIGUSR1
+#ifdef XXXSIGUSR1
     signal(SIGUSR1, SIG_IGN);
 #endif                          /* SIGUSR1 */
     bsetflag(conn->client, B_SAFEREAD, 0);


Re: another misc speedup: three fewer syscalls

Posted by Marc Slemko <ma...@worldgate.com>.
On Sun, 21 Dec 1997, Ben Laurie wrote:

> Dean Gaudet wrote:
> > 
> > Just cleaning up my source trees, seeing what patches I've got lying
> > around that I've never posted...
> > 
> > This is a method of eliminating the SIGUSR1 manipulation during a
> > request... removing three system calls from the request.  It's only been
> > lightly tested, but doesn't seem to improve performance that much so I
> > didn't bother pursuing it.  I mention this on the perf-tuning page when
> > I'm explaining how to get rid of more syscalls.
> 
> This makes me wonder - if it doesn't improve performance that much, why
> the obsession with syscalls?

Because with context-switch bastards like Solaris it may make more of a
difference? 

Because most syscalls do have a bigger impact.

Because they are easy things to optimize, so who cares if they help it
still looks good.  (best reason)

Because they have an impact on low-level issues that may not be obvious
from trivial benchmarking.


Re: another misc speedup: three fewer syscalls

Posted by Dean Gaudet <dg...@arctic.org>.
Oh cutting them from 45+ to approximately 20 definately has an
improvement.  Cutting them further won't help much because the ones that
we can cut are just "fluff" as far as the total cost goes.  However, this
is on Linux... and dare I say it, but Linux has one of the lowest syscall
overheads of all unixes.  It's entirely possible that on Solaris this
patch is a huge win, I never checked. 

As a good rule of thumb, a syscall takes 4 to 5 times more cpu cycles than
a regular function call.  To make a syscall with libc you have to incur a
function call, plus you have to incur parm marshalling, then a privelege
level change... and do it all in reverse to get the result.  So if you can
do something in user space instead of calling the OS, you typically end up
with faster code. 

Dean

On Sun, 21 Dec 1997, Ben Laurie wrote:

> Dean Gaudet wrote:
> > 
> > Just cleaning up my source trees, seeing what patches I've got lying
> > around that I've never posted...
> > 
> > This is a method of eliminating the SIGUSR1 manipulation during a
> > request... removing three system calls from the request.  It's only been
> > lightly tested, but doesn't seem to improve performance that much so I
> > didn't bother pursuing it.  I mention this on the perf-tuning page when
> > I'm explaining how to get rid of more syscalls.
> 
> This makes me wonder - if it doesn't improve performance that much, why
> the obsession with syscalls?
> 
> Cheers,
> 
> Ben (in Devil's Advocate mode).
> 
> -- 
> Ben Laurie            |Phone: +44 (181) 735 0686|Apache Group member
> Freelance Consultant  |Fax:   +44 (181) 735 0689|http://www.apache.org
> and Technical Director|Email: ben@algroup.co.uk |Apache-SSL author
> A.L. Digital Ltd,     |http://www.algroup.co.uk/Apache-SSL
> London, England.      |"Apache: TDG" http://www.ora.com/catalog/apache
> 


Re: another misc speedup: three fewer syscalls

Posted by Ben Laurie <be...@algroup.co.uk>.
Dean Gaudet wrote:
> 
> Just cleaning up my source trees, seeing what patches I've got lying
> around that I've never posted...
> 
> This is a method of eliminating the SIGUSR1 manipulation during a
> request... removing three system calls from the request.  It's only been
> lightly tested, but doesn't seem to improve performance that much so I
> didn't bother pursuing it.  I mention this on the perf-tuning page when
> I'm explaining how to get rid of more syscalls.

This makes me wonder - if it doesn't improve performance that much, why
the obsession with syscalls?

Cheers,

Ben (in Devil's Advocate mode).

-- 
Ben Laurie            |Phone: +44 (181) 735 0686|Apache Group member
Freelance Consultant  |Fax:   +44 (181) 735 0689|http://www.apache.org
and Technical Director|Email: ben@algroup.co.uk |Apache-SSL author
A.L. Digital Ltd,     |http://www.algroup.co.uk/Apache-SSL
London, England.      |"Apache: TDG" http://www.ora.com/catalog/apache