ApacheBench

 view release on metacpan or  search on metacpan

lib/HTTPD/Bench/ApacheBench.pm  view on Meta::CPAN

    $self->{concurrency} = $arg if $arg;
    return $self->{concurrency};
}

sub priority {
    my ($self, $arg) = @_;
    $self->{priority} = $arg if $arg;
    return $self->{priority};
}

sub memory {
    my ($self, $arg) = @_;
    $self->{memory} = $arg if defined $arg;
    return $self->{memory};
}

sub repeat {
    my ($self, $arg) = @_;
    $self->{repeat} = $arg if $arg;
    return $self->{repeat};
}

sub keepalive {
    my ($self, $arg) = @_;
    $self->{keepalive} = $arg if $arg;
    return $self->{keepalive};
}

sub timelimit {
    my ($self, $arg) = @_;
    $self->{timelimit} = $arg if $arg;
    return $self->{timelimit};
}

sub buffersize {
    my ($self, $arg) = @_;
    $self->{buffersize} = $arg if $arg;
    return $self->{buffersize};
}

sub request_buffersize {
    my ($self, $arg) = @_;
    $self->{request_buffersize} = $arg if $arg;
    return $self->{request_buffersize};
}

sub total_requests {
    my ($self) = @_;
    return 0 if ref $self->{runs} ne 'ARRAY';
    my $total = 0;
    foreach my $run (@{$self->{runs}}) {
	my $repeat = $run->repeat ? $run->repeat : $self->{repeat};
	$total += ($#{$run->urls} + 1) * $repeat
	  if ref $run->urls eq 'ARRAY';
    }
    return $total;
}


##################################################
## verify configuration of runs and execute     ##
##################################################
sub execute {
    my ($self) = @_;
    # keep track of temporarily altered run object variables
    my %altered;

    # fail if they have not added any runs
    return undef if ref $self->{runs} ne 'ARRAY';

    # pre execute initialization of each run
    foreach my $run_no (0..$#{$self->{runs}}) {
	my $runobj = $self->{runs}->[$run_no];

	$runobj->ready_to_execute or $runobj->prepare_for_execute or
	  return undef;

	# default to base ApacheBench object variables if not specified in run
	if (! $runobj->repeat) {
	    $runobj->repeat($self->{repeat});
	    $altered{$run_no}->{repeat} = 1;
	}
	if (! defined $runobj->memory) {
	    $runobj->memory($self->{memory});
	    $altered{$run_no}->{memory} = 1;
	}

        $runobj->pre_execute_warnings;
    }

    # call the XS code and store regression data
    $self->{'regression'} = $self->ab;

    # post execute polishing of each run
    foreach my $run_no (0..$#{$self->{runs}}) {
	my $runobj = $self->{runs}->[$run_no];
	$runobj->{'run_no'} = $run_no;
	$runobj->{'regression'} = $self->{'regression'};
	foreach my $param (qw(repeat memory)) {
	    delete $runobj->{$param}
	      if (ref $altered{$run_no} and $altered{$run_no}->{$param});
	}
    }
    return HTTPD::Bench::ApacheBench::Regression->new
      ({ 'regression' => $self->{'regression'} });
}


##################################################
## run accessors                                ##
##################################################
sub run {
    my ($self, $run_no, $run) = @_;
    return undef if ! (ref $self->{runs} eq 'ARRAY' && blessed $self->{runs}->[$run_no]
                         && $self->{runs}->[$run_no]->isa('HTTPD::Bench::ApacheBench::Run'));
    if (blessed $run && $run->isa('HTTPD::Bench::ApacheBench::Run')) {
	my $replaced_run = $self->{runs}->[$run_no];
	$self->{runs}->[$run_no] = $run;
	return $replaced_run;
    }
    return $self->{runs}->[$run_no];

lib/HTTPD/Bench/ApacheBench.pm  view on Meta::CPAN


  use HTTPD::Bench::ApacheBench;

  my $b = HTTPD::Bench::ApacheBench->new;

  # global configuration
  $b->concurrency(5);
  $b->priority("run_priority");

  # add HTTP request sequences (aka: runs)
  my $run1 = HTTPD::Bench::ApacheBench::Run->new
    ({ urls => ["http://localhost/one", "http://localhost/two"] });
  $b->add_run($run1);

  my $run2 = HTTPD::Bench::ApacheBench::Run->new
    ({ urls    => ["http://localhost/three", "http://localhost/four"],
       cookies => ["Login_Cookie=b3dcc9bac34b7e60;"],
       # note: manual cookies no longer necessary due to use_auto_cookies (enabled by default)
       order   => "depth_first",
       repeat  => 10,
       memory  => 2 });
  $b->add_run($run2);

  my $run3 = HTTPD::Bench::ApacheBench::Run->new
    ({ urls     => ["http://localhost/five", "http://localhost/six"],
       memory   => 3,
       postdata => [
           sub($) { sleep(int(rand(5)) + 1); return undef; },
           sub($) {
               my $prev_response = shift;
               sleep(int(rand(5)) + 1);
               my ($username) = ( $prev_response =~ m|<div id="userName">([^<>]+)</div>|i );
               return $username ? 'cgi-username='.$username : undef;
           },
       ] });
  $b->add_run($run3);

  # send HTTP request sequences to server and time responses
  my $ro = $b->execute;

  # calculate hits/sec
  print ((1000*$b->total_requests/$b->total_time)." req/sec\n");

  # show request times (in ms) for $run1, 1st repetition
  print join(', ', @{$run1->request_times}) . "\n";

  # show response times (in ms) for $run2, 7th repetition
  print join(', ', @{$run2->iteration(6)->response_times}) . "\n";

  # dump the entire regression object (WARNING, this could be a LOT OF DATA)
  use Data::Dumper;
  my $d = Data::Dumper->new([$ro]);
  print $d->Dumpxs;


=head1 GOALS

This project is meant to be the foundation of a complete benchmarking
and regression testing suite for an advanced, transaction-based mod_perl
site.  We need to be able to stress our server to its limit while also
having a way to verify the HTTP responses for correctness.  Since our site
is transaction-based (as opposed to content-based), we needed to extend
the single-URL ab model to a multiple-URL sequence model.

ApacheBench was originally based on the Apache 1.3.12 ab code
(src/support/ab.c), but has since undergone major rewrites and now barely
resembles ab.c.

Note: although this tool was designed to be used on an Apache mod_perl
site, it is generally applicable to any HTTP-compliant server.  Beware,
however, that it sends a high volume of HTTP requests in a very short period
of time, which may overwhelm some weaker HTTP server implementations
like NT/IIS.

=head1 DESCRIPTION

ApacheBench sends sequences of HTTP requests to an HTTP server and keeps
track of the time taken to receive a response, the data that was returned,
the size of the data that was returned, and various other bits of information.

Since it is implemented in C, it sends HTTP requests in a tight loop which
can stress your server to 100% capacity, especially if invoked in multiple
concurrent instances.  It gives accurate time measurements down to the
millisecond for each HTTP request-response interval.

Included is a simplified re-implementation of ab using the ApacheBench/Perl
API.  This should help get you started with ApacheBench.

=head1 CONFIGURATION METHODS

You need to tell ApacheBench what the requests will be, in what order to
send them, and how to prioritize sending them.  ApacheBench was designed
to simulate many users logged in simultaneously, each of whom may be doing
many different transactions at once.

=head2 Global configuration methods

Global configuration methods apply to all benchmarking runs associated
with this ApacheBench object.

=over 4

=item $b = HTTPD::Bench::ApacheBench->new()

Constructor.

=item $b->concurrency( $concur_level )

Number of requests to send simultaneously (default: B<1>)

=item $b->priority( $priority )

$priority can be either "B<equal_opportunity>" or "B<run_priority>".

If set to "B<equal_opportunity>", all benchmark runs that are configured
(see below) under this ApacheBench object are given equal access to
the concurrency level.  This means requests are taken from each run
and sent in parallel (the level of parallelism defined by concurrency()).

If set to "B<run_priority>", the benchmark runs that are configured first
get the highest priority.  This means all requests in $b->run(0) will



( run in 0.807 second using v1.01-cache-2.11-cpan-13bb782fe5a )