File Coverage

blib/lib/Linux/GetPidstat/Reader.pm
Criterion Covered Total %
statement 62 64 96.8
branch 17 18 94.4
condition 5 6 83.3
subroutine 11 12 91.6
pod 0 3 0.0
total 95 103 92.2


line stmt bran cond sub pod time code
1             package Linux::GetPidstat::Reader;
2 14     14   79749 use 5.008001;
  14         65  
3 14     14   79 use strict;
  14         28  
  14         292  
4 14     14   55 use warnings;
  14         28  
  14         304  
5              
6 14     14   166 use Carp;
  14         41  
  14         1418  
7 14     14   695 use Capture::Tiny qw/capture/;
  14         33108  
  14         809  
8 14     14   1530 use Path::Tiny qw/path/;
  14         24126  
  14         6637  
9              
10             sub new {
11 54     54 0 24860 my ( $class, %opt ) = @_;
12 54         304 bless \%opt, $class;
13             }
14              
15             sub get_program_pid_mapping {
16 53     53 0 4742 my $self = shift;
17              
18 53         308 my $pid_dir = path($self->{pid_dir});
19              
20 53         1821 my @program_pid_mapping;
21 53         306 for my $pid_file ($pid_dir->children) {
22             # Skip processing if there are no more files after directory scanning
23 105 50       10201 next unless -e $pid_file;
24              
25 105         1946 my $pid = $pid_file->slurp;
26             # Skip processing if it could not read anything from the file
27 105 100       17113 next if length($pid) == 0;
28              
29 104         229 chomp($pid);
30 104 100       268 unless (_is_valid_pid($pid)) {
31 26         67 next;
32             }
33              
34 78         128 my @pids;
35 78         201 push @pids, $pid;
36              
37 78 100       271 if ($self->{include_child}) {
38 76         208 my $child_pids = $self->search_child_pids($pid);
39 76         248 push @pids, @$child_pids;
40             }
41              
42 78         541 push @program_pid_mapping, {
43             program_name => $pid_file->basename,
44             pids => \@pids,
45             };
46             }
47              
48 53         2201 return \@program_pid_mapping;
49             }
50              
51             sub search_child_pids {
52 76     76 0 232 my ($self, $pid) = @_;
53 76         259 my $command = _command_search_child_pids($pid);
54 76     76   3760 my ($stdout, $stderr, $exit) = capture { system $command };
  76         292335  
55              
56 76 100 66     57500 if (length $stderr or $exit != 0) {
57 1         7 chomp ($stderr);
58 1         227 carp "Failed a command: $command, stdout=$stdout, stderr=$stderr, exit=$exit";
59             }
60 76 100       307 unless (length $stdout) {
61 1         9 return [];
62             }
63              
64 75         151 my @child_pids;
65              
66 75         886 my @lines = split '\n', $stdout;
67 75         190 for (@lines) {
68 1925         4175 while (/[^}]\((\d+)\)/g) {
69 260         706 my $child_pid = $1;
70 260 100       695 next if $child_pid == $pid;
71              
72             # TODO: Remove the limit.
73             ## FIXME: Replace calling pidstat with reading /proc manually
74 185         316 my $max = $self->{max_child_limit};
75 185 100 100     430 if ($max && $max <= scalar @child_pids) {
76 2         257 carp "Stop searching child pids. max_child_limit is too little. pid=$pid";
77 2         77 last;
78             }
79 183         518 push @child_pids, $child_pid;
80             }
81             }
82 75         412 return \@child_pids;
83             }
84              
85             # for mock in tests
86             sub _command_search_child_pids {
87 0     0   0 my $pid = shift;
88 0         0 return "pstree -pn $pid";
89             }
90              
91             sub _is_valid_pid {
92 104     104   244 my $pid = shift;
93 104 100       748 unless ($pid =~ /^[0-9]+$/) {
94 26         2815 carp "invalid pid: $pid";
95 26         1329 return 0;
96             }
97 78         218 return 1;
98             }
99              
100             1;
101             __END__