A couple of months ago i was going through slides from gozers "From
CGI to mod_perl 2.0, Fast!" talk, which has some benchmarks comparing
CGI, perlrun and registry to each other. At which point i realized
that i've never really known how much faster using straight handlers
is than using one of the CGI emulation layers. I also didn't have any
idea how much faster SetHandler modperl was vs SetHandler perl-script.
So i decided to see what i could figure out. I took gozers CGI from
the slides (slightly modified) and ran it through the paces on my
laptop, then converted the script to run as a straight handler.
here's the CGI version:
#!/usr/bin/perl
print qq[Content-Type: text/html\r\n\r\n];
print(qq[
<html><body>
<h1>Hello Worlds</h1>
<pre>
GATEWAY_INTERFACE: $ENV{GATEWAY_INTERFACE}
MOD_PERL: $ENV{MOD_PERL}
</pre>
</body></html>
]);
Here's the Handler version
package Kabob::HelloWorld;
use strict;
use warnings;
use Apache2::RequestRec ();
use Apache2::Const -compile =>qw(:common);
sub handler {
my $r = shift;
$r->content_type('text/html');
$r->print(qq[
<html><body>
<h1>Hello Worlds</h1>
<pre>
GATEWAY_INTERFACE: $ENV{GATEWAY_INTERFACE}
MOD_PERL: $ENV{MOD_PERL}
</pre>
</body></html>
]);
return Apache2::Const::OK;
}
1;
and here's the conf (these tests were all running through a light
mod_proxy front end too)
<Location /cgi/>
<IfDefine FrontEnd>
ProxyPass http://localhost:8080/cgi/
ProxyPassReverse http://localhost:8080/cgi/
</IfDefine>
</Location>
<IfDefine BackEnd>
ScriptAlias /cgi/ /www/p/
</IfDefine>
Alias /perlrun/ /www/p/
<Location /perlrun/>
<IfDefine FrontEnd>
ProxyPass http://localhost:8080/perlrun/
ProxyPassReverse http://localhost:8080/perlrun/
</IfDefine>
<IfDefine BackEnd>
SetHandler perl-script
PerlHandler ModPerl::PerlRun
Options +ExecCGI
PerlSendHeader On
</IfDefine>
</Location>
Alias /registry/ /www/p/
<Location /registry/>
<IfDefine FrontEnd>
ProxyPass http://localhost:8080/registry/
ProxyPassReverse http://localhost:8080/registry/
</IfDefine>
<IfDefine BackEnd>
SetHandler perl-script
PerlHandler ModPerl::Registry
Options +ExecCGI
PerlSendHeader On
</IfDefine>
</Location>
<Location /perlscript/>
<IfDefine FrontEnd>
ProxyPass http://localhost:8080/perlscript/
ProxyPassReverse http://localhost:8080/perlscript/
</IfDefine>
<IfDefine BackEnd>
SetHandler perl-script
PerlResponseHandler Kabob::HelloWorld
</IfDefine>
</Location>
<Location /modperl/>
<IfDefine FrontEnd>
ProxyPass http://localhost:8080/modperl/
ProxyPassReverse http://localhost:8080/modperl/
</IfDefine>
<IfDefine BackEnd>
SetHandler modperl
PerlResponseHandler Kabob::HelloWorld
</IfDefine>
</Location>
and here's the results (which are no doubt flawed for a number of reasons)
running: ab -n 10000 [url]
CGI
Requests per second: 217.80 [#/sec] (mean)
Time per request: 4.591 [ms] (mean)
Transfer rate: 53.17 [Kbytes/sec] received
PerlRun
Requests per second: 482.49 [#/sec] (mean)
Time per request: 2.073 [ms] (mean)
Transfer rate: 114.49 [Kbytes/sec] received
Registry
Requests per second: 693.33 [#/sec] (mean)
Time per request: 1.442 [ms] (mean)
Transfer rate: 164.53 [Kbytes/sec] received
SetHandler perl-script
Requests per second: 772.12 [#/sec] (mean)
Time per request: 1.295 [ms] (mean)
Transfer rate: 189.94 [Kbytes/sec] received
SetHandler modperl
Requests per second: 1048.66 [#/sec] (mean)
Time per request: 0.954 [ms] (mean)
Transfer rate: 250.84 [Kbytes/sec] received
I'm not sure how well you can really compare the CGI emulation numbers
to the PerlHandler numbers, but personally i think the 30%ish
improvement from perl-script to modperl is pretty amazing. I wouldn't
have imagined it would have been that high.
Adam