mirror of
https://github.com/percona/percona-toolkit.git
synced 2025-09-04 19:37:49 +00:00
121 lines
4.0 KiB
Perl
121 lines
4.0 KiB
Perl
# This program is copyright 2010-2011 Percona Inc.
|
|
# Feedback and improvements are welcome.
|
|
#
|
|
# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
|
|
# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
|
# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
#
|
|
# 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, version 2; OR the Perl Artistic License. On UNIX and similar
|
|
# systems, you can issue `man perlgpl' or `man perlartistic' to read these
|
|
# licenses.
|
|
#
|
|
# 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., 59 Temple
|
|
# Place, Suite 330, Boston, MA 02111-1307 USA.
|
|
# ###########################################################################
|
|
# TimeSeriesTrender package $Revision: 7096 $
|
|
# ###########################################################################
|
|
|
|
# Package: TimeSeriesTrender
|
|
# TimeSeriesTrender calculates trends in time.
|
|
{
|
|
package TimeSeriesTrender;
|
|
|
|
use strict;
|
|
use warnings FATAL => 'all';
|
|
use English qw(-no_match_vars);
|
|
use constant MKDEBUG => $ENV{MKDEBUG} || 0;
|
|
|
|
# Arguments:
|
|
# * callback Subroutine to call when the time is set to the next larger
|
|
# increment. Receives a hashref of the current timestamp's
|
|
# stats (see compute_stats()).
|
|
sub new {
|
|
my ( $class, %args ) = @_;
|
|
foreach my $arg ( qw(callback) ) {
|
|
die "I need a $arg argument" unless defined $args{$arg};
|
|
}
|
|
my $self = {
|
|
%args,
|
|
ts => '',
|
|
numbers => [],
|
|
};
|
|
return bless $self, $class;
|
|
}
|
|
|
|
# Set the current timestamp to be applied to all subsequent values received
|
|
# through add_number(). If the timestamp changes to the "next larger
|
|
# increment," then fire the callback. It *is* possible for a timestamp to be
|
|
# less than one previously seen. In such cases, we simply lump those
|
|
# time-series data points into the current timestamp's bucket.
|
|
sub set_time {
|
|
my ( $self, $ts ) = @_;
|
|
my $cur_ts = $self->{ts};
|
|
if ( !$cur_ts ) {
|
|
$self->{ts} = $ts;
|
|
}
|
|
elsif ( $ts gt $cur_ts ) {
|
|
my $statistics = $self->compute_stats($cur_ts, $self->{numbers});
|
|
$self->{callback}->($statistics);
|
|
$self->{numbers} = [];
|
|
$self->{ts} = $ts;
|
|
}
|
|
# If $cur_ts > $ts, then we do nothing -- we do not want $self->{ts} to ever
|
|
# decrease!
|
|
}
|
|
|
|
# Add a number to the current batch defined by the current timestamp, which is
|
|
# set by set_time().
|
|
sub add_number {
|
|
my ( $self, $number ) = @_;
|
|
push @{$self->{numbers}}, $number;
|
|
}
|
|
|
|
# Compute the desired statistics over the set of numbers, which is passed in as
|
|
# an arrayref. Returns a hashref.
|
|
sub compute_stats {
|
|
my ( $self, $ts, $numbers ) = @_;
|
|
my $cnt = scalar @$numbers;
|
|
my $result = {
|
|
ts => $ts,
|
|
cnt => 0,
|
|
sum => 0,
|
|
min => 0,
|
|
max => 0,
|
|
avg => 0,
|
|
stdev => 0,
|
|
};
|
|
return $result unless $cnt;
|
|
my ( $sum, $min, $max, $sumsq ) = (0, 2 ** 32, 0, 0);
|
|
foreach my $num ( @$numbers ) {
|
|
$sum += $num;
|
|
$min = $num < $min ? $num : $min;
|
|
$max = $num > $max ? $num : $max;
|
|
$sumsq += $num * $num;
|
|
}
|
|
my $avg = $sum / $cnt;
|
|
my $var = $sumsq / $cnt - ( $avg * $avg );
|
|
my $stdev = $var > 0 ? sqrt($var) : 0;
|
|
# TODO: must compute the significant digits of the input, and use that to
|
|
# round the output appropriately.
|
|
@{$result}{qw(cnt sum min max avg stdev)}
|
|
= ($cnt, $sum, $min, $max, $avg, $stdev);
|
|
return $result;
|
|
}
|
|
|
|
sub _d {
|
|
my ($package, undef, $line) = caller 0;
|
|
@_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
|
|
map { defined $_ ? $_ : 'undef' }
|
|
@_;
|
|
print STDERR "# $package:$line $PID ", join(' ', @_), "\n";
|
|
}
|
|
|
|
1;
|
|
}
|
|
# ###########################################################################
|
|
# End TimeSeriesTrender package
|
|
# ###########################################################################
|