1N/A#!/usr/bin/ksh
1N/A#
1N/A# zvmstat - print vmstat style info per Zone.
1N/A# This uses DTrace (Solaris 10 3/05).
1N/A#
1N/A# This program must be run from the global zone as root.
1N/A#
1N/A# $Id: zvmstat 3 2007-08-01 10:50:08Z brendan $
1N/A#
1N/A# USAGE: zvmstat [-ht] [interval [count]]
1N/A#
1N/A# zvmstat # default output
1N/A# -t # print times
1N/A# eg,
1N/A# zvmstat 1 # print every 1 second
1N/A# zvmstat 10 5 # print 5 x 10 second samples
1N/A# zvmstat -t 5 # print every 5 seconds with time
1N/A#
1N/A#
1N/A# FIELDS:
1N/A# re page reclaims
1N/A# mf minor faults
1N/A# fr pages freed
1N/A# sr scan rate
1N/A# epi executable pages paged in
1N/A# epo executable pages paged out
1N/A# epf executable pages freed
1N/A# api anonymous pages paged in
1N/A# apo anonymous pages paged out
1N/A# apf anonymous pages freed
1N/A# fpi filesystem pages paged in
1N/A# fpo filesystem pages paged out
1N/A# fpf filesystem pages freed
1N/A#
1N/A# NOTES:
1N/A# - Zone status should really be provided by Kstat, which currently
1N/A# provides system wide values, per CPU and per processor set, but not per
1N/A# zone. DTrace can fill this role in the meantime until Kstat supports zones.
1N/A# - First output does not contain summary since boot.
1N/A#
1N/A# SEE ALSO: prstat -Z
1N/A#
1N/A# COPYRIGHT: Copyright (c) 2005 Brendan Gregg.
1N/A#
1N/A# CDDL HEADER START
1N/A#
1N/A# The contents of this file are subject to the terms of the
1N/A# Common Development and Distribution License, Version 1.0 only
1N/A# (the "License"). You may not use this file except in compliance
1N/A# with the License.
1N/A#
1N/A# You can obtain a copy of the license at Docs/cddl1.txt
1N/A# or http://www.opensolaris.org/os/licensing.
1N/A# See the License for the specific language governing permissions
1N/A# and limitations under the License.
1N/A#
1N/A# CDDL HEADER END
1N/A#
1N/A# BUGS:
1N/A# - First output may not contain all zones due to how loops are achieved.
1N/A# Check for newer versions.
1N/A#
1N/A# Author: Brendan Gregg [Sydney, Australia]
1N/A#
1N/A# 11-May-2005 Brendan Gregg Created this.
1N/A# 26-Jul-2005 " " Improved code.
1N/A# 08-Jan-2006 " " Last update.
1N/A#
1N/A
1N/A
1N/A##############################
1N/A# --- Process Arguments ---
1N/A#
1N/A
1N/A### default variables
1N/Aopt_time=0; interval=1; counts=1
1N/A
1N/A### process options
1N/Awhile getopts ht name
1N/Ado
1N/A case $name in
1N/A t) opt_time=1 ;;
1N/A h|?) cat <<-END >&2
1N/A USAGE: zvmstat [-ht] [interval [count]]
1N/A zvmstat # default output
1N/A -t # print times
1N/A eg,
1N/A zvmstat 1 # print every 1 second
1N/A zvmstat 10 5 # print 5 x 10 second samples
1N/A zvmstat -t 5 # print every 5 seconds with time
1N/A END
1N/A exit 1
1N/A esac
1N/Adone
1N/Ashift $(( OPTIND - 1 ))
1N/A
1N/A### option logic
1N/Aif (( "0$1" > 0 )); then
1N/A interval=$1; counts=-1; shift
1N/Afi
1N/Aif (( "0$1" > 0 )); then
1N/A counts=$1; shift
1N/Afi
1N/A
1N/A
1N/A#################################
1N/A# --- Main Program, DTrace ---
1N/A#
1N/Adtrace -n '
1N/A #pragma D option quiet
1N/A #pragma D option destructive
1N/A #pragma D option switchrate=10
1N/A
1N/A /*
1N/A * Command line arguments
1N/A */
1N/A inline int OPT_time = '$opt_time';
1N/A inline int INTERVAL = '$interval';
1N/A inline int COUNTER = '$counts';
1N/A
1N/A /*
1N/A * Initialise variables
1N/A */
1N/A dtrace:::BEGIN
1N/A {
1N/A secs = INTERVAL;
1N/A counts = COUNTER;
1N/A zonemax = 0;
1N/A listing = 1;
1N/A re[""] = 0; pi[""] = 0; po[""] = 0;
1N/A mf[""] = 0; sr[""] = 0; fr[""] = 0;
1N/A epi[""] = 0; epo[""] = 0; epf[""] = 0;
1N/A api[""] = 0; apo[""] = 0; apf[""] = 0;
1N/A fpi[""] = 0; fpo[""] = 0; fpf[""] = 0;
1N/A }
1N/A
1N/A /*
1N/A * Build zonelist array
1N/A *
1N/A * Here we want the output of a command to be saved into an array
1N/A * inside dtrace. This is done by running the command, sending the
1N/A * output to /dev/null, and by probing its write syscalls from dtrace.
1N/A *
1N/A * This is an example of a "scraper".
1N/A */
1N/A
1N/A /*
1N/A * List zones
1N/A */
1N/A dtrace:::BEGIN
1N/A {
1N/A /* run zoneadm */
1N/A system("/usr/sbin/zoneadm list > /dev/null; echo END > /dev/null");
1N/A }
1N/A
1N/A /*
1N/A * Scrape zone listing
1N/A */
1N/A syscall::write:entry
1N/A /listing && (execname == "zoneadm") &&
1N/A (curthread->t_procp->p_parent->p_ppid == $pid)/
1N/A {
1N/A /* read zoneadm output */
1N/A zonelist[zonemax] = stringof(copyin(arg1, arg2 - 1));
1N/A
1N/A /* increment max number of zones */
1N/A zonemax++;
1N/A }
1N/A
1N/A /*
1N/A * Finish scraping zones
1N/A */
1N/A syscall::write:entry
1N/A /listing && (execname == "sh") && (ppid == $pid)/
1N/A {
1N/A /*
1N/A * this end tag lets us know our zonelist has finished.
1N/A * thanks A. Packer.
1N/A */
1N/A listing = stringof(copyin(arg1, arg2 - 1)) == "END" ? 0 : 1;
1N/A }
1N/A
1N/A /*
1N/A * Record vminfo counters
1N/A */
1N/A vminfo:::pgrec { re[zonename] += arg0; }
1N/A vminfo:::as_fault { mf[zonename] += arg0; }
1N/A vminfo:::scan { sr[zonename] += arg0; }
1N/A vminfo:::execpgin { epi[zonename] += arg0; }
1N/A vminfo:::execpgout { epo[zonename] += arg0; }
1N/A vminfo:::execfree { epf[zonename] += arg0; fr[zonename] += arg0; }
1N/A vminfo:::anonpgin { api[zonename] += arg0; }
1N/A vminfo:::anonpgout { apo[zonename] += arg0; }
1N/A vminfo:::anonfree { apf[zonename] += arg0; fr[zonename] += arg0; }
1N/A vminfo:::fspgin { fpi[zonename] += arg0; }
1N/A vminfo:::fspgout { fpo[zonename] += arg0; }
1N/A vminfo:::fsfree { fpf[zonename] += arg0; fr[zonename] += arg0; }
1N/A
1N/A /*
1N/A * Timer
1N/A */
1N/A profile:::tick-1sec
1N/A {
1N/A secs--;
1N/A }
1N/A
1N/A /*
1N/A * Check for exit
1N/A */
1N/A profile:::tick-1sec
1N/A /counts == 0/
1N/A {
1N/A exit(0);
1N/A }
1N/A
1N/A /*
1N/A * Print header line
1N/A */
1N/A profile:::tick-1sec
1N/A /secs == 0/
1N/A {
1N/A /* set counters */
1N/A secs = INTERVAL;
1N/A counts--;
1N/A zonei = 0;
1N/A
1N/A /* print time */
1N/A OPT_time ? printf("\n%Y,\n",walltimestamp) : 1;
1N/A
1N/A /* print output line */
1N/A printf("%10s %4s %5s %4s %5s %4s %4s %4s %4s %4s %4s %4s %4s %4s\n",
1N/A "ZONE", "re", "mf", "fr", "sr", "epi", "epo", "epf", "api", "apo",
1N/A "apf", "fpi", "fpo", "fpf");
1N/A
1N/A /* ensure zone writes are triggered */
1N/A printf(" \b");
1N/A }
1N/A
1N/A /*
1N/A * Print zone status line
1N/A *
1N/A * This is a fairly interesting function in that it loops over the keys in
1N/A * an associative array and prints out the values. DTrace cant really do
1N/A * loops, and generally doesnt need to. We "cheat" by generating writes
1N/A * in the above probe which in turn trigger the probe below which
1N/A * contains the contents of each loop. Dont do this at home! We are
1N/A * supposed to use aggreagations instead, wherever possible.
1N/A *
1N/A * This is an example of a "feedback loop".
1N/A */
1N/A syscall::write:return
1N/A /pid == $pid && zonei < zonemax/
1N/A {
1N/A /* fetch zonename */
1N/A self->zone = zonelist[zonei];
1N/A
1N/A /* print output */
1N/A printf("%10s %4d %5d %4d %5d %4d %4d %4d %4d %4d %4d %4d %4d %4d\n",
1N/A self->zone, re[self->zone], mf[self->zone], fr[self->zone],
1N/A sr[self->zone], epi[self->zone], epo[self->zone],
1N/A epf[self->zone], api[self->zone], apo[self->zone],
1N/A apf[self->zone], fpi[self->zone], fpo[self->zone],
1N/A fpf[self->zone]);
1N/A
1N/A /* clear values */
1N/A re[self->zone] = 0; mf[self->zone] = 0; fr[self->zone] = 0;
1N/A sr[self->zone] = 0; epi[self->zone] = 0; epo[self->zone] = 0;
1N/A epf[self->zone] = 0; api[self->zone] = 0; apo[self->zone] = 0;
1N/A apf[self->zone] = 0; fpi[self->zone] = 0; fpo[self->zone] = 0;
1N/A fpf[self->zone] = 0;
1N/A self->zone = 0;
1N/A
1N/A /* go to next zone */
1N/A zonei++;
1N/A }
1N/A'
1N/A