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,v 1.1.1.1 2015/09/30 22:01:06 christos Exp $ 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 76 opt_time=0; interval=1; counts=1 77 78 ### process options 79 while getopts ht name 80 do 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 94 done 95 shift $(( OPTIND - 1 )) 96 97 ### option logic 98 if (( "0$1" > 0 )); then 99 interval=$1; counts=-1; shift 100 fi 101 if (( "0$1" > 0 )); then 102 counts=$1; shift 103 fi 104 105 106 ################################# 107 # --- Main Program, DTrace --- 108 # 109 dtrace -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