1#!/usr/bin/perl -w 2# SPDX-License-Identifier: GPL-2.0-only 3# (c) 2010, Tom Zanussi <tzanussi@gmail.com> 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 12use 5.010000; 13use strict; 14use warnings; 15 16use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib"; 17use lib "./Perf-Trace-Util/lib"; 18use Perf::Trace::Core; 19use Perf::Trace::Util; 20use POSIX qw/SIGALRM SA_RESTART/; 21 22my $default_interval = 3; 23my $nlines = 20; 24my $print_thread; 25my $print_pending = 0; 26 27my %reads; 28my %writes; 29 30my $interval = shift; 31if (!$interval) { 32 $interval = $default_interval; 33} 34 35sub syscalls::sys_exit_read 36{ 37 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs, 38 $common_pid, $common_comm, $common_callchain, 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 53sub syscalls::sys_enter_read 54{ 55 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs, 56 $common_pid, $common_comm, $common_callchain, 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 66sub syscalls::sys_exit_write 67{ 68 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs, 69 $common_pid, $common_comm, $common_callchain, 70 $nr, $ret) = @_; 71 72 print_check(); 73 74 if ($ret <= 0) { 75 $writes{$common_pid}{errors}{$ret}++; 76 } 77} 78 79sub syscalls::sys_enter_write 80{ 81 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs, 82 $common_pid, $common_comm, $common_callchain, 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 92sub 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 101sub trace_end 102{ 103 print_unhandled(); 104 print_totals(); 105} 106 107sub print_check() 108{ 109 if ($print_pending == 1) { 110 $print_pending = 0; 111 print_totals(); 112 } 113} 114 115sub set_print_pending() 116{ 117 $print_pending = 1; 118 alarm $interval; 119} 120 121sub 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 178my %unhandled; 179 180sub 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 197sub trace_unhandled 198{ 199 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs, 200 $common_pid, $common_comm, $common_callchain) = @_; 201 202 $unhandled{$event_name}++; 203} 204