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   762750 use 5.008001;
  22         84  
3 22     22   89 use strict;
  22         33  
  22         356  
4 22     22   97 use warnings;
  22         44  
  22         595  
5              
6 22     22   364 use Capture::Tiny qw/capture/;
  22         44  
  22         885  
7 22     22   6694 use Parallel::ForkManager;
  22         155064  
  22         649  
8 22     22   7611 use Linux::GetPidstat::Collector::Parser;
  22         62  
  22         14173  
9              
10             my $GETPIDSTAT_DEBUG = sub {
11             $ENV{GETPIDSTAT_DEBUG} ? 1 : 0;
12             };
13              
14             sub new {
15 53     53 0 8725 my ( $class, %opt ) = @_;
16 53         325 bless \%opt, $class;
17             }
18              
19             sub get_pidstats_results {
20 59     59 0 49311 my ($self, $program_pid_mapping) = @_;
21              
22 59         121 my $ret_pidstats;
23              
24 59         647 my $pm = Parallel::ForkManager->new(scalar @$program_pid_mapping);
25             $pm->run_on_finish(sub {
26 82 50   82   41083219 if (my $ret = $_[5]) {
27 82         350 my ($program_name, $ret_pidstat, $stdout, $stderr) = @$ret;
28              
29 82 50       366 print $stdout, "\n" if $stdout;
30 82 100       983 warn $stderr if $stderr;
31              
32 82 100 66     765 if ($program_name && $ret_pidstat) {
33 56         135 push @{$ret_pidstats->{$program_name}}, $ret_pidstat;
  56         352  
34 56         373 return;
35             }
36             }
37              
38 26 100       137 warn "Failed to collect metrics\n" if $GETPIDSTAT_DEBUG->();
39 59         24626 });
40              
41             METHODS:
42 59         811 for my $info (@$program_pid_mapping) {
43 109         533 my $program_name = $info->{program_name};
44 109         210 my $pids = join(",", @{$info->{pids}});
  109         927  
45              
46 109 100       723 if (my $child_pid = $pm->start) {
47 91 100       71437 printf "child_pid=%d, program_name=%s, target_pids=%s\n",
48             $child_pid, $program_name, $pids if $GETPIDSTAT_DEBUG->();
49 91         1759 next METHODS;
50             }
51              
52 18         22748 my $ret_pidstat;
53             my ($stdout, $stderr) = capture {
54 18     18   33819 $ret_pidstat = $self->get_pidstat($pids);
55 18 100 66     311 unless ($ret_pidstat && %$ret_pidstat) {
56 6         144 warn sprintf
57             "Failed getting pidstat: pid=%d, target_pids=%s, program_name=%s\n",
58             $$, $pids, $program_name;
59             }
60 18         4053 };
61              
62 18         12973 $pm->finish(0, [$program_name, $ret_pidstat, $stdout, $stderr]);
63             }
64 41         656 $pm->wait_all_children;
65              
66 41         742 return summarize($ret_pidstats);
67             }
68              
69             sub get_pidstat {
70 18     18 0 107 my ($self, $pids) = @_;
71 18         564 my $command = _command_get_pidstat($pids, $self->{interval}, $self->{count});
72 18     18   1230 my ($stdout, $stderr, $exit) = capture { system $command };
  18         66212  
73              
74 18 50 66     18191 if (!$stdout or $stderr or $exit != 0) {
      66        
75 2         17 chomp($stderr);
76 2         82 warn sprintf
77             "Failed a command: %s, pid=%d, stdout=%s, stderr=%s, exit=%s\n",
78             $command, $$, $stdout, $stderr, $exit;
79 2         26 return;
80             }
81              
82 16         336 my @lines = split '\n', $stdout;
83 16         293 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 178 my $ret_pidstats = shift;
94              
95 41         153 my $summary = {};
96              
97             # in : backup_mysql => [ { cpu => 21.0... } ... ] ...
98             # out: backup_mysql => { cpu => 42.0 } ... } ...
99 41         344 while (my ($program_name, $rets) = each %$ret_pidstats) {
100 56         135 for my $ret (@{$rets}) {
  56         205  
101 56         302 while (my ($metric_name, $metric) = each %$ret) {
102 504         1844 $summary->{$program_name}->{$metric_name} += $metric;
103             }
104             }
105             }
106 41         449 return $summary;
107             }
108              
109             1;
110             __END__