package Smokeping::matchers::Avgratio;
=head1 NAME
Smokeping::matchers::Avgratio - detect changes in average median latency
=head1 OVERVIEW
The Avgratio matcher establishes a historic average median latency over
several measurement rounds. It compares this average, against a second
average latency value again build over several rounds of measurement.
=head1 DESCRIPTION
Call the matcher with the following sequence:
type = matcher
pattern = Avgratio(historic=>a,current=>b,comparator=>o,percentage=>p)
=over
=item historic
The number of median values to use for building the 'historic' average.
=item current
The number of median values to use for building the 'current' average.
=item comparator
Which comparison operator should be used to compare current/historic with percentage.
=item percentage
Right hand side of the comparison.
=back
old <--- historic ---><--- current ---> now
=head1 EXAMPLE
Take build the average median latency over 10 samples, use this to divide the
current average latency built over 2 samples and check if it is bigger than
150%.
Avgratio(historic=>10,current=>2,comparator=>'>',percentage=>150);
avg(current)/avg(historic) > 150/100
This means the matcher will activate when the current latency average is
more than 1.5 times the historic latency average established over the last
10 rounds of measurement.
=head1 COPYRIGHT
Copyright (c) 2004 by OETIKER+PARTNER AG. All rights reserved.
=head1 SPONSORSHIP
The development of this matcher has been sponsored by Virtela Communications, L.
=head1 LICENSE
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
=head1 AUTHOR
Tobias Oetiker
=cut
use vars qw($VERSION);
$VERSION = 1.0;
use strict;
use base qw(Smokeping::matchers::base);
use Carp;
sub new(@)
{
my $class = shift;
my $rules = {
historic=>'\d+',
current=>'\d+',
comparator=>'(<|>|<=|>=|==)',
percentage=>'\d+(\.\d+)?' };
my $self = $class->SUPER::new($rules,@_);
$self->{param}{sub} = eval "sub {\$_[0] ".$self->{param}{comparator}." \$_[1]}";
croak "compiling comparator $self->{param}{comparator}: $@" if $@;
$self->{param}{value} = $self->{param}{percentage}/100;
return $self;
}
sub Length($)
{
my $self = shift;
return $self->{param}{historic} + $self->{param}{current};
}
sub Desc ($) {
croak "Detect changes in average median latency";
}
sub avg(@){
my $sum=0;
my $cnt=0;
for (@_){
next unless defined $_;
$sum += $_;
$cnt ++;
}
return $sum/$cnt if $cnt;
return undef;
}
sub Test($$)
{ my $self = shift;
my $data = shift; # @{$data->{rtt}} and @{$data->{loss}}
my $len = $self->Length;
my $rlen = scalar @{$data->{rtt}};
return undef
if $rlen < $len
or (defined $data->{rtt}[-$len] and $data->{rtt}[-$len] eq 'S');
my $ac = $self->{param}{historic};
my $bc = $self->{param}{current};
my $cc = $ac +$bc;
my $ha = avg(@{$data->{rtt}}[-$cc..-$bc-1]);
my $ca = avg(@{$data->{rtt}}[-$bc..-1]);
return undef unless $ha and $ca;
return &{$self->{param}{sub}}($ca/$ha,$self->{param}{value});
}