File Coverage

blib/lib/Brackup/BackupStats.pm
Criterion Covered Total %
statement 24 75 32.0
branch 5 26 19.2
condition n/a
subroutine 7 12 58.3
pod 0 7 0.0
total 36 120 30.0


line stmt bran cond sub pod time code
1             package Brackup::BackupStats;
2 13     13   87 use strict;
  13         129  
  13         24639  
3              
4             sub new {
5 8     8 0 28 my $class = shift;
6 8         22 my %opts = @_;
7 8 50       36 croak("Unknown options: " . join(', ', keys %opts)) if %opts;
8              
9 8         118 my $self = {
10             start_time => time,
11             ts => Brackup::BackupStats::Data->new,
12             data => Brackup::BackupStats::Data->new,
13             };
14              
15 8 50       26 if (eval { require GTop }) {
  8         5073  
16 0         0 $self->{gtop} = GTop->new;
17 0         0 $self->{gtop_max} = 0;
18 0         0 $self->{gtop_data} = Brackup::BackupStats::Data->new;
19             }
20              
21 8         66 return bless $self, $class;
22             }
23              
24             sub print {
25 0     0 0 0 my $self = shift;
26 0         0 my $stats_file = shift;
27            
28             # Reset iterators
29 0         0 $self->reset;
30              
31 0         0 my $fh;
32 0 0       0 if ($stats_file) {
33 0 0       0 open $fh, ">$stats_file"
34             or die "Failed to open stats file '$stats_file': $!";
35             }
36             else {
37 0         0 $fh = *STDOUT;
38             }
39              
40 0 0       0 my $hash = $stats_file ? '' : '# ';
41 0         0 print $fh "${hash}BACKUPS STATS:\n";
42 0         0 print $fh "${hash}\n";
43              
44 0         0 my $start_time = $self->{start_time};
45 0         0 my $end_time = time;
46 0         0 my $fmt = "${hash}%-37s %s\n";
47 0         0 printf $fh $fmt, 'Start Time:', scalar localtime $start_time;
48 0         0 printf $fh $fmt, 'End Time:', scalar localtime $end_time;
49              
50 0         0 my $ts = $start_time;
51 0         0 while (my ($label, $next_ts) = $self->{ts}->next) {
52 0         0 printf $fh $fmt, "$label Time:", ($next_ts - $ts) . 's';
53 0         0 $ts = $next_ts;
54             }
55 0         0 printf $fh $fmt, 'Total Run Time:', ($end_time - $start_time) . 's';
56 0         0 print $fh "${hash}\n";
57              
58 0 0       0 if (my $gtop_data = $self->{gtop_data}) {
59 0         0 while (my ($label, $size) = $gtop_data->next) {
60 0         0 printf $fh $fmt,
61             "Post $label Memory Usage:", sprintf('%0.1f MB', $size / (1024 * 1024));
62             }
63 0         0 printf $fh $fmt,
64             'Peak Memory Usage:', sprintf('%0.1f MB', $self->{gtop_max} / (1024 * 1024));
65 0         0 print $fh "${hash}\n";
66             } else {
67 0         0 print $fh "${hash}GTop not installed, memory usage stats disabled\n";
68 0         0 print $fh "${hash}\n";
69             }
70              
71 0         0 my $data = $self->{data};
72 0         0 while (my ($key, $value) = $data->next) {
73 0         0 printf $fh $fmt, $key, $value;
74             }
75 0 0       0 print $fh "\n" if $stats_file;
76             }
77              
78             # Check/record max memory usage
79             sub check_maxmem {
80 81     81 0 212 my $self = shift;
81 81 50       847 return unless $self->{gtop};
82 0         0 my $mem = $self->{gtop}->proc_mem($$)->size;
83 0 0       0 $self->{gtop_max} = $mem if $mem > $self->{gtop_max};
84             }
85              
86             # Record current time (and memory, if applicable) against $label
87             sub timestamp {
88 32     32 0 122 my ($self, $label) = @_;
89 32         235 $self->{ts}->set($label => time);
90 32 50       150 return unless $self->{gtop};
91 0         0 $self->{gtop_data}->set($label => $self->{gtop}->proc_mem($$)->size);
92 0         0 $self->check_maxmem;
93             }
94              
95             sub set {
96 32     32 0 114 my $self = shift;
97 32         171 $self->{data}->set(shift, shift) while @_ >= 2;
98             }
99              
100             sub reset {
101 0     0 0 0 my $self = shift;
102 0         0 $self->{ts}->reset;
103 0         0 $self->{data}->reset;
104 0 0       0 $self->{gtop_data}->reset if $self->{gtop_data};
105             }
106              
107             sub note_stored_chunk {
108 0     0 0 0 my ($self, $chunk) = @_;
109             }
110              
111             package Brackup::BackupStats::Data;
112              
113             sub new {
114 16     16   37 my $class = shift;
115 16         163 return bless {
116             index => 0,
117             list => [], # ordered list of data keys
118             data => {},
119             }, $class;
120             }
121              
122             sub set {
123 64     64   142 my ($self, $key, $value) = @_;
124 64 50       256 die "data key '$key' exists" if exists $self->{data}->{$key};
125 64         88 push @{$self->{list}}, $key;
  64         190  
126 64         360 $self->{data}->{$key} = $value;
127             }
128              
129             # Iterator interface, returning ($key, $value)
130             sub next {
131 0     0     my $self = shift;
132 0 0         return () unless $self->{index} <= $#{$self->{list}};
  0            
133 0           my $key = $self->{list}->[$self->{index}++];
134 0           return ($key, $self->{data}->{$key});
135             }
136              
137             # Reset/rewind iterator
138             sub reset {
139 0     0     my $self = shift;
140 0           $self->{index} = 0;
141             }
142              
143             1;
144              
145             # vim:sw=4