The reason I recently ended up diving down the rabbit hole of the same_interp_tie method was actually that I was working on writing a helper method to watch memory size on a mod_perl process. My methodology was simply a brute force series of requests with a memory check before and after.

I'd be interested in any feedback on what I've got so far. I was also thinking it might fit nicely in Apache::TestUtil?

Basic code is below. I've also got tests I can provide after working in feedback.

Thanks,
Jim

==========================================
Jim Brandt
Administrative Computing Services
University at Buffalo


use strict;
use warnings;

use Apache::Test;
use Apache::TestUtil;
use Apache::TestRequest qw( GET GET_BODY );
use GTop;

=pod

=head1 t_mem

This function attempts to watch a mod_perl process to determine
if its memory use is stable. It gets the size of a process, requests
the indicated mod_perl resource the requested number of times,
then checks the memory again.

required params:
  url => the page to hit on the test server

optional params:
  request_count => number of times to hit the resource; default is 10
tolerance => percentage within which the test is considered successful

Return values:

In scalar context, t_mem returns 1 for true or undef for false.

In array context, t_mem looks like this:

my ($result, $pre_test_mem, $post_test_mem, $difference, $percent_diff) = t_mem({ url => '/test.cgi', request_count => 100, tolerance => 0 });

where:

$result is the true or false value,
$pre_test_mem is the memory in (bytes?) before the test
$post_test_mem is the memory in (bytes?) after the test
$difference is the difference between the two which is how much the process grew
$percent_diff is the percentage difference used to determine if it was
  within tolerance.

=cut

sub t_mem{
  my ($arg_ref) = @_;

  my $DEF_REQUEST_COUNT = 10;
  my $DEF_TOLERANCE = 0;

  die "No url passed."
    if not defined $arg_ref->{url};

  # Set defaults
my $request_count = exists $arg_ref->{request_count} ? $arg_ref-> {request_count} : $DEF_REQUEST_COUNT; my $tolerance = exists $arg_ref->{tolerance} ? $arg_ref-> {tolerance} : $DEF_TOLERANCE;

  # Set process to hit.
  my $pid = &get_pid();

  # Tie requests to one child to make sure we are really hitting it.
my $same_interp = Apache::TestRequest::same_interp_tie($arg_ref-> {url});

  my $res = Apache::TestRequest::same_interp_do($same_interp,
                        \&GET, $arg_ref->{url});

  my $pre_process_size = &get_process_size($pid);

  for (my $i=1; $i<=$request_count; $i++){
    $res = Apache::TestRequest::same_interp_do
      ( $same_interp, \&GET, $arg_ref->{url} );
    unless ($res->code == 200){
      die "Failed page load for $arg_ref->{url} on iteration $i";
    }
  }

  # Get process size again.
  my $post_process_size = &get_process_size($pid);

  # Compare and return results.
  my $diff = $post_process_size - $pre_process_size;

  # Calculate percent difference.
  my $percent_diff = ($diff * 100) / $pre_process_size;

  my $result;
  if ( $percent_diff <= $tolerance ){
    $result = 1;
  }

  if (wantarray){
return ($result, $pre_process_size, $post_process_size, $diff, $percent_diff);
  }

  return $result;
}


sub get_pid{
  # Is there a better way to get the process id?

  my $status = GET_BODY('/server-status');
  $_ = $status;

  my $pid = $1 if /(\d+)\sin state/m;

  unless( $pid ){
    die "Can't get process id.";
  }

  return $pid;
}

sub get_process_size{
  my $pid = shift;

  my $gtop = GTop->new;
  die "Unable to get process memory."
    unless (my $proc_mem = $gtop->proc_mem($pid));

  die "Unable to get real memory size."
    unless (my $rss = $proc_mem->rss);

  return $rss;
}


sub size_string {
  # Use this for nicer formating of results?

    my($size) = @_;

    if (!$size) {
        $size = "   0K";
    }
    elsif ($size == -1) {
        $size = "    -";
    }
    elsif ($size < 1024) {
        $size = "   1K";
    }
    elsif ($size < 1048576) {
        $size = sprintf "%4dK", ($size + 512) / 1024;
    }
    elsif ($size < 103809024) {
        $size = sprintf "%4.1fM", $size / 1048576.0;
    }
    else {
        $size = sprintf "%4dM", ($size + 524288) / 1048576;
    }

    return $size;
}

1;

Reply via email to