Improving mod_perl Driven Site's Performance -- Part V: Sharing Memory Page 4

To remind you why do we look for the smallest value in the column diff, recall the real memory usage formula:

  RAM_dedicated_to_mod_perl = diff * number_of_processes
                            + the_processes_with_largest_shared_memory

Notice that the smaller the diff is, the bigger the number of processes you can have using the same amount of RAM. Therefore every 100K difference counts, when you multiply it by the number of processes. If we take the number from the version version (1) vs. (4) and assume that we have 256M of memory dedicated to mod_perl processes we will get the following numbers using the formula derived from the above formula:

               RAM - largest_shared_size
  N_of Procs = -------------------------
                268435456 - 2609152
  (ver 1)  N =  ------------------- = 309
                268435456 - 2469888
  (ver 5)  N =  ------------------- = 262

So you can tell the difference (17% more child processes in the first version).

Initializing CGI.pm

CGI.pm is a big module that by default postpones the compilation of its methods until they are actually needed, thus making it possible to use it under a slow mod_cgi handler without adding a big overhead. That's not what we want under mod_perl and if you use CGI.pm you should precompile the methods that you are going to use at the server startup in addition to preloading the module. Use the compile method for that:

  use CGI;

where you should replace the tag group :all with the real tags and group tags that you are going to use if you want to optimize the memory usage.

I'm going to compare the shared memory foot print by using the script which is back compatible with mod_cgi. You will see that you can improve performance of this kind of scripts as well, but if you really want a fast code think about porting it to use Apache::Request for CGI interface and some other module for HTML generation.

So here is the Apache::Registry script that I'm going to use to make the comparison:

  use strict;
  use CGI ();
  use GTop ();
  my  = new CGI;
  print ->header('text/plain');
  print join "\n", map {"sh => ".->param(sh) } ->param;
  print "\n";

  my  = GTop->new->proc_mem(25885);
  my   = ->size;
  my  = ->share;

  my   =  - ;
  printf "%8s %8s %8s\n", qw(Size Shared Diff);
  printf "%8d %8d %8d (bytes)\n",,,;

The script initializes the CGI object, sends HTTP header and then print all the arguments and values that were passed to the script if at all. At the end as usual I print the memory usage.

As usual I are going to use a single child process, therefore I will use this setting in httpd.conf:

  MinSpareServers 1
  MaxSpareServers 1
  StartServers 1
  MaxClients 1
  MaxRequestsPerChild 100

I'm going to run memory benchmarks on three different versions of the startup.pl file. I always preload this module:

  use Gtop();
option 1
Leave the file unmodified.

option 2
Preload CGI.pm:
  use CGI ();

option 3
Preload CGI.pm and pre-compile the methods that I'm going to use in the script:
  use CGI ();
  CGI->compile(qw(header param));

This article was originally published on Jan 24, 2001

Thanks for your registration, follow us on our social networks to keep up-to-date