You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by "Paul J. Reder" <re...@raleigh.ibm.com> on 2000/06/12 23:50:45 UTC

Performance comparison of mod_cgi and mod_cgid.

With the latest patch from Jeff to keep zombie processes from occurring,
I have finally crunched a full comparison of mod_cgi and mod_cgid. The
long and short of it is that mod_cgid performs nearly twice as well as
mod_cgi under many conditions. Read on for more details.

=================================================================
The performance results for mod_cgid vs. mod_cgi are as follows:

The first set of runs were run on two machines (A and B). Httpd
was running on machine B, apache bench was run from machine A.
There was nothing else of significance running on machine B.
Both machines are Linux machines, running RedHat 6.1. Machines
A and B are connected via a 100Mbps ethernet switch. 5 sets
of each test were run and averages were taken.

The basic invocation was as follows:
ab -n X -c Y -w http://B:8080/cgi-bin/printenv

=====>>> MOD_CGI Results

X    1000   1000   1000   1000
Y       1     10    100     10
K*    Yes    Yes    Yes     No
----------------------------------------------------------------
Time  12.03  15.03  30.13  14.17
RPS   83.2   66.9   35.0   70.6

Max recorded throughput
Time  11.692 14.059 20.481 13.843
RPS   85.53  71.13  48.83  72.24

Min recorded throughput
Time  12.365 17.395 39.527 14.498
RPS   80.87  57.44  25.3   68.98

(K indicates whether the keepalive (-k) option was used).

=====>>> MOD_CGID Results

X    1000   1000   1000   1000
Y       1     10    100     10
K     Yes    Yes    Yes     No
----------------------------------------------------------------
Time   9.02   8.98  10.47   8.96
RPS  110.8  111.3   95.6  111.65

Max recorded throughput
Time   8.99   8.94  10.31   8.92
RPS  111.23 111.81  96.97 112.06

Min recorded throughput
Time   9.10   9.02  10.62   9.01
RPS  109.87 110.83  94.15 111.10


==================================================================
The tests were then rerun using B as the server, and using 10
different machines to each run the following command simultaneously
(again, 5 runs were averaged).

ab -n 1000 -c 10 -w http://B:8080/cgi-bin/printenv

          mod_cgi    mod_cgid
----------------------------------------------------------------
Time      178.74      90.4
RPS        56.2      112.3

Time is computed by the following means:
    Xi = Average of the times for the ten machines per run.
    Time = (X1 + X2 + X3 + X4 + X5) / 5  for average across runs.

RPS is computed as the total system throughput by the following means:
    Yi = Sum of throughputs for all ten machines.
    RPS = (Y1 + Y2 + Y3 + Y4 + Y5) / 5   for average across runs.


==================================================================
The most likely explanation for the improved performance of mod-cgid
is that the code per request is simpler (as shown in the following):

mod_cgid:
   Accept on server socket.
   Fork the child
   exec the cgi

mod_cgi:
   ap_createprocattr_init
   ap_setprocattr_io
   ap_setprocattr_dir
   ap_setprocattr_cmdtype
   ap_create_process
      fork child
      exec cgi
   ap_note_subprocess

The other processing before and after the above code is
very similar between the two. The exception might be in the way
that mod_cgi does iol handling vs. mod_cgid.

-- 

Paul J. Reder

---------------------------------------------------------------------
Noise proves nothing.  Often a hen who has merely laid an egg cackles
as if she laid an asteroid.
		-- Mark Twain
(An apt quote in this political season.)

Re: Performance comparison of mod_cgi and mod_cgid.

Posted by Bill Stoddard <st...@raleigh.ibm.com>.
> With the latest patch from Jeff to keep zombie processes from occurring,
> I have finally crunched a full comparison of mod_cgi and mod_cgid. The
> long and short of it is that mod_cgid performs nearly twice as well as
> mod_cgi under many conditions. Read on for more details.
>

How do these numbers compare with mod_cgi running under the pre-fork MPM? mod_cgi on
Apache 1.3?

Bill


Re: Performance comparison of mod_cgi and mod_cgid.

Posted by Manoj Kasichainula <ma...@io.com>.
On Mon, Jun 12, 2000 at 02:58:51PM -0700, rbb@covalent.net wrote:
> The original problem this module was meant to solve (namely forking a
> threaded process) seems like a much better explanation for the performance
> difference IMHO.

The way to test this would be to run the server in a single-threaded
mode (perhaps with the prefork MPM even) and compare the results. ISTR
that Linux did not have this problem because of its different thread
handling; I think my tests last year confirmed this (though I have no
numbers anymore).

> It seems to me that fork (on all platforms) must create
> all threads and then kill them all to be POSIX compliant.

I don't get this. fork+exec, sure, but why would fork be required to
create and then destroy threads? I can't speak for POSIX, but SUSv2
(which I believe is also POSIX-compatible) doesn't have any evidence
of this:

http://www.opengroup.org/onlinepubs/007908799/xsh/fork.html

"A process is created with a single thread. If a multi-threaded
process calls fork(), the new process contains a replica of the
calling thread and its entire address space..."


Re: Performance comparison of mod_cgi and mod_cgid.

Posted by James Sutherland <ja...@cam.ac.uk>.
On Mon, 12 Jun 2000 rbb@covalent.net wrote:

> > I tend to agree with Ryan here; certainly fork() seems like the most
> > likely culprit, if it's forking a load of threads then killing them all
> > every time.
> > 
> > The next stage, of course, is to have the cgid process pre-fork, and add a
> > modular API. Then, after a few years, give it an abstraction layer to aid
> > porting, write multi-threaded versions... :-)
> > 
> > On a more serious note, have you tried moving the fork() up before the
> > accept(), so the child accept()s requests then exec()s? If it's possible,
> > this should help cut request latency slightly, I think? (Probably little
> > or no impact on these benchmarks, though...)
> 
> I'm not sure I like this idea, it opens too many questions.  How many
> processes do we pre-fork? 

Just one - instead of accept()...fork(), we do fork()...accept(). This
way, there's no need for any extra configuration (except perhaps whether
or not to use this technique), and only a single extra process.

> Do we need new configuration options for this? 

At most, just an "CGIDPreFork" enabled/disabled setting.

> At some point does this become a server in and of itself?

In a sense, it already is, albeit a very simple one.

> This is an interesting idea, but I'm not sure its something we even want
> to consider for this version of mod_cgid.

Agreed - just an idea to keep in mind for the future.


James.


Re: Performance comparison of mod_cgi and mod_cgid.

Posted by rb...@covalent.net.
> I tend to agree with Ryan here; certainly fork() seems like the most
> likely culprit, if it's forking a load of threads then killing them all
> every time.
> 
> The next stage, of course, is to have the cgid process pre-fork, and add a
> modular API. Then, after a few years, give it an abstraction layer to aid
> porting, write multi-threaded versions... :-)
> 
> On a more serious note, have you tried moving the fork() up before the
> accept(), so the child accept()s requests then exec()s? If it's possible,
> this should help cut request latency slightly, I think? (Probably little
> or no impact on these benchmarks, though...)

I'm not sure I like this idea, it opens too many questions.  How many
processes do we pre-fork?  Do we need new configuration options for
this?  At some point does this become a server in and of itself?

This is an interesting idea, but I'm not sure its something we even want
to consider for this version of mod_cgid.

Ryan


_______________________________________________________________________________
Ryan Bloom                        	rbb@apache.org
406 29th St.
San Francisco, CA 94131
-------------------------------------------------------------------------------



Re: Performance comparison of mod_cgi and mod_cgid.

Posted by James Sutherland <ja...@cam.ac.uk>.
On Mon, 12 Jun 2000 rbb@covalent.net wrote:

> 
> > mod_cgid:
> >    Accept on server socket.
> >    Fork the child
> >    exec the cgi
> > 
> > mod_cgi:
> >    ap_createprocattr_init
> >    ap_setprocattr_io
> >    ap_setprocattr_dir
> >    ap_setprocattr_cmdtype
> >    ap_create_process
> >       fork child
> >       exec cgi
> >    ap_note_subprocess
> > 
> > The other processing before and after the above code is
> > very similar between the two. The exception might be in the way
> > that mod_cgi does iol handling vs. mod_cgid.
> 
> I have a hard time with this explanation.  If you take a look at what the
> setprocattr_* functions are doing, it just isn't that much.  I also find
> it hard to believe that the cmdtype and dir functions can't be removed.
> 
> This explanation really makes it look like APR is a huge drain on system
> resources, which is not what we are seeing with the rest of Apache 2.0.  I
> would prefer that we had some real proof that APR is causing these
> problems before this is just assumed.
> 
> The original problem this module was meant to solve (namely forking a
> threaded process) seems like a much better explanation for the performance
> difference IMHO.  It seems to me that fork (on all platforms) must create
> all threads and then kill them all to be POSIX compliant.

I tend to agree with Ryan here; certainly fork() seems like the most
likely culprit, if it's forking a load of threads then killing them all
every time.

The next stage, of course, is to have the cgid process pre-fork, and add a
modular API. Then, after a few years, give it an abstraction layer to aid
porting, write multi-threaded versions... :-)

On a more serious note, have you tried moving the fork() up before the
accept(), so the child accept()s requests then exec()s? If it's possible,
this should help cut request latency slightly, I think? (Probably little
or no impact on these benchmarks, though...)


James.


Re: Performance comparison of mod_cgi and mod_cgid.

Posted by rb...@covalent.net.
> mod_cgid:
>    Accept on server socket.
>    Fork the child
>    exec the cgi
> 
> mod_cgi:
>    ap_createprocattr_init
>    ap_setprocattr_io
>    ap_setprocattr_dir
>    ap_setprocattr_cmdtype
>    ap_create_process
>       fork child
>       exec cgi
>    ap_note_subprocess
> 
> The other processing before and after the above code is
> very similar between the two. The exception might be in the way
> that mod_cgi does iol handling vs. mod_cgid.

I have a hard time with this explanation.  If you take a look at what the
setprocattr_* functions are doing, it just isn't that much.  I also find
it hard to believe that the cmdtype and dir functions can't be removed.

This explanation really makes it look like APR is a huge drain on system
resources, which is not what we are seeing with the rest of Apache 2.0.  I
would prefer that we had some real proof that APR is causing these
problems before this is just assumed.

The original problem this module was meant to solve (namely forking a
threaded process) seems like a much better explanation for the performance
difference IMHO.  It seems to me that fork (on all platforms) must create
all threads and then kill them all to be POSIX compliant.

Ryan

_______________________________________________________________________________
Ryan Bloom                        	rbb@apache.org
406 29th St.
San Francisco, CA 94131
-------------------------------------------------------------------------------