Cache-Memcached-Fast
view release on metacpan or search on metacpan
script/benchmark.pl view on Meta::CPAN
#! /usr/bin/perl
#
# Copyright (C) 2007-2008 Tomash Brechko. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the same terms as Perl itself, either Perl version 5.8.8
# or, at your option, any later version of Perl 5 you may have
# available.
#
use v5.12;
use warnings;
# NOTE: at least on Linux (kernel 2.6.18.2) there is a certain
# artifact that affects wallclock time (but not CPU time) of some
# benchmarks: when send/receive rate changes dramatically, the system
# doesn't adopt to it right away. Instead, for some time a lot of
# small-range ACK packets are being sent, and this increases the
# latency. Because of this '*_multi (%h)', which comes first, has
# bigger wallclock time than '*_multi (@h)', which comes next. I
# tried pre-warming the connection, but this doesn't help in all
# cases. Seems like 'noreply' mode is also affected, and maybe
# 'nowait'.
use constant default_iteration_count => 1_000;
use constant key_count => 100;
use constant NOWAIT => 1;
use constant NOREPLY => 1;
my $value = 'x' x 40;
use Cache::Memcached::Fast;
use Benchmark qw(:hireswallclock timethese cmpthese timeit timesum timestr);
use FindBin;
die <<HELP unless @ARGV;
Usage: $FindBin::Script HOST:PORT... [COUNT] ["compare"]
HOST:PORT... - list of memcached server addresses.
COUNT - number of iterations (default ${\default_iteration_count})
(each iteration will process ${\key_count} keys).
"compare" - literal string to enable comparison with
Cache::Memcached.
HELP
pop @ARGV if my $compare = $ARGV[-1] eq 'compare';
my $count = $ARGV[-1] =~ /^\d+$/ ? pop @ARGV : default_iteration_count;
my $max_keys = $count * key_count / 2;
my @addrs = @ARGV;
my $old;
my $old_method = qr/^(?:add|set|replace|incr|decr|delete|get)$/;
my $old_method_multi = qr/^get$/;
if ($compare) {
require Cache::Memcached;
$old = new Cache::Memcached {
servers => [@addrs],
namespace => "Cache::Memcached::bench/$$/",
connect_timeout => 5,
select_timeout => 5,
};
$old->enable_compress(0);
}
my $new = new Cache::Memcached::Fast {
servers => [@addrs],
namespace => "Cache::Memcached::bench/$$/",
ketama_points => 150,
nowait => NOWAIT,
connect_timeout => 5,
io_timeout => 5,
};
my $version = $new->server_versions;
if ( keys %$version != @addrs ) {
my @servers = map {
if ( ref($_) eq 'HASH' ) {
$_->{address};
}
elsif ( ref($_) eq 'ARRAY' ) {
$_->[0];
}
else {
$_;
}
} @addrs;
warn "No server is running at "
. join( ', ', grep { not exists $version->{$_} } @servers ) . "\n";
exit 1;
}
my $min_version = 2**31;
while ( my ( $s, $v ) = each %$version ) {
if ( $v =~ /(\d+)\.(\d+)\.(\d+)/ ) {
my $n = $1 * 10000 + $2 * 100 + $3;
$min_version = $n if $n < $min_version;
}
else {
warn "Can't parse version of $s: $v";
exit 1;
}
}
my $noreply = NOREPLY && $min_version >= 10205;
@addrs = map { +{ address => $_, noreply => $noreply } } @addrs;
my $new_noreply = new Cache::Memcached::Fast {
servers => [@addrs],
namespace => "Cache::Memcached::bench/$$/",
ketama_points => 150,
connect_timeout => 5,
io_timeout => 5,
};
sub get_key {
int( rand($max_keys) );
}
sub merge_hash {
my ( $h1, $h2 ) = @_;
while ( my ( $k, $v ) = each %$h2 ) {
$h1->{$k} = $v;
}
}
sub bench_finalize {
my ( $title, $code, $finalize ) = @_;
say "Benchmark: timing $count iterations of $title...";
my $b1 = timeit( $count, $code );
# We call nowait_push here. Otherwise the time of gathering
# the results would be added to the following commands.
my $b2 = timeit( 1, $finalize );
my $res = timesum( $b1, $b2 );
say "$title: ", timestr( $res, 'auto' );
return { $title => $res };
}
sub run {
my ( $method, $value, $cas ) = @_;
my $params = sub {
my @params;
push @params, $_[0] . '-' . get_key();
push @params, 0 if $cas;
push @params, $value if defined $value;
return @params;
};
my $params_multi = sub {
my @res;
for ( my $i = 0; $i < key_count; ++$i ) {
my @params;
push @params, $_[0] . '-' . get_key();
if ( $cas or defined $value ) {
push @params, 0 if $cas;
push @params, $value if defined $value;
push @res, \@params;
}
else {
push @res, @params;
}
}
return @res;
};
my @test = (
"$method" => sub {
my $res = $new->$method( &$params('p$') )
foreach ( 1 .. key_count );
},
);
push @test, (
"old $method" => sub {
my $res = $old->$method( &$params('o$') )
foreach ( 1 .. key_count );
},
) if defined $old and $method =~ /$old_method/o;
my $bench = timethese( $count, {@test} );
if ( defined $value and $noreply ) {
# We call get('no-such-key') here. Otherwise the time of
# sending the requests might be added to the following
( run in 1.246 second using v1.01-cache-2.11-cpan-96521ef73a4 )