view release on metacpan or search on metacpan
$postdata = join('', <FILE>);
close FILE;
}
my $c = $options{'c'} || 1;
my $n = $options{'n'} || 1;
my $b = HTTPD::Bench::ApacheBench->new;
$b->concurrency($c);
$b->keepalive( $options{'k'} );
$b->timelimit( $options{'t'} );
my $run = HTTPD::Bench::ApacheBench::Run->new
({
urls => [ $ARGV[0] ],
repeat => $n,
memory => 3,
});
$run->cookies([ $options{'C'} ]);
$run->postdata([ $postdata ]);
$run->head_requests([ $options{'i'} ]);
doc/C_Functions_Tree view on Meta::CPAN
read a chunk of data from a socket;
if (all data has been read OR an error occurred)
-> close_connection(); return;
if (there is no data available to read at the moment: read returned EAGAIN)
-> return;
if (we have not received the full http header)
if (this chunk of data contains end of http header: "\r\n\r\n" or "\n\n")
-> check response header for Keep-Alive and mark accordingly;
else
-> return;
if (response indicated keepalive and we've received entire response)
-> store_regression_data();
-> schedule_next_request();
if (next scheduled request is keepalive and the hostname/port are same)
-> write_request();
else
-> close the connection and start a fresh one: start_connect();
write_request()
reset_request();
write full http request to socket;
reset_request()
build http request according to GET/HEAD/POST settings;
lib/HTTPD/Bench/ApacheBench.pm view on Meta::CPAN
##################################################
sub initialize {
my ($self) = @_;
$self->{runs} = [] if ref $self->{runs} ne 'ARRAY';
$self->{concurrency} ||= 1;
$self->{repeat} ||= 1;
$self->{priority} ||= "equal_opportunity";
$self->{buffersize} ||= 262144;
$self->{request_buffersize} ||= 8192;
$self->{timelimit} = undef if ! defined $self->{timelimit};
$self->{keepalive} = 0 if ! defined $self->{keepalive};
$self->{memory} = 1 if ! defined $self->{memory};
}
##################################################
## configure the global parameters ##
##################################################
sub config {
my ($self, $opt) = @_;
foreach (qw(concurrency priority buffersize repeat memory)) {
lib/HTTPD/Bench/ApacheBench.pm view on Meta::CPAN
$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) = @_;
lib/HTTPD/Bench/ApacheBench.pm view on Meta::CPAN
(default: "B<equal_opportunity>")
=item $b->repeat( $n )
The number of times to repeat the request sequence in each run.
This can be overridden on a per-run basis (see below).
(default: B<1>)
=item $b->keepalive( 0|1 )
Whether or not to use HTTP Keep-Alive feature for requests configured in this
object. This can be overridden on a per-url/per-run basis (see below).
B<Warning>: If you configure runs which contain requests to more than one
hostname/port, be aware that setting $b->keepalive() may not improve
performance. See the discussion in the $run->keepalive() section for more
details.
(default: B<0>)
=item $b->timelimit( $sec_to_max_wait )
Set the maximum number of seconds to wait for requests configured in this
object to complete (i.e. receive the full response from the server).
B<Warning>: once the specified number of seconds have elapsed, ApacheBench
will read one last chunk of data from each open socket, and exit. This could
lib/HTTPD/Bench/ApacheBench.pm view on Meta::CPAN
If this option is omitted, no extra HTTP request headers will be sent in
any of the requests for this run. Length of @req_headers should equal the
length of @url_list.
The following example for a @url_list of length 4 produces two requests with
no extra headers, one with 1 extra header, and one with 2 extra headers.
$run->request_headers([ undef, undef, "Extra-Header: bread",
"Extra-Header1: butter\r\nExtra-Header2: toaster" ])
=item $run->keepalive( \@keepalives )
Use HTTP Keep-Alive feature for the specified requests in this run. The
length of @keepalives should equal the length of @url_list, and it is
interpreted as an array of booleans, with undef indicating to use the
object default set by $b->keepalive(). Any true value in @keepalives will
result in a Keep-Alive HTTP request being sent for the corresponding URL.
To achieve full performance benefits from this feature, you need to be sure
your Keep-Alive requests are consecutive. If a non-Keep-Alive request or
a request for a different hostname or port immediately follows a Keep-Alive
request B<in the connection slot>, I<the connection will be closed> and a
new connection will be opened.
Further, keep in mind that for $b->concurrency() > 1, there are many
connection slots open and even though requests in @url_list will be sent
in order, there is no guarantee they will all use the same connection slot.
The HTTP Keep-Alive feature only yields performance benefits when consecutive
Keep-Alive requests use the same connection slot. Otherwise ApacheBench has
to close and re-open connections, resulting in the same performance as not
using keepalive() at all.
To guarantee consecutive Keep-Alive requests with $b->concurrency() > 1,
I recommend you either declare I<all> URLs in all runs as keepalive()
(this can be done by setting $b->keepalive( 1 ) and not overriding it by
calling keepalive() for any runs), or set $run->order( "depth_first" ) and
$b->priority( "run_priority" ). This is the only combination of configuration
options that guarantees consecutive, same-slot Keep-Alive requests
regardless of your concurrency setting.
For $b->concurrency() == 1, things are simpler. At any given time, there
is only one connection slot open, so just make sure your keepalive URLs are
consecutive within each run (if in "run_priority" mode), or that
equal-numbered repetitions of URLs in all runs are keepalive (if in
"equal_opportunity" mode), and be sure that all requests are to the
same hostname/port.
=item $run->timelimits( \@timelimits )
Set the maximum number of seconds to wait for requests in this
run to complete (i.e. receive the full response from the server). The
length of @timelimits should equal the length of @url_list, and it is
interpreted as an array of double precision floating point numbers
(representing the number of seconds to wait for a response). An undef or 0
lib/HTTPD/Bench/ApacheBench/Run.pm view on Meta::CPAN
#####################################################
## sanity check on run object variables: ##
## this method is intended to hopefully catch ##
## errors that cause a segmentation fault in ab() ##
#####################################################
sub ready_to_execute {
my ($self) = @_;
foreach (qw(urls cookies postdata head_requests
content_types request_headers keepalive timelimits)) {
return 0 unless ref $self->{$_} eq "ARRAY";
}
return 0 if grep { ref($_) || m/\s$/ } @{$self->{urls}};
return 1;
}
#####################################################
## do a pre-execute fixup of run object ##
#####################################################
lib/HTTPD/Bench/ApacheBench/Run.pm view on Meta::CPAN
# whitespace at the end of urls will cause trouble
map { chomp $_ } @{$self->{urls}};
# set 'cookies' to undef if not specified
$self->{cookies} = [undef] unless ref $self->{cookies} eq "ARRAY";
# set 'postdata', 'content_types', and 'request_headers' to undef
# if not specified in run
foreach my $param (qw(postdata head_requests content_types
request_headers keepalive timelimits)) {
$self->{$param} = [ map {undef} @{$self->{urls}} ]
if ref $self->{$param} ne "ARRAY";
}
return 1;
}
sub pre_execute_warnings {
my ($self) = @_;
lib/HTTPD/Bench/ApacheBench/Run.pm view on Meta::CPAN
$self->{head_requests} = $arg if $arg;
return $self->{head_requests};
}
sub content_types {
my ($self, $arg) = @_;
$self->{content_types} = $arg if $arg;
return $self->{content_types};
}
sub keepalive {
my ($self, $arg) = @_;
$self->{keepalive} = $arg if $arg;
return $self->{keepalive};
}
sub timelimits {
my ($self, $arg) = @_;
$self->{timelimits} = $arg if $arg;
return $self->{timelimits};
}
sub append {
my ($self, $opt) = @_;
src/ApacheBench.xs view on Meta::CPAN
HV *
ab(input_hash)
SV * input_hash;
PREINIT:
char *pt,**url_keys;
int i,j,k,arrlen,arrlen2;
int def_buffersize; /* default buffersize for all runs */
int def_repeat; /* default number of repeats if unspecified in runs */
int def_memory; /* default memory setting if unspecified in runs */
bool def_keepalive = 0; /* default keepalive setting */
struct global *registry = calloc(1, sizeof(struct global));
int total_started = 0, total_good = 0, total_failed = 0;
CODE:
SV * runs;
SV * urls = 0;
SV * post_data = 0;
SV * head_requests = 0;
SV * cookies = 0;
SV * ctypes = 0;
SV * req_headers = 0;
SV * keepalive = 0;
SV * url_tlimits = 0;
AV * run_group, *tmpav, *tmpav2;
SV * tmpsv, *tmpsv2 = 0, *tmpsv3;
HV * tmphv;
STRLEN len;
if (AB_DEBUG_XS) printf("AB_DEBUG: start of ab()\n");
registry->concurrency = 1;
registry->requests = 0;
src/ApacheBench.xs view on Meta::CPAN
def_buffersize = SvIV(tmpsv);
tmpsv = *(hv_fetch(tmphv, "repeat", 6, 0));
def_repeat = SvIV(tmpsv);
tmpsv = *(hv_fetch(tmphv, "memory", 6, 0));
def_memory = SvIV(tmpsv);
if (AB_DEBUG_XS) printf("AB_DEBUG: ab() init - stage 1\n");
tmpsv = *(hv_fetch(tmphv, "keepalive", 9, 0));
if (SvTRUE(tmpsv))
def_keepalive = 1;
if (AB_DEBUG_XS) printf("AB_DEBUG: ab() init - stage 2\n");
tmpsv = *(hv_fetch(tmphv, "priority", 8, 0));
pt = SvPV(tmpsv, len);
if (strcmp(pt, "run_priority") == 0)
registry->priority = RUN_PRIORITY;
else {
registry->priority = EQUAL_OPPORTUNITY;
if (strcmp(pt, "equal_opportunity") != 0)
src/ApacheBench.xs view on Meta::CPAN
if (hv_exists(tmphv, "postdata", 8))
post_data = *(hv_fetch(tmphv, "postdata", 8, 0));
if (hv_exists(tmphv, "head_requests", 13))
head_requests = *(hv_fetch(tmphv, "head_requests", 13, 0));
if (hv_exists(tmphv, "cookies", 7))
cookies = *(hv_fetch(tmphv, "cookies", 7, 0));
if (hv_exists(tmphv, "content_types", 13))
ctypes = *(hv_fetch(tmphv, "content_types", 13, 0));
if (hv_exists(tmphv, "request_headers", 15))
req_headers = *(hv_fetch(tmphv, "request_headers", 15, 0));
if (hv_exists(tmphv, "keepalive", 9))
keepalive = *(hv_fetch(tmphv, "keepalive", 9, 0));
if (hv_exists(tmphv, "timelimits", 10))
url_tlimits = *(hv_fetch(tmphv, "timelimits", 10, 0));
/* configure urls */
for (i = registry->position[k]; i < registry->position[k+1]; i++) {
tmpav =(AV *) SvRV(urls);
tmpsv = *(av_fetch(tmpav, i - registry->position[k], 0));
if (SvPOK(tmpsv)) {
pt = SvPV(tmpsv, len);
url_keys[i] = pt;
src/ApacheBench.xs view on Meta::CPAN
}
/*If the number of ctypes strings is less than
that of urls, then assign NULL (undef) */
for (j = i; j < registry->position[k+1]; j++)
registry->ctypes[j] = 0;
if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 6\n", k);
/* find smaller of keepalive array length and urls array length */
tmpav = (AV *) SvRV(keepalive);
i = ap_min(registry->position[k+1],
registry->position[k] + av_len(tmpav) + 1);
if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 6.1\n", k);
/* configure keepalive */
for (j = registry->position[k]; j < i; j++) {
if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 6.2, j=%d\n", k, j);
tmpsv = *(av_fetch(tmpav, j - registry->position[k], 0));
if (SvOK(tmpsv))
if (SvTRUE(tmpsv))
registry->keepalive[j] = 1;
else
registry->keepalive[j] = 0;
else
registry->keepalive[j] = def_keepalive;
if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 6.3, j=%d\n", k, j);
}
/*If the number of keepalive strings is less than
that of urls, then assign object's default keepalive value */
for (j = i; j < registry->position[k+1]; j++)
registry->keepalive[j] = def_keepalive;
if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 7\n", k);
/* find smaller of url_tlimits array length and urls array length */
tmpav = (AV *) SvRV(url_tlimits);
i = ap_min(registry->position[k+1],
registry->position[k] + av_len(tmpav) + 1);
if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 7.1\n", k);
src/apachebench/execute.c view on Meta::CPAN
registry->ready_to_run_queue[registry->tail].run = i;
registry->ready_to_run_queue[registry->tail].thread = j;
registry->ready_to_run_queue[registry->tail++].url = registry->position[i];
}
}
registry->hostname = malloc(registry->number_of_urls * sizeof(char *));
registry->path = malloc(registry->number_of_urls * sizeof(char *));
registry->port = malloc(registry->number_of_urls * sizeof(int));
registry->ctypes = malloc(registry->number_of_urls * sizeof(char *));
registry->req_headers = malloc(registry->number_of_urls * sizeof(char *));
registry->keepalive = malloc(registry->number_of_urls * sizeof(bool));
registry->url_tlimit = malloc(registry->number_of_urls * sizeof(double));
registry->started = malloc(registry->number_of_urls * sizeof(int));
registry->finished = malloc(registry->number_of_urls * sizeof(int));
registry->failed = malloc(registry->number_of_urls * sizeof(int));
registry->good = malloc(registry->number_of_urls * sizeof(int));
registry->postdata = malloc(registry->number_of_urls * sizeof(char *));
registry->postsubs = malloc(registry->number_of_urls * sizeof(SV *));
registry->postlen = malloc(registry->number_of_urls * sizeof(int));
registry->posting = malloc(registry->number_of_urls * sizeof(int));
registry->totalposted = malloc(registry->number_of_urls * sizeof(int));
src/apachebench/socket_io.c view on Meta::CPAN
}
/* --------------------------------------------------------- */
/* start asnchronous non-blocking connection */
static void
start_connect(struct global * registry, struct connection * c) {
c->read = 0;
c->bread = 0;
c->keepalive = 0;
c->cbx = 0;
c->gotheader = 0;
c->fd = socket(AF_INET, SOCK_STREAM, 0);
#ifdef AB_DEBUG
printf("AB_DEBUG: start of start_connect()\n");
#endif
if (c->fd < 0) {
myerr(registry->warn_and_error, "socket error");
src/apachebench/socket_io.c view on Meta::CPAN
* needs to be extended to handle whatever servers folks want to
* test against. -djg
*/
c->gotheader = 1;
*s = 0; /* terminate at end of header */
if (registry->memory[c->run] >= 2) {
c->response_headers = malloc(CBUFFSIZE * sizeof(char));
strcpy(c->response_headers, c->cbuff);
}
if (registry->keepalive[c->url] &&
(strstr(c->cbuff, "Keep-Alive") ||
strstr(c->cbuff, "keep-alive"))) { /* for benefit of MSIIS */
char *cl;
cl = strstr(c->cbuff, "Content-Length:");
/* handle NCSA, which sends Content-length: */
if (!cl)
cl = strstr(c->cbuff, "Content-length:");
if (cl) {
c->keepalive = 1;
c->length = atoi(cl + 16);
}
}
c->bread += c->cbx - (s + wslen - c->cbuff) + r - tocopy;
}
} else {
/* outside header, everything we have read is entity body */
c->bread += r;
}
/*
* cater for the case where we're using keepalives and doing HEAD
* requests
*/
if (c->keepalive &&
((c->bread >= c->length) || (registry->posting[c->url] < 0))) {
/* save current url for checking for hostname/port changes */
int prev = c->url;
/* finished a keep-alive connection */
registry->good[c->url]++;
registry->finished[c->url]++;
store_regression_data(registry, c);
if (++registry->done >= registry->need_to_be_done)
return;
if (!schedule_next_request(registry, c))
return;
c->length = 0;
c->gotheader = 0;
c->cbx = 0;
c->read = c->bread = 0;
c->keepalive = 0;
/* if new hostname/port is different from last hostname/port, or new
url is *not* keepalive, then we need to close connection and start
a new connection */
if (registry->keepalive[c->url] &&
strcmp(registry->hostname[c->url], registry->hostname[prev]) == 0
&& registry->port[c->url] == registry->port[prev]) {
write_request(registry, c);
registry->started[c->url]++;
c->start_time = c->connect_time; /* zero connect time with keep-alive */
} else {
ab_close(c->fd);
FD_CLR(c->fd, ®istry->readbits);
FD_CLR(c->fd, ®istry->writebits);
start_connect(registry, c);
}
}
}
/* --------------------------------------------------------- */
src/apachebench/socket_io.c view on Meta::CPAN
registry->version,
registry->hostname[i],
registry->postlen[i],
ctype);
}
#ifdef AB_DEBUG
printf("AB_DEBUG: reset_request() - stage 2\n");
#endif
if (registry->keepalive[i])
strcat(c->request_headers, "Connection: Keep-Alive\r\n");
if (registry->cookie[c->run]) {
strcat(c->request_headers, "Cookie: ");
strcat(c->request_headers, registry->cookie[c->run]);
strcat(c->request_headers, "\r\n");
}
#ifdef AB_DEBUG
printf("AB_DEBUG: reset_request() - stage 2.1: c->run %d; c->thread %d\n", c->run, c->thread);
#endif
src/apachebench/types.h view on Meta::CPAN
#define BREADTH_FIRST 0
/* ------------------- STRUCTS -------------------------- */
struct connection {
int fd;
int state;
int url; /* which url are we testing */
int read; /* amount of bytes read */
int bread; /* amount of body read */
int length; /* Content-Length value used for keep-alive */
char cbuff[CBUFFSIZE]; /* a buffer to store server response header */
int cbx; /* offset in cbuffer */
int keepalive; /* non-zero if a keep-alive request */
int gotheader; /* non-zero if we have the entire header in
* cbuff */
int thread; /* Thread number */
int run;
struct timeval start_time, connect_time, before_postdata_time, sent_request_time, done_time;
char *request; /* HTTP request */
char *request_headers;
int reqlen;
src/apachebench/types.h view on Meta::CPAN
int requests; /* the max of the repeats */
double tlimit; /* global time limit, in seconds */
struct timeval min_tlimit; /* minimum of all time limits */
int *position; /* The position next run starts */
char **hostname; /* host name */
int *port; /* port numbers */
char **path; /* path name */
char **ctypes; /* values for Content-type: headers */
double *url_tlimit; /* time limit in seconds for each url */
bool *keepalive; /* whether to use Connection: Keep-Alive */
int *posting; /* GET if ==0, POST if >0, HEAD if <0 */
char **postdata, **cookie; /* datas for post and optional cookie line */
SV **postsubs; /* coderefs for post */
char **req_headers; /* optional arbitrary request headers to add */
char ***auto_cookies; /* cookies extracted from response_headers for the run, i.e. set by http server */
bool *use_auto_cookies; /* whether to use auto_cookie feature for the run */
int *postlen; /* length of data to be POSTed */
int *totalposted; /* total number of bytes posted, inc. headers*/
t/test3_execute.t view on Meta::CPAN
ok($b->run(0)->request_headers([map {"Accept-Encoding: text/html"} @urls]));
# we make three identical runs except the first will GET, the second will POST,
# and the third HEAD; the second run also uses the HTTP Keep-Alive feature
my $run1 = HTTPD::Bench::ApacheBench::Run->new({
repeat => $n,
urls => [ @urls ],
order => "depth_first",
});
$run1->postdata([ map {"post"} @urls ]);
$run1->keepalive([map {1} @urls]);
$b->add_run($run1);
ok($b->run(1), $run1);
my $run2 = HTTPD::Bench::ApacheBench::Run->new({
repeat => $n,
urls => [ @urls ],
order => "depth_first",
});
$run2->head_requests([ map {1} @urls ]);
$b->add_run($run2);