File Coverage

blib/lib/Linux/GetPidstat/Collector.pm
Criterion Covered Total %
statement 65 67 97.0
branch 15 18 83.3
condition 8 12 66.6
subroutine 13 14 92.8
pod 0 4 0.0
total 101 115 87.8


line stmt bran cond sub pod time code
1             package Linux::GetPidstat::Collector;
2 22     22   736429 use 5.008001;
  22         67  
3 22     22   88 use strict;
  22         33  
  22         362  
4 22     22   99 use warnings;
  22         32  
  22         534  
5              
6 22     22   90 use Capture::Tiny qw/capture/;
  22         33  
  22         834  
7 22     22   6569 use Parallel::ForkManager;
  22         152742  
  22         582  
8 22     22   6849 use Linux::GetPidstat::Collector::Parser;
  22         53  
  22         11921  
9              
10             my $GETPIDSTAT_DEBUG = sub {
11             $ENV{GETPIDSTAT_DEBUG} ? 1 : 0;
12             };
13              
14             sub new {
15 53     53 0 7437 my ( $class, %opt ) = @_;
16 53         313 bless \%opt, $class;
17             }
18              
19             sub get_pidstats_results {
20 59     59 0 45236 my ($self, $program_pid_mapping) = @_;
21              
22 59         120 my $ret_pidstats;
23              
24 59         541 my $pm = Parallel::ForkManager->new(scalar @$program_pid_mapping);
25             $pm->run_on_finish(sub {
26 82 50   82   41079419 if (my $ret = $_[5]) {
27 82         307 my ($program_name, $ret_pidstat, $stdout, $stderr) = @$ret;
28              
29 82 50       248 print $stdout, "\n" if $stdout;
30 82 100       1020 warn $stderr if $stderr;
31              
32 82 100 66     625 if ($program_name && $ret_pidstat) {
33 56         118 push @{$ret_pidstats->{$program_name}}, $ret_pidstat;
  56         253  
34 56         314 return;
35             }
36             }
37              
38 26 100       109 warn "Failed to collect metrics\n" if $GETPIDSTAT_DEBUG->();
39 59         21081 });
40              
41             METHODS:
42 59         754 for my $info (@$program_pid_mapping) {
43 109         352 my $program_name = $info->{program_name};
44 109         297 my $pids = join(",", @{$info->{pids}});
  109         672  
45              
46 109 100       508 if (my $child_pid = $pm->start) {
47 91 100       77936 printf "child_pid=%d, program_name=%s, target_pids=%s\n",
48             $child_pid, $program_name, $pids if $GETPIDSTAT_DEBUG->();
49 91         1680 next METHODS;
50             }
51              
52 18         18761 my $ret_pidstat;
53             my ($stdout, $stderr) = capture {
54 18     18   35665 $ret_pidstat = $self->get_pidstat($pids);
55 18 100 66     361 unless ($ret_pidstat && %$ret_pidstat) {
56 6         147 warn sprintf
57             "Failed getting pidstat: pid=%d, target_pids=%s, program_name=%s\n",
58             $$, $pids, $program_name;
59             }
60 18         4009 };
61              
62 18         12830 $pm->finish(0, [$program_name, $ret_pidstat, $stdout, $stderr]);
63             }
64 41         548 $pm->wait_all_children;
65              
66 41         613 return summarize($ret_pidstats);
67             }
68              
69             sub get_pidstat {
70 18     18 0 118 my ($self, $pids) = @_;
71 18         533 my $command = _command_get_pidstat($pids, $self->{interval}, $self->{count});
72 18     18   1292 my ($stdout, $stderr, $exit) = capture { system $command };
  18         70739  
73              
74 18 50 66     16895 if (!$stdout or $stderr or $exit != 0) {
      66        
75 2         17 chomp($stderr);
76 2         81 warn sprintf
77             "Failed a command: %s, pid=%d, stdout=%s, stderr=%s, exit=%s\n",
78             $command, $$, $stdout, $stderr, $exit;
79 2         24 return;
80             }
81              
82 16         287 my @lines = split '\n', $stdout;
83 16         212 return parse_pidstat_output(\@lines);
84             }
85              
86             # for mock in tests
87             sub _command_get_pidstat {
88 0     0   0 my ($pids, $interval, $count) = @_;
89 0         0 return "pidstat -h -u -r -s -d -w -p $pids $interval $count";
90             }
91              
92             sub summarize($) {
93 41     41 0 192 my $ret_pidstats = shift;
94              
95 41         138 my $summary = {};
96              
97             # in : backup_mysql => [ { cpu => 21.0... } ... ] ...
98             # out: backup_mysql => { cpu => 42.0 } ... } ...
99 41         254 while (my ($program_name, $rets) = each %$ret_pidstats) {
100 56         123 for my $ret (@{$rets}) {
  56         154  
101 56         216 while (my ($metric_name, $metric) = each %$ret) {
102 504         1526 $summary->{$program_name}->{$metric_name} += $metric;
103             }
104             }
105             }
106 41         386 return $summary;
107             }
108              
109             1;
110             __END__