Home | History | Annotate | Download | only in perl
      1 #!/usr/bin/perl -w
      2 # (c) 2010, Tom Zanussi <tzanussi (at] gmail.com>
      3 # Licensed under the terms of the GNU GPL License version 2
      4 
      5 # read/write top
      6 #
      7 # Periodically displays system-wide r/w call activity, broken down by
      8 # pid.  If an [interval] arg is specified, the display will be
      9 # refreshed every [interval] seconds.  The default interval is 3
     10 # seconds.
     11 
     12 use 5.010000;
     13 use strict;
     14 use warnings;
     15 
     16 use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
     17 use lib "./Perf-Trace-Util/lib";
     18 use Perf::Trace::Core;
     19 use Perf::Trace::Util;
     20 use POSIX qw/SIGALRM SA_RESTART/;
     21 
     22 my $default_interval = 3;
     23 my $nlines = 20;
     24 my $print_thread;
     25 my $print_pending = 0;
     26 
     27 my %reads;
     28 my %writes;
     29 
     30 my $interval = shift;
     31 if (!$interval) {
     32     $interval = $default_interval;
     33 }
     34 
     35 sub syscalls::sys_exit_read
     36 {
     37     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
     38 	$common_pid, $common_comm,
     39 	$nr, $ret) = @_;
     40 
     41     print_check();
     42 
     43     if ($ret > 0) {
     44 	$reads{$common_pid}{bytes_read} += $ret;
     45     } else {
     46 	if (!defined ($reads{$common_pid}{bytes_read})) {
     47 	    $reads{$common_pid}{bytes_read} = 0;
     48 	}
     49 	$reads{$common_pid}{errors}{$ret}++;
     50     }
     51 }
     52 
     53 sub syscalls::sys_enter_read
     54 {
     55     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
     56 	$common_pid, $common_comm,
     57 	$nr, $fd, $buf, $count) = @_;
     58 
     59     print_check();
     60 
     61     $reads{$common_pid}{bytes_requested} += $count;
     62     $reads{$common_pid}{total_reads}++;
     63     $reads{$common_pid}{comm} = $common_comm;
     64 }
     65 
     66 sub syscalls::sys_exit_write
     67 {
     68     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
     69 	$common_pid, $common_comm,
     70 	$nr, $ret) = @_;
     71 
     72     print_check();
     73 
     74     if ($ret <= 0) {
     75 	$writes{$common_pid}{errors}{$ret}++;
     76     }
     77 }
     78 
     79 sub syscalls::sys_enter_write
     80 {
     81     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
     82 	$common_pid, $common_comm,
     83 	$nr, $fd, $buf, $count) = @_;
     84 
     85     print_check();
     86 
     87     $writes{$common_pid}{bytes_written} += $count;
     88     $writes{$common_pid}{total_writes}++;
     89     $writes{$common_pid}{comm} = $common_comm;
     90 }
     91 
     92 sub trace_begin
     93 {
     94     my $sa = POSIX::SigAction->new(\&set_print_pending);
     95     $sa->flags(SA_RESTART);
     96     $sa->safe(1);
     97     POSIX::sigaction(SIGALRM, $sa) or die "Can't set SIGALRM handler: $!\n";
     98     alarm 1;
     99 }
    100 
    101 sub trace_end
    102 {
    103     print_unhandled();
    104     print_totals();
    105 }
    106 
    107 sub print_check()
    108 {
    109     if ($print_pending == 1) {
    110 	$print_pending = 0;
    111 	print_totals();
    112     }
    113 }
    114 
    115 sub set_print_pending()
    116 {
    117     $print_pending = 1;
    118     alarm $interval;
    119 }
    120 
    121 sub print_totals
    122 {
    123     my $count;
    124 
    125     $count = 0;
    126 
    127     clear_term();
    128 
    129     printf("\nread counts by pid:\n\n");
    130 
    131     printf("%6s  %20s  %10s  %10s  %10s\n", "pid", "comm",
    132 	   "# reads", "bytes_req", "bytes_read");
    133     printf("%6s  %-20s  %10s  %10s  %10s\n", "------", "--------------------",
    134 	   "----------", "----------", "----------");
    135 
    136     foreach my $pid (sort { ($reads{$b}{bytes_read} || 0) <=>
    137 			       ($reads{$a}{bytes_read} || 0) } keys %reads) {
    138 	my $comm = $reads{$pid}{comm} || "";
    139 	my $total_reads = $reads{$pid}{total_reads} || 0;
    140 	my $bytes_requested = $reads{$pid}{bytes_requested} || 0;
    141 	my $bytes_read = $reads{$pid}{bytes_read} || 0;
    142 
    143 	printf("%6s  %-20s  %10s  %10s  %10s\n", $pid, $comm,
    144 	       $total_reads, $bytes_requested, $bytes_read);
    145 
    146 	if (++$count == $nlines) {
    147 	    last;
    148 	}
    149     }
    150 
    151     $count = 0;
    152 
    153     printf("\nwrite counts by pid:\n\n");
    154 
    155     printf("%6s  %20s  %10s  %13s\n", "pid", "comm",
    156 	   "# writes", "bytes_written");
    157     printf("%6s  %-20s  %10s  %13s\n", "------", "--------------------",
    158 	   "----------", "-------------");
    159 
    160     foreach my $pid (sort { ($writes{$b}{bytes_written} || 0) <=>
    161 			($writes{$a}{bytes_written} || 0)} keys %writes) {
    162 	my $comm = $writes{$pid}{comm} || "";
    163 	my $total_writes = $writes{$pid}{total_writes} || 0;
    164 	my $bytes_written = $writes{$pid}{bytes_written} || 0;
    165 
    166 	printf("%6s  %-20s  %10s  %13s\n", $pid, $comm,
    167 	       $total_writes, $bytes_written);
    168 
    169 	if (++$count == $nlines) {
    170 	    last;
    171 	}
    172     }
    173 
    174     %reads = ();
    175     %writes = ();
    176 }
    177 
    178 my %unhandled;
    179 
    180 sub print_unhandled
    181 {
    182     if ((scalar keys %unhandled) == 0) {
    183 	return;
    184     }
    185 
    186     print "\nunhandled events:\n\n";
    187 
    188     printf("%-40s  %10s\n", "event", "count");
    189     printf("%-40s  %10s\n", "----------------------------------------",
    190 	   "-----------");
    191 
    192     foreach my $event_name (keys %unhandled) {
    193 	printf("%-40s  %10d\n", $event_name, $unhandled{$event_name});
    194     }
    195 }
    196 
    197 sub trace_unhandled
    198 {
    199     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
    200 	$common_pid, $common_comm) = @_;
    201 
    202     $unhandled{$event_name}++;
    203 }
    204