App-livehttperf
view release on metacpan or search on metacpan
lib/App/livehttperf.pm view on Meta::CPAN
$|=1;
for my $concurrency ( @concurrency ) {
LOG "\nRunning with concurrency of $concurrency" if INFO;
my $pm = Parallel::ForkManager->new( $concurrency );
$stats{$concurrency} = {
reqs => Statistics::Descriptive::Full->new(),
recs => {},
counts => {
successful_requests => 0,
failed_requests => 0,
bytes_sent => 0,
bytes_recv => 0,
},
errors => {
total => 0,
recs => {}
},
};
$pm->run_on_start(sub {
my ($pid, $tid) = @_;
$stats{$concurrency}->{started} = [ gettimeofday ];
});
$pm->run_on_finish(sub {
my ($pid, $failures, $tid, $exit_signal, $core_dump, $data) = @_;
$stats{$concurrency}->{elapsed} = tv_interval( $stats{$concurrency}->{started} );
$stats{$concurrency}->{counts}->{failed_requests} += $failures;
if ( defined $data ) {
# all failed request by $rec_no
$stats{$concurrency}->{errors}->{recs}->{$_} += $data->{errors}->{$_}
for keys %{ $data->{errors} };
# add to stats total time of all requests in all runs
$stats{$concurrency}->{reqs}->add_data(
@{ $data->{reqs} }
);
# sum counts
$stats{$concurrency}->{counts}->{$_} += $data->{counts}->{$_}
for qw( successful_requests bytes_sent bytes_recv 1xx 2xx 3xx 4xx 5xx );
# add to stats time of each request in all runs
for my $rec_no ( keys %{ $data->{recs} } ) {
$stats{$concurrency}->{recs}->{$rec_no} = Statistics::Descriptive::Full->new()
unless exists $stats{$concurrency}->{recs}->{$rec_no};
$stats{$concurrency}->{recs}->{$rec_no}->add_data(
@{ $data->{recs}->{$rec_no} }
);
}
}
});
for my $tid ( 1 .. $concurrency ) {
LOG "Starting thread $tid" if INFO;
$pm->start($tid) and next;
my $failed_requests = 0;
my $successful_requests = 0;
my %req_stats = (
reqs => Statistics::Descriptive::Full->new(),
recs => {},
counts => {},
);
my @req_stats_data;
my %rec_stats_data;
my $bytes_sent = 0;
my $bytes_recv = 0;
my %rec_errors;
my %res_statuses = (
'1xx' => 0,
'2xx' => 0,
'3xx' => 0,
'4xx' => 0,
'5xx' => 0,
);
for my $no ( 1 .. $OPTS{repeat} ) {
LOG "Starting run $no (thread $tid)" if INFO;
# create brand new UA for each loop
my $ua = LWP::UserAgent->new(
(
$OPTS{reuse_cookies} ?
()
:
( cookie_jar => {} )
),
%ua_opts
);
my $rec_no = 0;
for my $rec ( @recs ) {
$rec_no++;
if ( ! ref $rec ) {
LOG "[$tid.$no.$rec_no] Waiting for ", elapsed($rec) if DEBUG;
sleep $rec;
next;
}
my $req = $rec->{req};
$bytes_sent += $rec->{req_bytes};
my $exp_res = $rec->{res};
LOG "[$tid.$no.$rec_no] REQ:\n", $req->headers->as_string if DEBUG;
LOG "[$tid.$no.$rec_no] REQ:\n", $req->as_string if TRACE;
my $res;
# start of the request in run $no
my $rec_stats_start = [ gettimeofday ];
eval {
$res = $ua->request($req, $OPTS{verbosity} == 1 ? sub { print "." } : () )
or die "No response\n";
};
my $err = $@;
push @{ $rec_stats_data{$rec_no} }, tv_interval( $rec_stats_start );
if ( $res ) {
LOG "[$tid.$no.$rec_no] RES:\n", $res->headers->as_string if DEBUG;
LOG "[$tid.$no.$rec_no] RES:\n", $res->as_string if TRACE;
my $res_headers = $res->headers;
$bytes_recv += $res_headers->header('Content-Length') ||
(length($res_headers->as_string) + length($res->content));
$res_statuses{int($res->code / 100) .'xx'}++;
}
if ( $err || ! response_matched($exp_res, $res) ) {
$failed_requests++;
$rec_errors{$rec_no}++;
if ( ERROR ) {
my $nl = $OPTS{verbosity} == 1 ? "\n" : '';
if ( $res ) {
LOG "$nl\[$tid.$no.$rec_no] RES FAILED: ", $res->status_line;
} else {
LOG "$nl\[$tid.$no.$rec_no] RES FAILED: (no response)";
}
}
if ( TRACE ) {
LOG " Exception: $err" if $err;
}
} else {
$successful_requests++;
LOG "[$tid.$no.$rec_no] RES: ", $res->status_line if DEBUG;
}
}
LOG "\nFinished run $no (thread $tid)" if INFO;
}
$req_stats{reqs} = [];
for my $rec_no ( keys %rec_stats_data ) {
for ( my $i = 0; $i < @{ $rec_stats_data{$rec_no} }; $i++ ) {
# total time of all requests in given run $no
$req_stats{reqs}->[$i] += $rec_stats_data{$rec_no}->[$i];
}
}
$req_stats{recs} = { %rec_stats_data };
$req_stats{errors} = { %rec_errors };
$req_stats{counts} = {
successful_requests => $successful_requests,
bytes_sent => $bytes_sent,
bytes_recv => $bytes_recv,
%res_statuses,
};
LOG "\nFinished thread $tid" if INFO;
$pm->finish($failed_requests, \%req_stats);
}
$pm->wait_all_children;
LOG "\nFinished testing concurrency $concurrency" if INFO;
}
$elapsed_time = tv_interval( $test_started );
}
sub get_concurrency_time_stats {
my ($concurrency) = @_;
my $reqs = $stats{$concurrency}->{reqs};
return (
$concurrency,
scalar localtime($stats{$concurrency}->{started}->[0]),
sprintf("%.6f", $stats{$concurrency}->{elapsed}),
( map { sprintf("%.6f", $reqs->$_() ) } qw( min max mean standard_deviation median ) ),
);
}
sub get_concurrency_res_stats {
my ($concurrency) = @_;
my $counts = $stats{$concurrency}->{counts};
return (
$concurrency,
( map { $counts->{$_} } qw( successful_requests failed_requests 1xx 2xx 3xx 4xx 5xx ) ),
);
}
sub xlsx_row {
return [ @_ ];
}
sub save_results {
print "\n";
{
my $reqs_sent = $total_urls * $OPTS{repeat} * sum(@concurrency);
my $test_run_at = localtime();
print "\n";
print "SUMMARY\n";
print " Test run at: ", $test_run_at, "\n";
print " URLs tested: ", $total_urls, "\n";
print " Total delays (per run): ", ($total_delays ? elapsed($total_delays) : '0'), "\n";
print " Requests sent: ", $reqs_sent, "\n";
print " Test elapsed time: ", ($elapsed_time < 1 ? '< 1 sec' : elapsed($elapsed_time)), "\n";
print "\n";
if ( $xls ) {
( run in 1.142 second using v1.01-cache-2.11-cpan-e1769b4cff6 )