package Brackup::BackupStats; use strict; sub new { my $class = shift; my %opts = @_; croak("Unknown options: " . join(', ', keys %opts)) if %opts; my $self = { start_time => time, ts => Brackup::BackupStats::Data->new, data => Brackup::BackupStats::Data->new, }; if (eval { require GTop }) { $self->{gtop} = GTop->new; $self->{gtop_max} = 0; $self->{gtop_data} = Brackup::BackupStats::Data->new; } return bless $self, $class; } sub print { my $self = shift; my $stats_file = shift; # Reset iterators $self->reset; my $fh; if ($stats_file) { open $fh, ">$stats_file" or die "Failed to open stats file '$stats_file': $!"; } else { $fh = *STDOUT; } my $hash = $stats_file ? '' : '# '; print $fh "${hash}BACKUPS STATS:\n"; print $fh "${hash}\n"; my $start_time = $self->{start_time}; my $end_time = time; my $fmt = "${hash}%-37s %s\n"; printf $fh $fmt, 'Start Time:', scalar localtime $start_time; printf $fh $fmt, 'End Time:', scalar localtime $end_time; my $ts = $start_time; while (my ($label, $next_ts) = $self->{ts}->next) { printf $fh $fmt, "$label Time:", ($next_ts - $ts) . 's'; $ts = $next_ts; } printf $fh $fmt, 'Total Run Time:', ($end_time - $start_time) . 's'; print $fh "${hash}\n"; if (my $gtop_data = $self->{gtop_data}) { while (my ($label, $size) = $gtop_data->next) { printf $fh $fmt, "Post $label Memory Usage:", sprintf('%0.1f MB', $size / (1024 * 1024)); } printf $fh $fmt, 'Peak Memory Usage:', sprintf('%0.1f MB', $self->{gtop_max} / (1024 * 1024)); print $fh "${hash}\n"; } else { print $fh "${hash}GTop not installed, memory usage stats disabled\n"; print $fh "${hash}\n"; } my $data = $self->{data}; while (my ($key, $value) = $data->next) { printf $fh $fmt, $key, $value; } print $fh "\n" if $stats_file; } # Check/record max memory usage sub check_maxmem { my $self = shift; return unless $self->{gtop}; my $mem = $self->{gtop}->proc_mem($$)->size; $self->{gtop_max} = $mem if $mem > $self->{gtop_max}; } # Record current time (and memory, if applicable) against $label sub timestamp { my ($self, $label) = @_; $self->{ts}->set($label => time); return unless $self->{gtop}; $self->{gtop_data}->set($label => $self->{gtop}->proc_mem($$)->size); $self->check_maxmem; } sub set { my $self = shift; $self->{data}->set(shift, shift) while @_ >= 2; } sub reset { my $self = shift; $self->{ts}->reset; $self->{data}->reset; $self->{gtop_data}->reset if $self->{gtop_data}; } sub note_stored_chunk { my ($self, $chunk) = @_; } package Brackup::BackupStats::Data; sub new { my $class = shift; return bless { index => 0, list => [], # ordered list of data keys data => {}, }, $class; } sub set { my ($self, $key, $value) = @_; die "data key '$key' exists" if exists $self->{data}->{$key}; push @{$self->{list}}, $key; $self->{data}->{$key} = $value; } # Iterator interface, returning ($key, $value) sub next { my $self = shift; return () unless $self->{index} <= $#{$self->{list}}; my $key = $self->{list}->[$self->{index}++]; return ($key, $self->{data}->{$key}); } # Reset/rewind iterator sub reset { my $self = shift; $self->{index} = 0; } 1; # vim:sw=4