zvmstat revision 235368
174667Sjedgar#!/usr/bin/ksh
274667Sjedgar#
374667Sjedgar# zvmstat - print vmstat style info per Zone.
474667Sjedgar#           This uses DTrace (Solaris 10 3/05).
574667Sjedgar#
674667Sjedgar# This program must be run from the global zone as root.
774667Sjedgar#
874667Sjedgar# $Id: zvmstat 3 2007-08-01 10:50:08Z brendan $
974667Sjedgar#
1074667Sjedgar# USAGE: 	zvmstat [-ht] [interval [count]]
1174667Sjedgar#
1274667Sjedgar#		zvmstat         # default output
1374667Sjedgar#			-t      # print times
1474667Sjedgar#  eg,
1574667Sjedgar#		zvmstat 1       # print every 1 second
1674667Sjedgar#		zvmstat 10 5    # print 5 x 10 second samples
17184607Simp#		zvmstat -t 5    # print every 5 seconds with time
18184607Simp#
19184607Simp#
20184607Simp# FIELDS:
21184607Simp#		re		page reclaims
22184607Simp#		mf		minor faults
23184607Simp#		fr		pages freed
24184607Simp#		sr		scan rate
2574667Sjedgar#		epi		executable pages paged in
2674667Sjedgar#		epo		executable pages paged out
2774667Sjedgar#		epf		executable pages freed
2874667Sjedgar#		api		anonymous pages paged in
2974686Sjedgar#		apo		anonymous pages paged out
3074667Sjedgar#		apf		anonymous pages freed
3174667Sjedgar#		fpi		filesystem pages paged in
3274686Sjedgar#		fpo		filesystem pages paged out
3374686Sjedgar#		fpf		filesystem pages freed
3474667Sjedgar#
3575222Sru# NOTES: 
3674667Sjedgar# - Zone status should really be provided by Kstat, which currently
3784306Sru#   provides system wide values, per CPU and per processor set, but not per
3884306Sru#   zone. DTrace can fill this role in the meantime until Kstat supports zones.
3974667Sjedgar# - First output does not contain summary since boot.
4074686Sjedgar#
4174667Sjedgar# SEE ALSO: prstat -Z
42108037Sru#
4374686Sjedgar# COPYRIGHT: Copyright (c) 2005 Brendan Gregg.
44108037Sru#
4574686Sjedgar# CDDL HEADER START
4674686Sjedgar#
4774686Sjedgar#  The contents of this file are subject to the terms of the
4874686Sjedgar#  Common Development and Distribution License, Version 1.0 only
4974667Sjedgar#  (the "License").  You may not use this file except in compliance
5074693Sru#  with the License.
5174667Sjedgar#
5274693Sru#  You can obtain a copy of the license at Docs/cddl1.txt
5374686Sjedgar#  or http://www.opensolaris.org/os/licensing.
5474693Sru#  See the License for the specific language governing permissions
5574667Sjedgar#  and limitations under the License.
5674667Sjedgar#
5774667Sjedgar# CDDL HEADER END
5874686Sjedgar#
5974667Sjedgar# BUGS:
6074667Sjedgar# - First output may not contain all zones due to how loops are achieved.
6174667Sjedgar#   Check for newer versions.
6274667Sjedgar#
6374667Sjedgar# Author: Brendan Gregg  [Sydney, Australia]
6474667Sjedgar#
6574667Sjedgar# 11-May-2005   Brendan Gregg   Created this.
6674686Sjedgar# 26-Jul-2005	   "      "	Improved code.
6774667Sjedgar# 08-Jan-2006	   "      "	Last update.
6874667Sjedgar#
6974667Sjedgar
7074667Sjedgar
7174667Sjedgar##############################
7274667Sjedgar# --- Process Arguments ---
7374667Sjedgar#
7474686Sjedgar
7574667Sjedgar### default variables
7674667Sjedgaropt_time=0; interval=1; counts=1
7774667Sjedgar
7874667Sjedgar### process options
7974686Sjedgarwhile getopts ht name
8074667Sjedgardo
8174667Sjedgar	case $name in
82	t)      opt_time=1 ;;
83	h|?)    cat <<-END >&2
84		USAGE: zvmstat [-ht] [interval [count]]
85		       zvmstat         # default output
86		               -t      # print times
87		   eg,
88		       zvmstat 1       # print every 1 second
89		       zvmstat 10 5    # print 5 x 10 second samples
90		       zvmstat -t 5    # print every 5 seconds with time
91		END
92		exit 1
93	esac
94done
95shift $(( OPTIND - 1 ))
96
97### option logic
98if (( "0$1" > 0 )); then
99        interval=$1; counts=-1; shift
100fi
101if (( "0$1" > 0 )); then
102        counts=$1; shift
103fi
104
105
106#################################
107# --- Main Program, DTrace ---
108#
109dtrace -n '
110 #pragma D option quiet
111 #pragma D option destructive
112 #pragma D option switchrate=10
113
114 /*
115  * Command line arguments
116  */
117 inline int OPT_time   = '$opt_time';
118 inline int INTERVAL   = '$interval';
119 inline int COUNTER    = '$counts';
120
121 /* 
122  * Initialise variables
123  */
124 dtrace:::BEGIN 
125 {
126	secs = INTERVAL; 
127	counts = COUNTER;
128	zonemax = 0;
129	listing = 1;
130	re[""] = 0; pi[""] = 0; po[""] = 0;
131	mf[""] = 0; sr[""] = 0; fr[""] = 0;
132	epi[""] = 0; epo[""] = 0; epf[""] = 0;
133	api[""] = 0; apo[""] = 0; apf[""] = 0;
134	fpi[""] = 0; fpo[""] = 0; fpf[""] = 0;
135 }
136
137 /*
138  * Build zonelist array
139  *
140  * Here we want the output of a command to be saved into an array
141  * inside dtrace. This is done by running the command, sending the
142  * output to /dev/null, and by probing its write syscalls from dtrace. 
143  *
144  * This is an example of a "scraper".
145  */
146
147 /*
148  * List zones
149  */
150 dtrace:::BEGIN 
151 {
152	/* run zoneadm */
153	system("/usr/sbin/zoneadm list > /dev/null; echo END > /dev/null");
154 }
155
156 /*
157  * Scrape zone listing
158  */
159 syscall::write:entry
160 /listing && (execname == "zoneadm") && 
161 (curthread->t_procp->p_parent->p_ppid == $pid)/
162 {
163	/* read zoneadm output */
164	zonelist[zonemax] = stringof(copyin(arg1, arg2 - 1));
165
166	/* increment max number of zones */
167	zonemax++;
168 }
169
170 /*
171  * Finish scraping zones
172  */
173 syscall::write:entry
174 /listing && (execname == "sh") && (ppid == $pid)/
175 {
176	/*
177	 * this end tag lets us know our zonelist has finished.
178	 * thanks A. Packer.
179	 */
180	listing = stringof(copyin(arg1, arg2 - 1)) == "END" ? 0 : 1;
181 }
182
183 /*
184  * Record vminfo counters
185  */
186 vminfo:::pgrec      { re[zonename] += arg0; }
187 vminfo:::as_fault   { mf[zonename] += arg0; }
188 vminfo:::scan       { sr[zonename] += arg0; }
189 vminfo:::execpgin   { epi[zonename] += arg0; }
190 vminfo:::execpgout  { epo[zonename] += arg0; }
191 vminfo:::execfree   { epf[zonename] += arg0; fr[zonename] += arg0; }
192 vminfo:::anonpgin   { api[zonename] += arg0; }
193 vminfo:::anonpgout  { apo[zonename] += arg0; }
194 vminfo:::anonfree   { apf[zonename] += arg0; fr[zonename] += arg0; }
195 vminfo:::fspgin     { fpi[zonename] += arg0; }
196 vminfo:::fspgout    { fpo[zonename] += arg0; }
197 vminfo:::fsfree     { fpf[zonename] += arg0; fr[zonename] += arg0; }
198
199 /*
200  * Timer
201  */
202 profile:::tick-1sec
203 {
204	secs--;
205 }
206
207 /*
208  * Check for exit
209  */
210 profile:::tick-1sec
211 /counts == 0/
212 {
213	exit(0);
214 }
215
216 /*
217  * Print header line
218  */
219 profile:::tick-1sec
220 /secs == 0/
221 {
222	/* set counters */
223	secs = INTERVAL;
224	counts--;
225	zonei = 0;
226
227	/* print time */
228	OPT_time ? printf("\n%Y,\n",walltimestamp) : 1;
229
230	/* print output line */
231	printf("%10s %4s %5s %4s %5s %4s %4s %4s %4s %4s %4s %4s %4s %4s\n",
232	    "ZONE", "re", "mf", "fr", "sr", "epi", "epo", "epf", "api", "apo",
233	    "apf", "fpi", "fpo", "fpf");
234
235	/* ensure zone writes are triggered */
236	printf(" \b");
237 }
238
239 /*
240  * Print zone status line
241  *
242  * This is a fairly interesting function in that it loops over the keys in 
243  * an associative array and prints out the values. DTrace cant really do 
244  * loops, and generally doesnt need to. We "cheat" by generating writes
245  * in the above probe which in turn trigger the probe below which 
246  * contains the contents of each loop. Dont do this at home! We are
247  * supposed to use aggreagations instead, wherever possible.
248  *
249  * This is an example of a "feedback loop".
250  */
251 syscall::write:return
252 /pid == $pid && zonei < zonemax/
253 {
254	/* fetch zonename */
255	self->zone = zonelist[zonei];
256
257	/* print output */
258	printf("%10s %4d %5d %4d %5d %4d %4d %4d %4d %4d %4d %4d %4d %4d\n",
259	    self->zone, re[self->zone], mf[self->zone], fr[self->zone],
260	    sr[self->zone], epi[self->zone], epo[self->zone],
261	    epf[self->zone], api[self->zone], apo[self->zone],
262	    apf[self->zone], fpi[self->zone], fpo[self->zone],
263	    fpf[self->zone]);
264	
265	/* clear values */
266	re[self->zone] = 0; mf[self->zone] = 0; fr[self->zone] = 0;
267	sr[self->zone] = 0; epi[self->zone] = 0; epo[self->zone] = 0;
268	epf[self->zone] = 0; api[self->zone] = 0; apo[self->zone] = 0;
269	apf[self->zone] = 0; fpi[self->zone] = 0; fpo[self->zone] = 0;
270	fpf[self->zone] = 0;
271	self->zone = 0;
272	
273	/* go to next zone */
274	zonei++;
275 }
276'
277
278