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# 08-Jan-2006, ver 0.72        (check for newer versions)
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#
20#       re     page reclaims         Kbytes
21#       maj    major faults          Kbytes
22#       mf     minor faults          Kbytes
23#       fr     page frees            Kbytes
24#       epi    executable page ins   Kbytes
25#       epo    executable page outs  Kbytes
26#       api    anonymous page ins    Kbytes
27#       apo    anonymous page outs   Kbytes
28#       fpi    filesystem page ins   Kbytes
29#       fpo    filesystem page outs  Kbytes
30#       sy     system calls          number
31#
32# SEE ALSO:	vmstat(1M)
33#
34# NOTES:
35#
36# When using dvmstat to run a command - if the command takes some time
37# to execute, dvmstat will print output every second. If the command runs
38# in less than a second, then the only one line of output will be printed.
39#
40# COPYRIGHT: Copyright (c) 2005 Brendan Gregg.
41#
42# CDDL HEADER START
43#
44#  The contents of this file are subject to the terms of the
45#  Common Development and Distribution License, Version 1.0 only
46#  (the "License").  You may not use this file except in compliance
47#  with the License.
48#
49#  You can obtain a copy of the license at Docs/cddl1.txt
50#  or http://www.opensolaris.org/os/licensing.
51#  See the License for the specific language governing permissions
52#  and limitations under the License.
53#
54# CDDL HEADER END
55#
56# Author: Brendan Gregg  [Sydney, Australia]
57#
58# 12-Jun-2005  Brendan Gregg   Created this.
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 && NAME == strstr(NAME, execname)) ||
153  (OPT_name && execname == strstr(execname, NAME)) ||
154  (OPT_command && pid == $target)/
155 { epi += arg0; }
156
157 vminfo:::execpgout
158 /(OPT_pid && pid == PID) ||
159  (OPT_name && NAME == strstr(NAME, execname)) ||
160  (OPT_name && execname == strstr(execname, NAME)) ||
161  (OPT_command && pid == $target)/
162 { epo += arg0; }
163
164 vminfo:::anonpgin
165 /(OPT_pid && pid == PID) ||
166  (OPT_name && NAME == strstr(NAME, execname)) ||
167  (OPT_name && execname == strstr(execname, NAME)) ||
168  (OPT_command && pid == $target)/
169 { api += arg0; }
170
171 vminfo:::anonpgout
172 /(OPT_pid && pid == PID) ||
173  (OPT_name && NAME == strstr(NAME, execname)) ||
174  (OPT_name && execname == strstr(execname, NAME)) ||
175  (OPT_command && pid == $target)/
176 { apo += arg0; }
177
178 vminfo:::fspgin
179 /(OPT_pid && pid == PID) ||
180  (OPT_name && NAME == strstr(NAME, execname)) ||
181  (OPT_name && execname == strstr(execname, NAME)) ||
182  (OPT_command && pid == $target)/
183 { fpi += arg0; }
184
185 vminfo:::fspgout
186 /(OPT_pid && pid == PID) ||
187  (OPT_name && NAME == strstr(NAME, execname)) ||
188  (OPT_name && execname == strstr(execname, NAME)) ||
189  (OPT_command && pid == $target)/
190 { fpo += arg0; }
191
192 vminfo:::pgrec
193 /(OPT_pid && pid == PID) ||
194  (OPT_name && NAME == strstr(NAME, execname)) ||
195  (OPT_name && execname == strstr(execname, NAME)) ||
196  (OPT_command && pid == $target)/
197 { re += arg0; }
198
199 vminfo:::as_fault
200 /(OPT_pid && pid == PID) ||
201  (OPT_name && NAME == strstr(NAME, execname)) ||
202  (OPT_name && execname == strstr(execname, NAME)) ||
203  (OPT_command && pid == $target)/
204 { mf += arg0; }
205
206 vminfo:::maj_fault
207 /(OPT_pid && pid == PID) ||
208  (OPT_name && NAME == strstr(NAME, execname)) ||
209  (OPT_name && execname == strstr(execname, NAME)) ||
210  (OPT_command && pid == $target)/
211 { maj += arg0; }
212
213 vminfo:::dfree
214 /(OPT_pid && pid == PID) ||
215  (OPT_name && NAME == strstr(NAME, execname)) ||
216  (OPT_name && execname == strstr(execname, NAME)) ||
217  (OPT_command && pid == $target)/
218 { fr += arg0; }
219
220 syscall:::entry
221 /(OPT_pid && pid == PID) ||
222  (OPT_name && NAME == strstr(NAME, execname)) ||
223  (OPT_name && execname == strstr(execname, NAME)) ||
224  (OPT_command && pid == $target)/
225 { sy++; }
226
227 /* 
228  * Print output line
229  */
230 profile:::tick-1sec,
231 dtrace:::END
232 {
233	/* convert to Kbytes */
234	re  *= `_pagesize / 1024;
235	maj *= `_pagesize / 1024;
236	mf  *= `_pagesize / 1024;
237	fr  *= `_pagesize / 1024;
238	epi *= `_pagesize / 1024;
239	epo *= `_pagesize / 1024;
240	api *= `_pagesize / 1024;
241	apo *= `_pagesize / 1024;
242	fpi *= `_pagesize / 1024;
243	fpo *= `_pagesize / 1024;
244
245	/* print line */
246	printf("%6d %5d %5d %4d %4d %4d %4d %4d %4d %4d %6d\n",
247	    re, maj, mf, fr, epi, epo, api, apo, fpi, fpo, sy);
248
249	/* clear counters */
250	epi = 0; epo = 0; api = 0; apo = 0; fpi = 0; fpo = 0;
251	re = 0; mf = 0; maj = 0; fr = 0; sy = 0;
252 }
253'
254
255### Run DTrace
256if [ $opt_command -eq 1 ]; then
257        /usr/sbin/dtrace -n "$dtrace" -x evaltime=exec -c "$command" >&2
258else
259        /usr/sbin/dtrace -n "$dtrace" >&2
260fi
261
262