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