1#!/usr/bin/sh
2#
3# dvmstat - vmstat by PID/name/command.
4#           Written using DTrace (Solaris 10 3/05).
5#
6# This program provides vmstat like data for one particular PID, a 
7# process name, or when running a command. It prints statistics
8# every second.
9#
10# $Id: dvmstat 3 2007-08-01 10:50:08Z brendan $
11#
12# USAGE:	dvmstat { -p PID | -n name | command }
13#  eg,
14#		dvmstat -p 1871       # examine PID 1871
15#		dvmstat -n tar        # examine processes called "tar"
16#		dvmstat df -h         # run and examine "df -h"
17#
18# FIELDS: 
19#		re	page reclaims		Kbytes
20#		maj	major faults		Kbytes
21#		mf	minor faults		Kbytes
22#		fr	page frees		Kbytes
23#		epi	executable page ins	Kbytes
24#		epo	executable page out	Kbytes
25#		api	anonymous page ins	Kbytes
26#		apo	anonymous page outs	Kbytes
27#		fpi	filesystem page ins	Kbytes
28#		fpo	filesystem page outs	Kbytes
29#		sy	system calls		number
30#
31# SEE ALSO:	vmstat(1M)
32#
33# NOTES:
34#
35# When using dvmstat to run a command - if the command takes some time
36# to execute, dvmstat will print output every second. If the command runs
37# in less than a second, then the only one line of output will be printed.
38#
39# COPYRIGHT: Copyright (c) 2005 Brendan Gregg.
40#
41# CDDL HEADER START
42#
43#  The contents of this file are subject to the terms of the
44#  Common Development and Distribution License, Version 1.0 only
45#  (the "License").  You may not use this file except in compliance
46#  with the License.
47#
48#  You can obtain a copy of the license at Docs/cddl1.txt
49#  or http://www.opensolaris.org/os/licensing.
50#  See the License for the specific language governing permissions
51#  and limitations under the License.
52#
53# CDDL HEADER END
54#
55# Author: Brendan Gregg  [Sydney, Australia]
56#
57# 12-Jun-2005	Brendan Gregg	Created this.
58# 08-Jan-2006	   "      "	Last update.
59# 
60
61##############################
62# --- Process Arguments ---
63#
64
65### Default variables
66opt_pid=0; opt_name=0; pid=0; pname="."; opt_command=0; command=""
67
68### Process options
69while getopts hn:p: name
70do
71        case $name in
72        p)      opt_pid=1; pid=$OPTARG ;;
73        n)      opt_name=1; pname=$OPTARG ;;
74        h|?)    cat <<-END >&2
75		USAGE: dvmstat [-h] { -p PID | -n name | command }
76		           -p PID          # examine this PID
77		           -n name         # examine this process name
78		  eg,
79		       dvmstat -p 1871     # examine PID 1871
80		       dvmstat -n tar      # examine processes called "tar"
81		       dvmstat df -h       # run and examine "df -h"
82		END
83                exit 1
84        esac
85done
86shift `expr $OPTIND - 1`
87
88
89### Option logic
90if [ $opt_pid -eq 0 -a $opt_name -eq 0 ]; then
91        opt_command=1
92        if [ "$*" = "" ]; then
93                $0 -h
94                exit
95        fi
96        command="$*"
97fi
98
99
100#################################
101# --- Main Program, DTrace ---
102#
103dtrace='
104 #pragma D option quiet
105
106 /*
107  * Command line arguments
108  */
109 inline int OPT_pid      = '$opt_pid';
110 inline int OPT_name     = '$opt_name';
111 inline int OPT_command  = '$opt_command';
112 inline int PID          = '$pid';
113 inline string NAME      = "'$pname'";
114 inline string COMMAND   = "'$command'";
115 inline int SCREEN       = 21;
116
117 /*
118  * Initialise variables
119  */
120 dtrace:::BEGIN
121 {
122	epi = 0; epo = 0; api = 0; apo = 0; fpi = 0; fpo = 0;
123	re = 0; mf = 0; maj = 0; fr = 0; sy = 0;
124	lines = SCREEN + 1;
125	header = 0;
126 }
127
128 /*
129  * Print header
130  */
131 dtrace:::BEGIN,
132 dtrace:::END,
133 profile:::tick-1sec
134 /(OPT_command && probename == "END") || 
135  (!(OPT_command && probename == "BEGIN") && lines++ > SCREEN)/
136 {
137	printf("%6s %5s %5s %4s %4s %4s %4s %4s %4s %4s %6s\n",
138	    "re", "maj", "mf", "fr", "epi", "epo", "api", "apo", 
139	    "fpi", "fpo", "sy");
140	lines = 0;
141 }
142
143 /*
144  * Probe events
145  *
146  * this intentionally does not use an associative array for storing data,
147  * for reasons of performance.
148  */
149
150 vminfo:::execpgin
151 /(OPT_pid && pid == PID) ||
152  (OPT_name && execname == NAME) ||
153  (OPT_command && pid == $target)/
154 { epi += arg0; }
155
156 vminfo:::execpgout
157 /(OPT_pid && pid == PID) ||
158  (OPT_name && execname == NAME) ||
159  (OPT_command && pid == $target)/
160 { epo += arg0; }
161
162 vminfo:::anonpgin
163 /(OPT_pid && pid == PID) ||
164  (OPT_name && execname == NAME) ||
165  (OPT_command && pid == $target)/
166 { api += arg0; }
167
168 vminfo:::anonpgout
169 /(OPT_pid && pid == PID) ||
170  (OPT_name && execname == NAME) ||
171  (OPT_command && pid == $target)/
172 { apo += arg0; }
173
174 vminfo:::fspgin
175 /(OPT_pid && pid == PID) ||
176  (OPT_name && execname == NAME) ||
177  (OPT_command && pid == $target)/
178 { fpi += arg0; }
179
180 vminfo:::fspgout
181 /(OPT_pid && pid == PID) ||
182  (OPT_name && execname == NAME) ||
183  (OPT_command && pid == $target)/
184 { fpo += arg0; }
185
186 vminfo:::pgrec
187 /(OPT_pid && pid == PID) ||
188  (OPT_name && execname == NAME) ||
189  (OPT_command && pid == $target)/
190 { re += arg0; }
191
192 vminfo:::as_fault
193 /(OPT_pid && pid == PID) ||
194  (OPT_name && execname == NAME) ||
195  (OPT_command && pid == $target)/
196 { mf += arg0; }
197
198 vminfo:::maj_fault
199 /(OPT_pid && pid == PID) ||
200  (OPT_name && execname == NAME) ||
201  (OPT_command && pid == $target)/
202 { maj += arg0; }
203
204 vminfo:::dfree
205 /(OPT_pid && pid == PID) ||
206  (OPT_name && execname == NAME) ||
207  (OPT_command && pid == $target)/
208 { fr += arg0; }
209
210 syscall:::entry
211 /(OPT_pid && pid == PID) ||
212  (OPT_name && execname == NAME) ||
213  (OPT_command && pid == $target)/
214 { sy++; }
215
216 /* 
217  * Print output line
218  */
219 profile:::tick-1sec,
220 dtrace:::END
221 {
222	/* convert to Kbytes */
223	re  *= `_pagesize / 1024;
224	maj *= `_pagesize / 1024;
225	mf  *= `_pagesize / 1024;
226	fr  *= `_pagesize / 1024;
227	epi *= `_pagesize / 1024;
228	epo *= `_pagesize / 1024;
229	api *= `_pagesize / 1024;
230	apo *= `_pagesize / 1024;
231	fpi *= `_pagesize / 1024;
232	fpo *= `_pagesize / 1024;
233
234	/* print line */
235	printf("%6d %5d %5d %4d %4d %4d %4d %4d %4d %4d %6d\n",
236	    re, maj, mf, fr, epi, epo, api, apo, fpi, fpo, sy);
237
238	/* clear counters */
239	epi = 0; epo = 0; api = 0; apo = 0; fpi = 0; fpo = 0;
240	re = 0; mf = 0; maj = 0; fr = 0; sy = 0;
241 }
242'
243
244### Run DTrace
245if [ $opt_command -eq 1 ]; then
246        /usr/sbin/dtrace -n "$dtrace" -x evaltime=exec -c "$command" >&2
247else
248        /usr/sbin/dtrace -n "$dtrace" >&2
249fi
250
251