zvmstat revision 235380
1#!/usr/bin/ksh 2# 3# zvmstat - print vmstat style info per Zone. 4# This uses DTrace (Solaris 10 3/05). 5# 6# This program must be run from the global zone as root. 7# 8# $Id: zvmstat 3 2007-08-01 10:50:08Z brendan $ 9# 10# USAGE: zvmstat [-ht] [interval [count]] 11# 12# zvmstat # default output 13# -t # print times 14# eg, 15# zvmstat 1 # print every 1 second 16# zvmstat 10 5 # print 5 x 10 second samples 17# zvmstat -t 5 # print every 5 seconds with time 18# 19# 20# FIELDS: 21# re page reclaims 22# mf minor faults 23# fr pages freed 24# sr scan rate 25# epi executable pages paged in 26# epo executable pages paged out 27# epf executable pages freed 28# api anonymous pages paged in 29# apo anonymous pages paged out 30# apf anonymous pages freed 31# fpi filesystem pages paged in 32# fpo filesystem pages paged out 33# fpf filesystem pages freed 34# 35# NOTES: 36# - Zone status should really be provided by Kstat, which currently 37# provides system wide values, per CPU and per processor set, but not per 38# zone. DTrace can fill this role in the meantime until Kstat supports zones. 39# - First output does not contain summary since boot. 40# 41# SEE ALSO: prstat -Z 42# 43# COPYRIGHT: Copyright (c) 2005 Brendan Gregg. 44# 45# CDDL HEADER START 46# 47# The contents of this file are subject to the terms of the 48# Common Development and Distribution License, Version 1.0 only 49# (the "License"). You may not use this file except in compliance 50# with the License. 51# 52# You can obtain a copy of the license at Docs/cddl1.txt 53# or http://www.opensolaris.org/os/licensing. 54# See the License for the specific language governing permissions 55# and limitations under the License. 56# 57# CDDL HEADER END 58# 59# BUGS: 60# - First output may not contain all zones due to how loops are achieved. 61# Check for newer versions. 62# 63# Author: Brendan Gregg [Sydney, Australia] 64# 65# 11-May-2005 Brendan Gregg Created this. 66# 26-Jul-2005 " " Improved code. 67# 08-Jan-2006 " " Last update. 68# 69 70 71############################## 72# --- Process Arguments --- 73# 74 75### default variables 76opt_time=0; interval=1; counts=1 77 78### process options 79while getopts ht name 80do 81 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