A very important aspect of performance tuning is to make sure that your applications don't use too much memory. If they do, you cannot run many servers, and therefore in most cases, under a heavy load the overall performance will be degraded. The code also may leak memory, which is even worse, since if the same process serves many requests and more memory is used after each request, after a while all the RAM will be used and the machine will start swapping (i.e., using the swap partition). This is a very undesirable situation, because when the system starts to swap, the performance will suffer badly. If memory consumption grows without bound, it will eventually lead to a machine crash.

The simplest way to figure out how big the processes are and to see whether they are growing is to watch the output of the top(1) or ps(1) utilities.

For example, here is the output of top(1):

8:51am  up 66 days,  1:44,  1 user,  load average: 1.09, 2.27, 2.61
  95 processes: 92 sleeping, 3 running, 0 zombie, 0 stopped
  CPU states: 54.0% user,  9.4% system,  1.7% nice, 34.7% idle
  Mem:  387664K av, 309692K used,  77972K free, 111092K shrd,  70944K buff
  Swap: 128484K av,  11176K used, 117308K free                170824K cached

  29225 nobody 0  0  9760 9760  7132 S      0 12.5  2.5   0:00 httpd_perl
  29220 nobody 0  0  9540 9540  7136 S      0  9.0  2.4   0:00 httpd_perl
  29215 nobody 1  0  9672 9672  6884 S      0  4.6  2.4   0:01 httpd_perl
  29255 root   7  0  1036 1036   824 R      0  3.2  0.2   0:01 top
376 squid  0  0 15920  14M   556 S      0  1.1  3.8 209:12 squid
  29227 mysql  5  5  1892 1892   956 S N    0  1.1  0.4   0:00 mysqld
  29223 mysql  5  5  1892 1892   956 S N    0  0.9  0.4   0:00 mysqld
  29234 mysql  5  5  1892 1892   956 S N    0  0.9  0.4   0:00 mysqld

This starts with overall information about the system and then displays the most active processes at the given moment. So, for example, if we look at the httpd_perl processes, we can see the size of the resident (RSS) and shared (SHARE) memory segments.[35] This sample was taken on a production server running Linux.

[35]You can tell top to sort the entries by memory usage by pressing M while viewing the top screen.

But of course we want to see all the apache/mod_perl processes, and that's where ps(1) comes in. The options of this utility vary from one Unix flavor to another, and some flavors provide their own tools. Let's check the information about mod_perl processes:

panic% ps -o pid,user,rss,vsize,%cpu,%mem,ucomm -C httpd_perl
29213 root     8584 10264  0.0  2.2 httpd_perl
29215 nobody   9740 11316  1.0  2.5 httpd_perl
29216 nobody   9668 11252  0.7  2.4 httpd_perl
29217 nobody   9824 11408  0.6  2.5 httpd_perl
29218 nobody   9712 11292  0.6  2.5 httpd_perl
29219 nobody   8860 10528  0.0  2.2 httpd_perl
29220 nobody   9616 11200  0.5  2.4 httpd_perl
29221 nobody   8860 10528  0.0  2.2 httpd_perl
29222 nobody   8860 10528  0.0  2.2 httpd_perl
29224 nobody   8860 10528  0.0  2.2 httpd_perl
29225 nobody   9760 11340  0.7  2.5 httpd_perl
29235 nobody   9524 11104  0.4  2.4 httpd_perl

Now you can see the resident (RSS) and virtual (VSZ) memory segments (and the shared memory segment if you ask for it) of all mod_perl processes. Please refer to the top(1) and ps(1) manpages for more information.

You probably agree that using top(1) and ps(1) is cumbersome if you want to use memory-size sampling during the benchmark test. We want to have a way to print memory sizes during program execution at the desired places. The GTop module, which is a Perl glue to the libgtop library, is exactly what we need for that task.

You are fortunate if you run Linux or any of the BSD flavors, as the libgtop C library from the GNOME project is supported on those platforms. This library provides an API to access various system-wide and process-specific information. (Some other operating systems also support libgtop.)

With GTop, if we want to print the memory size of the current process we'd just execute:

use GTop ( );
print GTop->new->proc_mem($$)->size;

$$ is the Perl special variable that gives the process ID (PID) of the currently running process.

If you want to look at some other process and you have the necessary permission, just replace $$ with the other process's PID and you can peek inside it. For example, to check the shared size, you'd do:

print GTop->new->proc_mem($$)->share;

Let's try to run some tests:

panic% perl -MGTop -e 'my $g = GTop->new->proc_mem($$); \
  printf "%5.5s => %d\n",$_,$g->$_( ) for qw(size share vsize rss)'

 size => 1519616
share => 1073152
vsize => 2637824
  rss => 1515520

We have just printed the memory sizes of the process: the real, the shared, the virtual, and the resident (not swapped out).

There are many other things GTop can do for you—please refer to its manpage for more information. We are going to use this module in our performance tuning tips later in this chapter, so you will be able to exercise it a lot.

If you are running a true BSD system, you may use BSD::Resource::getrusage instead of GTop. For example:

print "used memory = ".(BSD::Resource::getrusage)[2]."\n"

For more information, refer to the BSD::Resource manpage.

The Apache::VMonitor module, with the help of the GTop module, allows you to watch all your system information using your favorite browser, from anywhere in the world, without the need to telnet to your machine. If you are wondering what information you can retrieve with GTop, you should look at Apache::VMonitor, as it utilizes a large part of the API GTop provides.