Home | History | Annotate | Line # | Download | only in Bin
      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