1235368Sgnn#!/usr/bin/ksh 2235368Sgnn# 3235368Sgnn# rwtop - display top read/write bytes by process. 4235368Sgnn# Written using DTrace (Solaris 10 3/05). 5235368Sgnn# 6235368Sgnn# This is measuring reads and writes at the application level. This matches 7235368Sgnn# read and write system calls. 8235368Sgnn# 9235368Sgnn# $Id: rwtop 3 2007-08-01 10:50:08Z brendan $ 10235368Sgnn# 11235368Sgnn# USAGE: rwtop [-cC] [-j|-Z] [-n name] [-p pid] 12235368Sgnn# [-t top] [interval [count]] 13235368Sgnn# 14235368Sgnn# rwtop # default output, 5 second samples 15235368Sgnn# 16235368Sgnn# -C # don't clear the screen 17235368Sgnn# -c # print counts 18235368Sgnn# -j # print project ID 19235368Sgnn# -Z # print zone ID 20235368Sgnn# -n name # this process name only 21235368Sgnn# -p PID # this PID only 22235368Sgnn# -t top # print top number only 23235368Sgnn# eg, 24235368Sgnn# rwtop 1 # 1 second samples 25235368Sgnn# rwtop -t 10 # print top 10 only 26235368Sgnn# rwtop -n bash # monitor processes named "bash" 27235368Sgnn# rwtop -C 5 12 # print 12 x 5 second samples 28235368Sgnn# 29235368Sgnn# FIELDS: 30235368Sgnn# ZONE Zone ID 31235368Sgnn# PROJ Project ID 32235368Sgnn# UID User ID 33235368Sgnn# PID Process ID 34235368Sgnn# PPID Parent Process ID 35235368Sgnn# CMD Process name 36235368Sgnn# D Direction, Read or Write 37235368Sgnn# BYTES Total bytes during sample 38235368Sgnn# app_r total reads during sample, Kbytes 39235368Sgnn# app_w total writes during sample, Kbytes 40235368Sgnn# 41235368Sgnn# SEE ALSO: iotop 42235368Sgnn# 43235368Sgnn# INSPIRATION: top(1) by William LeFebvre 44235368Sgnn# 45235368Sgnn# COPYRIGHT: Copyright (c) 2005, 2006 Brendan Gregg. 46235368Sgnn# 47235368Sgnn# CDDL HEADER START 48235368Sgnn# 49235368Sgnn# The contents of this file are subject to the terms of the 50235368Sgnn# Common Development and Distribution License, Version 1.0 only 51235368Sgnn# (the "License"). You may not use this file except in compliance 52235368Sgnn# with the License. 53235368Sgnn# 54235368Sgnn# You can obtain a copy of the license at Docs/cddl1.txt 55235368Sgnn# or http://www.opensolaris.org/os/licensing. 56235368Sgnn# See the License for the specific language governing permissions 57235368Sgnn# and limitations under the License. 58235368Sgnn# 59235368Sgnn# CDDL HEADER END 60235368Sgnn# 61235368Sgnn# Author: Brendan Gregg [Sydney, Australia] 62235368Sgnn# 63235368Sgnn# 24-Jul-2005 Brendan Gregg Created this. 64235368Sgnn# 20-Apr-2006 " " Last update. 65235368Sgnn 66235368Sgnn 67235368Sgnn############################## 68235368Sgnn# --- Process Arguments --- 69235368Sgnn# 70235368Sgnn 71235368Sgnn### default variables 72235368Sgnnopt_name=0; opt_pid=0; opt_clear=1; opt_proj=0; opt_zone=0 73235368Sgnnopt_def=1; opt_bytes=1; filter=0; pname=.; pid=0 74235368Sgnnopt_top=0; opt_count=0; interval=5; count=-1; top=0 75235368Sgnn 76235368Sgnn### process options 77235368Sgnnwhile getopts Cchn:p:jt:Z name 78235368Sgnndo 79235368Sgnn case $name in 80235368Sgnn C) opt_clear=0 ;; 81235368Sgnn c) opt_count=1; opt_bytes=0 ;; 82235368Sgnn n) opt_name=1; pname=$OPTARG ;; 83235368Sgnn p) opt_pid=1; pid=$OPTARG ;; 84235368Sgnn j) opt_proj=1; opt_def=0 ;; 85235368Sgnn t) opt_top=1; top=$OPTARG ;; 86235368Sgnn Z) opt_zone=1; opt_def=0 ;; 87235368Sgnn h|?) cat <<-END >&2 88235368Sgnn USAGE: rwtop [-cC] [-j|-Z] [-n name] [-p pid] 89235368Sgnn [-t top] [interval [count]] 90235368Sgnn 91235368Sgnn -C # don't clear the screen 92235368Sgnn -c # print counts 93235368Sgnn -j # print project ID 94235368Sgnn -Z # print zone ID 95235368Sgnn -n name # this process name only 96235368Sgnn -p PID # this PID only 97235368Sgnn -t top # print top number only 98235368Sgnn eg, 99235368Sgnn rwtop # default output, 5 second samples 100235368Sgnn rwtop 1 # 1 second samples 101235368Sgnn rwtop -t 10 # print top 10 only 102235368Sgnn rwtop -n bash # monitor processes named "bash" 103235368Sgnn rwtop -C 5 12 # print 12 x 5 second samples 104235368Sgnn END 105235368Sgnn exit 1 106235368Sgnn esac 107235368Sgnndone 108235368Sgnn 109235368Sgnnshift $(( $OPTIND - 1 )) 110235368Sgnn 111235368Sgnn### option logic 112235368Sgnnif [[ "$1" > 0 ]]; then 113235368Sgnn interval=$1; shift 114235368Sgnnfi 115235368Sgnnif [[ "$1" > 0 ]]; then 116235368Sgnn count=$1; shift 117235368Sgnnfi 118235368Sgnnif (( opt_proj && opt_zone )); then 119235368Sgnn opt_proj=0 120235368Sgnnfi 121235368Sgnnif (( opt_name || opt_pid )); then 122235368Sgnn filter=1 123235368Sgnnfi 124235368Sgnnif (( opt_clear )); then 125235368Sgnn clearstr=`clear` 126235368Sgnnelse 127235368Sgnn clearstr=. 128235368Sgnnfi 129235368Sgnn 130235368Sgnn 131235368Sgnn 132235368Sgnn################################# 133235368Sgnn# --- Main Program, DTrace --- 134235368Sgnn# 135235368Sgnn/usr/sbin/dtrace -n ' 136235368Sgnn /* 137235368Sgnn * Command line arguments 138235368Sgnn */ 139235368Sgnn inline int OPT_def = '$opt_def'; 140235368Sgnn inline int OPT_proj = '$opt_proj'; 141235368Sgnn inline int OPT_zone = '$opt_zone'; 142235368Sgnn inline int OPT_clear = '$opt_clear'; 143235368Sgnn inline int OPT_bytes = '$opt_bytes'; 144235368Sgnn inline int OPT_count = '$opt_count'; 145235368Sgnn inline int OPT_name = '$opt_name'; 146235368Sgnn inline int OPT_pid = '$opt_pid'; 147235368Sgnn inline int OPT_top = '$opt_top'; 148235368Sgnn inline int INTERVAL = '$interval'; 149235368Sgnn inline int COUNTER = '$count'; 150235368Sgnn inline int FILTER = '$filter'; 151235368Sgnn inline int TOP = '$top'; 152235368Sgnn inline int PID = '$pid'; 153235368Sgnn inline string NAME = "'$pname'"; 154235368Sgnn inline string CLEAR = "'$clearstr'"; 155235368Sgnn 156235368Sgnn #pragma D option quiet 157235368Sgnn 158235368Sgnn /* 159235368Sgnn * Print header 160235368Sgnn */ 161235368Sgnn dtrace:::BEGIN 162235368Sgnn { 163235368Sgnn /* starting values */ 164235368Sgnn counts = COUNTER; 165235368Sgnn secs = INTERVAL; 166235368Sgnn app_r = 0; 167235368Sgnn app_w = 0; 168235368Sgnn 169235368Sgnn printf("Tracing... Please wait.\n"); 170235368Sgnn } 171235368Sgnn 172235368Sgnn /* 173235368Sgnn * Check event is being traced 174235368Sgnn */ 175235368Sgnn sysinfo:::readch, 176235368Sgnn sysinfo:::writech 177235368Sgnn /pid != $pid/ 178235368Sgnn { 179235368Sgnn /* default is to trace unless filtering, */ 180235368Sgnn this->ok = FILTER ? 0 : 1; 181235368Sgnn 182235368Sgnn /* check each filter, */ 183235368Sgnn (OPT_name == 1 && NAME == execname)? this->ok = 1 : 1; 184235368Sgnn (OPT_pid == 1 && PID == pid) ? this->ok = 1 : 1; 185235368Sgnn } 186235368Sgnn 187235368Sgnn /* 188235368Sgnn * Increment tallys 189235368Sgnn */ 190235368Sgnn sysinfo:::readch 191235368Sgnn /this->ok/ 192235368Sgnn { 193235368Sgnn app_r += arg0; 194235368Sgnn } 195235368Sgnn sysinfo:::writech 196235368Sgnn /this->ok/ 197235368Sgnn { 198235368Sgnn app_w += arg0; 199235368Sgnn } 200235368Sgnn 201235368Sgnn /* 202235368Sgnn * Process event 203235368Sgnn */ 204235368Sgnn sysinfo:::readch, 205235368Sgnn sysinfo:::writech 206235368Sgnn /this->ok/ 207235368Sgnn { 208235368Sgnn /* choose statistic to track */ 209235368Sgnn this->value = OPT_bytes ? arg0 : 1; 210235368Sgnn 211235368Sgnn /* 212235368Sgnn * Save details 213235368Sgnn */ 214235368Sgnn OPT_def ? @out[uid, pid, ppid, execname, 215235368Sgnn probename == "readch" ? "R" : "W"] = sum(this->value) : 1; 216235368Sgnn OPT_proj ? @out[curpsinfo->pr_projid, pid, ppid, execname, 217235368Sgnn probename == "readch" ? "R" : "W"] = sum(this->value) : 1; 218235368Sgnn OPT_zone ? @out[curpsinfo->pr_zoneid, pid, ppid, execname, 219235368Sgnn probename == "readch" ? "R" : "W"] = sum(this->value) : 1; 220235368Sgnn 221235368Sgnn this->ok = 0; 222235368Sgnn } 223235368Sgnn 224235368Sgnn /* 225235368Sgnn * Timer 226235368Sgnn */ 227235368Sgnn profile:::tick-1sec 228235368Sgnn { 229235368Sgnn secs--; 230235368Sgnn } 231235368Sgnn 232235368Sgnn /* 233235368Sgnn * Print Report 234235368Sgnn */ 235235368Sgnn profile:::tick-1sec 236235368Sgnn /secs == 0/ 237235368Sgnn { 238235368Sgnn /* fetch 1 min load average */ 239235368Sgnn this->load1a = `hp_avenrun[0] / 65536; 240235368Sgnn this->load1b = ((`hp_avenrun[0] % 65536) * 100) / 65536; 241235368Sgnn 242235368Sgnn /* convert counters to Kbytes */ 243235368Sgnn app_r /= 1024; 244235368Sgnn app_w /= 1024; 245235368Sgnn 246235368Sgnn /* print status */ 247235368Sgnn OPT_clear ? printf("%s", CLEAR) : 1; 248235368Sgnn printf("%Y, load: %d.%02d, app_r: %6d KB, app_w: %6d KB\n\n", 249235368Sgnn walltimestamp, this->load1a, this->load1b, app_r, app_w); 250235368Sgnn 251235368Sgnn /* print headers */ 252235368Sgnn OPT_def ? printf(" UID ") : 1; 253235368Sgnn OPT_proj ? printf(" PROJ ") : 1; 254235368Sgnn OPT_zone ? printf(" ZONE ") : 1; 255235368Sgnn printf("%6s %6s %-16s %1s", 256235368Sgnn "PID", "PPID", "CMD", "D"); 257235368Sgnn OPT_bytes ? printf(" %16s\n", "BYTES") : 1; 258235368Sgnn OPT_count ? printf(" %16s\n", "COUNT") : 1; 259235368Sgnn 260235368Sgnn /* truncate to top lines if needed */ 261235368Sgnn OPT_top ? trunc(@out, TOP) : 1; 262235368Sgnn 263235368Sgnn /* print data */ 264235368Sgnn printa("%5d %6d %6d %-16s %1s %16@d\n", @out); 265235368Sgnn printf("\n"); 266235368Sgnn 267235368Sgnn /* clear data */ 268235368Sgnn trunc(@out); 269235368Sgnn app_r = 0; 270235368Sgnn app_w = 0; 271235368Sgnn secs = INTERVAL; 272235368Sgnn counts--; 273235368Sgnn } 274235368Sgnn 275235368Sgnn /* 276235368Sgnn * End of program 277235368Sgnn */ 278235368Sgnn profile:::tick-1sec 279235368Sgnn /counts == 0/ 280235368Sgnn { 281235368Sgnn exit(0); 282235368Sgnn } 283235368Sgnn 284235368Sgnn /* 285235368Sgnn * Cleanup for Ctrl-C 286235368Sgnn */ 287235368Sgnn dtrace:::END 288235368Sgnn { 289235368Sgnn trunc(@out); 290235368Sgnn } 291235368Sgnn' 292235368Sgnn 293