What’s the minimum time it could take a serve a web page using a given Perl-based solution using CGI? What’s the minimum amount of memory it would take?

To check the relative differences between several options listed below, I made the simplest possible “Hello World” page, and benchmarked the time and memory used to serve it. To create a base line, I also measured the results for an empty Perl script that just prints “Hello World”.

The result summary is after the jump.

If it’s not already clear, these benchmarks are not meant to represent real world applications or web servers. Of course, physics dictate that would be difficult of any application to perform any faster than these times, using the same systems and hardware.

System Version Startup*Memory**
Empty Script Perl 5.8.8 0.01s 4.7M
CGI::Simple 1.103 0.08s 5.5M
CGI.pm 3.42 0.11s 5.7M
CGI::Application 4.20 0.21s 6.0M
Mojo 0.8.9 0.29s 8.3M
Mojolicious 0.8.9 0.31s 8.8M
Titanium 1.0 0.14s 6.0M
Titanium w/Dispatch 1.0 0.39s 10.1M
Catalyst 5.8000_03 0.80s 13.5M
HTTP::Engine 0.0.18 1.50s 14.9M
HTTP::Engine/Shika 0.0.99_01 0.19s 6.6M
* The "real" time in seconds as timed with `time -p perl foo.pl` on a 1.1 Ghz ThinkPad T23 laptop with Ubuntu 8.04 Linux. ** The virtual memory size when the script is about to exit, as timed by printing the output of this at the end of the script run: `ps -o pid,user,rss,vsize,ucomm -C perl`;

Let’s go through some of the numbers.

CGI::Simple, a lighter-weight CGI.pm alternative turns in the best time and memory consumption. Before considering using it, note that it has a different interface in a few places, like file upload handling, and there are still some cases that CGI.pm can handle but it can’t, like some kinds of file uploads.

Next there’s much-maligned CGI.pm, still appearing here with a respectable second-fastest start time and low memory consumption. Both CGI::Simple and CGI.pm help process an HTTP request and prepare an HTTP response, which is functionality targeted by most of the options listed here.

CGI::Application is next on the list. It explicitly doesn’t provide any of the functionality of CGI.pm itself, and I don’t think CGI.pm would even be loaded for this bare-bones “Hello World” case. CGI::Application provides basic application structure, control flow, and a callback system for plugins. As a long time user, It’s no surprise to confirm that CGi::Application is a very lightweight solution.

Mojo is next. It’s functionality includes supporting several server backends and abstracting the HTTP server response and request. This is a bit similar to what CGI.pm does, since CGI.pm also supports mod_perl and FastCGI as well has helping with the HTTP request and response. (Of course the Mojo and CGI approaches couldn’t be more different!). Mojo also provides a similar amount of functionality as HTTP::Engine. Mojo’s result shows that it can be a rather lightweight solution itself, perhaps suitable for running in a CGI environment. Overall, the performance of Mojo is impressive here.

Next up we have Mojolicious and Titanium, which had very similar speed benchmarks. Mojolicious adds dispatching and a file-extension based templating system to Mojo, including the ability to serve static pages and a simple built-in templating system. It’s perhaps similar to the amount of functionality that CGI::Application covers when combined with CGI.pm and HTML::Template, but again the approach is very different.

Of the group of systems tested here, I would say Titanium covers the largest scope of functionality, since it goes beyond usual framework offerings, including additional methods for managing database handles, config files, sessions, form validation and form filling. I often run Titanium-style apps under CGI with good performance. In a persistent environment, the smaller memory footprint would be a more significant win here, allowing more application processes to be run concurrently.

Second to last on the list we have Catalyst, the Perl framework which needs no introduction. It’s slower startup time is not particularly considered a concern here, as it is not targeted at being deployed in CGI environments. That it uses a bit more memory does show some kind of additional overhead, although for many deployments a bit extra memory per-process won’t matter.

Finally, taking far more time and still more memory, we have HTTP::Engine. Considering its scope of functionality competes with Mojo, this performance and memory overhead is disappointing. HTTP::Engine explicitly has a CGI interface, but taking 1.5 seconds and almost 15 megs of memory just to print “Hello World” is dismal. Update 12/1/2008- HTTP::Engine replaced “Moose” with “Shika” and massive speed and memory gains, apparently without any reduction in functionality. The run time of 0.19 seconds and memory usage of 6.6 megs is rather respectable.

I can already anticipate the feedback to this article saying that the startup times don’t matter because much of this is compile-time work, which doesn’t apply to persistent-environments, because compilation would only then happen once at server start-up time, and is not per-request. And there’s the perception I expect to hear echo’ed back again: No one uses straight CGI anymore, right?

As a professional website developer with over a decade of experience, nearly all the web applications I’ve written have run in CGI, and have performed just fine this way. Why do anything more complicated, when the simple solution works?

A web framework is a bit like an operating system, it’s there to prop up the layer where the real value-added work happens. For an OS, that’s the application. For a web-app, that’s the custom application logic. If your web application is going to be slow and hog memory it should because your custom application does that, not because the framework itself takes almost two seconds to boot up and uses 15 megabytes of memory before your application really gets started.

If your application is not expected to be high-traffic, several of the solutions mentioned here are candidates for running under CGI, saving the complexity and overhead of deploying in FastCGI or mod_perl. If you creating your applications with best practices like avoiding global variables, it will likely be easy to convert it to run under mod_perl or FastCGI later.

As a disclosure, some of the testing scripts I used are below. For Catalyst, Mojo, and Mojolicious, I used the default CGI scripts that came bundled with them.


use CGI;
my $q = CGI->new;
print $q->header;
print "Hello from CGI\n"; 


package HelloWorld;
use base 'CGI::Application';

sub setup {
    my $self = shift;


sub hello_world {
    my $self = shift;
    return "Hello World\n".


# Titanium with Dispatching, dispatch.pl
use CGI::Application::Dispatch;
    default => 'hello-world/hello_world',

Titanium with Dispatching, HelloWorld.pm

package HelloWorld;
use base 'Titanium';

sub setup {
    my $self = shift;


sub hello_world {
    my $self = shift;
    return "Hello World\n";     

# HTTP::Engine
use HTTP::Engine;
my $engine = HTTP::Engine->new(
      interface => {
          module => 'CGI',
          request_handler => 'main::handle_request',

sub handle_request {
      my $req = shift;
      HTTP::Engine::Response->new( body => "Hello from HTTP::Engine\n\n");


print "Hello World\n";

The Perfect Day

Published on November 02, 2015