#!/usr/bin/ksh # # rwtop - display top read/write bytes by process. # Written using DTrace (Solaris 10 3/05). # # This is measuring reads and writes at the application level. This matches # read and write system calls. # # 24-Jul-2005, ver 0.70 # # USAGE: rwtop [-cC] [-j|-Z] [-n name] [-p pid] # [-t top] [interval [count]] # # rwtop # default output, 5 second samples # # -C # don't clear the screen # -c # print counts # -j # print project ID # -Z # print zone ID # -n name # this process name only # -p PID # this PID only # -t top # print top number only # eg, # rwtop 1 # 1 second samples # rwtop -t 10 # print top 10 only # rwtop -n bash # monitor processes named "bash" # rwtop -C 5 12 # print 12 x 5 second samples # # FIELDS: # ZONE Zone ID # PROJ Project ID # UID User ID # PID Process ID # PPID Parent Process ID # CMD Process name # D Direction, Read or Write # BYTES Total bytes during sample # app_r total reads during sample, Kb # app_w total writes during sample, Kb # # SEE ALSO: iotop # # INSPIRATION: top(1) by William LeFebvre # # COPYRIGHT: Copyright (c) 2005 Brendan Gregg. # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at Docs/cddl1.txt # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # CDDL HEADER END # # Author: Brendan Gregg [Sydney, Australia] # # 24-Jul-2005 Brendan Gregg Created this. ############################## # --- Process Arguments --- # ### default variables opt_name=0; opt_pid=0; opt_clear=1; opt_proj=0; opt_zone=0 opt_def=1; opt_bytes=1; filter=0; pname=.; pid=0 opt_top=0; opt_count=0; interval=5; count=-1; top=0 ### process options while getopts Ccn:p:jt:Z name do case $name in C) opt_clear=0 ;; c) opt_count=1; opt_bytes=0 ;; n) opt_name=1; pname=$OPTARG ;; p) opt_pid=1; pid=$OPTARG ;; j) opt_proj=1; opt_def=0 ;; t) opt_top=1; top=$OPTARG ;; Z) opt_zone=1; opt_def=0 ;; h|?) cat <<-END >&2 USAGE: rwtop [-cC] [-j|-Z] [-n name] [-p pid] [-t top] [interval [count]] -C # don't clear the screen -c # print counts -j # print project ID -Z # print zone ID -n name # this process name only -p PID # this PID only -t top # print top number only eg, rwtop # default output, 5 second samples rwtop 1 # 1 second samples rwtop -t 10 # print top 10 only rwtop -n bash # monitor processes named "bash" rwtop -C 5 12 # print 12 x 5 second samples END exit 1 esac done shift $(( $OPTIND - 1 )) ### option logic if [[ "$1" > 0 ]]; then interval=$1; shift fi if [[ "$1" > 0 ]]; then count=$1; shift fi if (( opt_proj && opt_zone )); then opt_proj=0 fi if (( opt_name || opt_pid )); then filter=1 fi if (( opt_clear )); then clearstr=`clear` else clearstr=. fi ################################# # --- Main Program, DTrace --- # /usr/sbin/dtrace -n ' /* * Command line arguments */ inline int OPT_def = '$opt_def'; inline int OPT_proj = '$opt_proj'; inline int OPT_zone = '$opt_zone'; inline int OPT_clear = '$opt_clear'; inline int OPT_bytes = '$opt_bytes'; inline int OPT_count = '$opt_count'; inline int OPT_name = '$opt_name'; inline int OPT_pid = '$opt_pid'; inline int OPT_top = '$opt_top'; inline int INTERVAL = '$interval'; inline int COUNTER = '$count'; inline int FILTER = '$filter'; inline int TOP = '$top'; inline int PID = '$pid'; inline string NAME = "'$pname'"; inline string CLEAR = "'$clearstr'"; #pragma D option quiet /* * Print header */ dtrace:::BEGIN { /* starting values */ counts = COUNTER; secs = INTERVAL; app_r = 0; app_w = 0; printf("Sampling... Please wait.\n"); } /* * Check event is being traced */ sysinfo:::readch, sysinfo:::writech /pid != $pid/ { /* default is to trace unless filtering, */ this->ok = FILTER ? 0 : 1; /* check each filter, */ (OPT_name == 1 && NAME == execname)? this->ok = 1 : 1; (OPT_pid == 1 && PID == pid) ? this->ok = 1 : 1; } /* * Increment tallys */ sysinfo:::readch /this->ok/ { app_r += arg0; } sysinfo:::writech /this->ok/ { app_w += arg0; } /* * Process event */ sysinfo:::readch, sysinfo:::writech /this->ok/ { /* choose statistic to track */ this->value = OPT_bytes ? arg0 : 1; /* * Save details */ OPT_def ? @out[uid, pid, ppid, execname, probename == "readch" ? "R" : "W"] = sum(this->value) : 1; OPT_proj ? @out[curpsinfo->pr_projid, pid, ppid, execname, probename == "readch" ? "R" : "W"] = sum(this->value) : 1; OPT_zone ? @out[curpsinfo->pr_zoneid, pid, ppid, execname, probename == "readch" ? "R" : "W"] = sum(this->value) : 1; this->ok = 0; } /* * Timer */ profile:::tick-1sec { secs--; } /* * Print Report */ profile:::tick-1sec /secs == 0/ { /* fetch 1 min load average */ this->load1a = `hp_avenrun[0] / 65536; this->load1b = ((`hp_avenrun[0] % 65536) * 100) / 65536; /* convert counters to Kb */ app_r /= 1024; app_w /= 1024; /* print status */ OPT_clear ? printf("%s", CLEAR) : 1; printf("%Y, load: %d.%02d, app_r: %6d Kb, app_w: %6d Kb\n\n", walltimestamp, this->load1a, this->load1b, app_r, app_w); /* print headers */ OPT_def ? printf(" UID ") : 1; OPT_proj ? printf(" PROJ ") : 1; OPT_zone ? printf(" ZONE ") : 1; printf("%6s %6s %-16s %1s", "PID", "PPID", "CMD", "D"); OPT_bytes ? printf(" %16s\n", "BYTES") : 1; OPT_count ? printf(" %16s\n", "COUNT") : 1; /* truncate to top lines if needed */ OPT_top ? trunc(@out, TOP) : 1; /* print data */ printa("%5d %6d %6d %-16s %1s %16@d\n", @out); printf("\n"); /* clear data */ trunc(@out); app_r = 0; app_w = 0; secs = INTERVAL; counts--; } /* * End of program */ profile:::tick-1sec /counts == 0/ { exit(0); } /* * Cleanup for Ctrl-C */ dtrace:::END { trunc(@out); } '