1package Smokeping::matchers::Median; 2 3=head1 NAME 4 5Smokeping::matchers::Median - Find persistent changes in latency 6 7=head1 OVERVIEW 8 9The idea behind this matcher is to find sustained changes in latency. 10 11The median matcher takes a number of past median latencies. It splits the latencies into 12two groups (old and new) and again finds the median for each groups. If the 13difference between the two medians is bigger than a certain value, it will 14give a match. 15 16=head1 DESCRIPTION 17 18Call the matcher with the following sequence: 19 20 type = matcher 21 pattern = Median(old=>x,new=>y,diff=>z) 22 23This will create a matcher which consumes x+y latency-datapoints, builds the 24two medians and the matches if the difference between the median latency is 25larger than z seconds. 26 27=head1 COPYRIGHT 28 29Copyright (c) 2004 by OETIKER+PARTNER AG. All rights reserved. 30 31=head1 LICENSE 32 33This program is free software; you can redistribute it and/or modify 34it under the terms of the GNU General Public License as published by 35the Free Software Foundation; either version 2 of the License, or 36(at your option) any later version. 37 38This program is distributed in the hope that it will be useful, 39but WITHOUT ANY WARRANTY; without even the implied warranty of 40MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 41GNU General Public License for more details. 42 43You should have received a copy of the GNU General Public License 44along with this program; if not, write to the Free Software 45Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 46 47=head1 AUTHOR 48 49Tobias Oetiker <tobi@oetiker.ch> 50 51=cut 52 53use strict; 54use base qw(Smokeping::matchers::base); 55use vars qw($VERSION); 56$VERSION = 1.0; 57use Carp; 58 59sub new(@) 60{ 61 my $class = shift; 62 my $rules = { 63 old=>'\d+', 64 new=>'\d+', 65 diff=>'\d+(\.\d+)?' }; 66 67 my $self = $class->SUPER::new($rules,@_); 68 return $self; 69} 70 71# how many values does the matcher need to do it's magic 72sub Length($) 73{ 74 my $self = shift; 75 return $self->{param}{old} + $self->{param}{new}; 76} 77 78sub Desc ($) { 79 croak "Find changes in median latency"; 80} 81 82sub Test($$) 83{ my $self = shift; 84 my $data = shift; # @{$data->{rtt}} and @{$data->{loss}} 85 my $ac = $self->{param}{old}; 86 my $bc = $self->{param}{new}; 87 my $cc = $ac +$bc; 88 my $count = scalar @{$data->{rtt}}; 89 $cc = $count if $count < $cc; 90 $bc = $count if $count < $bc; 91 my $oldm = robust_median(@{$data->{rtt}}[-$cc..-$bc-1]); 92 my $newm = robust_median(@{$data->{rtt}}[-$bc..-1]); 93 return abs($oldm-$newm) > $self->{param}{diff}; 94} 95 96sub robust_median(@){ 97 my @numbers = sort {$a <=> $b} grep { defined $_ and $_ =~ /\d/ } @_; 98 my $count = $#numbers; 99 return 0 if $count < 0; 100 return ($count / 2 == int($count/2)) ? $numbers[$count/2] : ($numbers[$count/2+0.5] + $numbers[$count/2-0.5])/2; 101} 102