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 
     21 my $default_interval = 3;
     22 my $nlines = 20;
     23 my $print_thread;
     24 my $print_pending = 0;
     25 
     26 my %reads;
     27 my %writes;
     28 
     29 my $interval = shift;
     30 if (!$interval) {
     31     $interval = $default_interval;
     32 }
     33 
     34 sub syscalls::sys_exit_read
     35 {
     36     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
     37 	$common_pid, $common_comm,
     38 	$nr, $ret) = @_;
     39 
     40     print_check();
     41 
     42     if ($ret > 0) {
     43 	$reads{$common_pid}{bytes_read} += $ret;
     44     } else {
     45 	if (!defined ($reads{$common_pid}{bytes_read})) {
     46 	    $reads{$common_pid}{bytes_read} = 0;
     47 	}
     48 	$reads{$common_pid}{errors}{$ret}++;
     49     }
     50 }
     51 
     52 sub syscalls::sys_enter_read
     53 {
     54     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
     55 	$common_pid, $common_comm,
     56 	$nr, $fd, $buf, $count) = @_;
     57 
     58     print_check();
     59 
     60     $reads{$common_pid}{bytes_requested} += $count;
     61     $reads{$common_pid}{total_reads}++;
     62     $reads{$common_pid}{comm} = $common_comm;
     63 }
     64 
     65 sub syscalls::sys_exit_write
     66 {
     67     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
     68 	$common_pid, $common_comm,
     69 	$nr, $ret) = @_;
     70 
     71     print_check();
     72 
     73     if ($ret <= 0) {
     74 	$writes{$common_pid}{errors}{$ret}++;
     75     }
     76 }
     77 
     78 sub syscalls::sys_enter_write
     79 {
     80     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
     81 	$common_pid, $common_comm,
     82 	$nr, $fd, $buf, $count) = @_;
     83 
     84     print_check();
     85 
     86     $writes{$common_pid}{bytes_written} += $count;
     87     $writes{$common_pid}{total_writes}++;
     88     $writes{$common_pid}{comm} = $common_comm;
     89 }
     90 
     91 sub trace_begin
     92 {
     93     $SIG{ALRM} = \&set_print_pending;
     94     alarm 1;
     95 }
     96 
     97 sub trace_end
     98 {
     99     print_unhandled();
    100     print_totals();
    101 }
    102 
    103 sub print_check()
    104 {
    105     if ($print_pending == 1) {
    106 	$print_pending = 0;
    107 	print_totals();
    108     }
    109 }
    110 
    111 sub set_print_pending()
    112 {
    113     $print_pending = 1;
    114     alarm $interval;
    115 }
    116 
    117 sub print_totals
    118 {
    119     my $count;
    120 
    121     $count = 0;
    122 
    123     clear_term();
    124 
    125     printf("\nread counts by pid:\n\n");
    126 
    127     printf("%6s  %20s  %10s  %10s  %10s\n", "pid", "comm",
    128 	   "# reads", "bytes_req", "bytes_read");
    129     printf("%6s  %-20s  %10s  %10s  %10s\n", "------", "--------------------",
    130 	   "----------", "----------", "----------");
    131 
    132     foreach my $pid (sort { ($reads{$b}{bytes_read} || 0) <=>
    133 			       ($reads{$a}{bytes_read} || 0) } keys %reads) {
    134 	my $comm = $reads{$pid}{comm} || "";
    135 	my $total_reads = $reads{$pid}{total_reads} || 0;
    136 	my $bytes_requested = $reads{$pid}{bytes_requested} || 0;
    137 	my $bytes_read = $reads{$pid}{bytes_read} || 0;
    138 
    139 	printf("%6s  %-20s  %10s  %10s  %10s\n", $pid, $comm,
    140 	       $total_reads, $bytes_requested, $bytes_read);
    141 
    142 	if (++$count == $nlines) {
    143 	    last;
    144 	}
    145     }
    146 
    147     $count = 0;
    148 
    149     printf("\nwrite counts by pid:\n\n");
    150 
    151     printf("%6s  %20s  %10s  %13s\n", "pid", "comm",
    152 	   "# writes", "bytes_written");
    153     printf("%6s  %-20s  %10s  %13s\n", "------", "--------------------",
    154 	   "----------", "-------------");
    155 
    156     foreach my $pid (sort { ($writes{$b}{bytes_written} || 0) <=>
    157 			($writes{$a}{bytes_written} || 0)} keys %writes) {
    158 	my $comm = $writes{$pid}{comm} || "";
    159 	my $total_writes = $writes{$pid}{total_writes} || 0;
    160 	my $bytes_written = $writes{$pid}{bytes_written} || 0;
    161 
    162 	printf("%6s  %-20s  %10s  %13s\n", $pid, $comm,
    163 	       $total_writes, $bytes_written);
    164 
    165 	if (++$count == $nlines) {
    166 	    last;
    167 	}
    168     }
    169 
    170     %reads = ();
    171     %writes = ();
    172 }
    173 
    174 my %unhandled;
    175 
    176 sub print_unhandled
    177 {
    178     if ((scalar keys %unhandled) == 0) {
    179 	return;
    180     }
    181 
    182     print "\nunhandled events:\n\n";
    183 
    184     printf("%-40s  %10s\n", "event", "count");
    185     printf("%-40s  %10s\n", "----------------------------------------",
    186 	   "-----------");
    187 
    188     foreach my $event_name (keys %unhandled) {
    189 	printf("%-40s  %10d\n", $event_name, $unhandled{$event_name});
    190     }
    191 }
    192 
    193 sub trace_unhandled
    194 {
    195     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
    196 	$common_pid, $common_comm) = @_;
    197 
    198     $unhandled{$event_name}++;
    199 }
    200