sub add_process { my $procs = shift; my $cmds = shift; my $pid = shift; my $start = shift; my $exe = shift; my $parent = shift || -1; $procs->{$pid} = { start => $start, end => -1, parent => $parent, cmd => [$exe], sys => 0, user => 0, read => {}, write => {}, kids => {}, }; $cmds->{$exe} = {} unless $cmds->{$exe}; $cmds->{$exe}->{$kid} = 1; } sub parse_data { my $procs = shift; my $cmds = shift; my $lasttime = 0; while () { if (/^(\d+)\s+(\d+)\s+\((.*?)\)\s+(.*)\s+$/) { my $time = $1; my $pid = $2; my $exe = $3; my $op = $4; $lasttime = $time; if (! exists $procs->{$pid}) { &add_process($procs, $cmds, $pid, $time, $exe); } if ($op =~ /exit\suser:\s(\d+)\ssys:\s(\d+)/) { my $user = $1; my $sys = $2; $procs->{$pid}->{end} = $time; $procs->{$pid}->{sys} = $sys; $procs->{$pid}->{user} = $user; # hwclock warps system time, so adjust, pretending it takes # no time to execute if ($exe =~ /hwclock/) { my $duration = $procs->{$pid}->{end} - $procs->{$pid}->{start}; my $tmp = $procs->{$pid}; $tmp->{start} += $duration; while ($tmp->{parent}) { $tmp = $procs->{$tmp->{parent}}; $tmp->{start} += $duration; if ($tmp->{end}) { $tmp->{end} += $duration; } } } } elsif ($op =~ /fork\s(\d+)/) { my $kid = $1; &add_process($procs, $cmds, $kid, $time, $exe, $pid); $procs->{$pid}->{kids}->{$kid} = 1; } elsif ($op =~ /exec\s(.*)/) { my $path = $1; my $bin = (splitpath($path))[2]; push @{$procs->{$pid}->{cmd}}, $bin; $cmds->{$bin} = {} unless $cmds->{$bin}; $cmds->{$bin}->{$pid} = 1; } elsif ($op =~ /access\s(.*?)\sread:\s(\d+)\swrite:\s(\d+)/) { my $file = $1; my $read = $2; my $write = $3; if ($read) { $procs->{$pid}->{read}->{$file} = [] unless $procs->{$pid}->{read}->{$file}; push @{$procs->{$pid}->{read}->{$file}}, { time => $time, bytes => $read, }; } if ($write) { $procs->{$pid}->{write}->{$file} = [] unless $procs->{$pid}->{write}->{$file}; push @{$procs->{$pid}->{write}->{$file}}, { time => $time, bytes => $write, }; } } else { print "cannot grok '$_'\n"; } } } return $lasttime; } sub accumulate_stats { my $procs = shift; my $stats = shift; foreach my $pid (keys %{$procs}) { if ($procs->{$pid}->{parent} == -1) { $stats->{$pid} = {}; &do_accumulate_stats($procs, $stats->{$pid}, $pid); } } } sub do_accumulate_stats { my $procs = shift; my $stats = shift; my $pid = shift; my $proc = $procs->{$pid}; my $nread = 0; my $nwrite = 0; foreach my $file (keys %{$proc->{read}}) { $nread += $proc->{read}->{$file}; } foreach my $file (keys %{$proc->{write}}) { $nwrite += $proc->{write}->{$file}; } my $cnread = $nread; my $cnwrite = $nwrite; my $csys = $proc->{sys}; my $cuser = $proc->{user}; foreach my $kid (keys %{$proc->{kids}}) { &do_accumulate_stats($procs, $stats, $kid); my $cstats = $stats->{$kid}; $cnread+= $cstats->[0]; $cnwrite+= $cstats->[1]; $csys+= $cstats->[2]; $cuser+= $cstats->[3]; } $stats->{$pid} = [ $nread, $nwrite, $proc->{sys}, $proc->{user}, $cnread, $cnwrite, $csys, $cuser ]; }