Appendix D. Sample Perl Kstat Utilities

A Simple Kstat Walker

#!/usr/bin/perl -w
#
# kgrep - walk the Kstat tree, grepping names.
#
# This is a simple demo of walking the Kstat tree in Perl. The output
# is similar to a "kstat -p", however an argument can be provided to
# grep the full statistic name (joined by ":").
#
# USAGE:    kgrep [pattern]
#    eg,    kgrep hme0

use strict;
use Sun::Solaris::Kstat;
my $Kstat = Sun::Solaris::Kstat->new();
my $pattern = defined $ARGV[0] ? $ARGV[0] : ".";
die "USAGE: kgrep [pattern]
" if $pattern eq "-h";

# loop over all kstats
foreach my $module (keys(%$Kstat)) {
    my $Modules = $Kstat->{$module};
    foreach my $instance (keys(%$Modules)) {
        my $Instances = $Modules->{$instance};
        foreach my $name (keys(%$Instances)) {
            my $Names = $Instances->{$name};
            foreach my $stat (keys(%$Names)) {
                my $value = $$Names{$stat};
                # print kstat name and value
                printf "%-50s %s
", "$module:$instance:$name:$stat", $value
                    if "$module:$instance:$name:$stat" =~ /$pattern/;
            }
        }
    }
}

A Perl Version of Uptime

#!/usr/bin/perl -w
#
# uptime - Perl Kstat version of uptime. Solaris 8+.
#
# This program fetches similar statistics to the /usr/bin/uptime command,
# as a demonstation of the Perl Kstat module.
#
# USAGE:    uptime
#

use strict;
use Sun::Solaris::Kstat;

### Create Kstat object
my $Kstat = Sun::Solaris::Kstat->new();

### Fetch load averages
my $load1  = $Kstat->{unix}->{0}->{system_misc}->{avenrun_1min};
my $load5  = $Kstat->{unix}->{0}->{system_misc}->{avenrun_5min};
my $load15 = $Kstat->{unix}->{0}->{system_misc}->{avenrun_15min};

### Fetch boot time
my $boot = $Kstat->{unix}->{0}->{system_misc}->{boot_time};

### Processing
$load1  /= 256;
$load5  /= 256;
$load15 /= 256;
my $days = (time() - $boot) / (60 * 60 * 24);

### Print output
print scalar localtime();
printf ",  up %.2f days", $days ;
printf ",  load averages: %.2f, %.2f, %.2f
", $load1, $load5, $load15;

A Network Statistics Utility

#!/usr/bin/perl -w
#
# nicstat - print network traffic, Kb/s read and written.
#           Solaris 8+, Perl (Sun::Solaris::Kstat).
#
# "netstat -i" only gives a packet count, this program gives Kbytes.
#
# 23-Jan-2006, ver 0.98
#
# USAGE:    nicstat [-hsz] [-i int[,int...]] | [interval [count]]
#           -h              # help
#           -s              # print summary output
#           -z              # skip zero lines
#           -i int[,int...] # print these instances only
#   eg,
#           nicstat         # print summary since boot
#           nicstat 1       # print continually, every 1 second
#           nicstat 1 5     # print 5 times, every 1 second
#           nicstat -i hme0 # only examine hme0
#
# This prints out the Kb/s transferred for all the network cards (NICs),
# including packet counts and average sizes. The first line is the summary
# data since boot.
#
# FIELDS:
#           Int         Interface
#           rKb/s       read Kbytes/s
#           wKb/s       write Kbytes/s
#           rPk/s       read Packets/s
#           wPk/s       write Packets/s
#           rAvs        read Average size, bytes
#           wAvs        write Average size, bytes
#           %Util       %Utilisation (r+w/ifspeed)
#           Sat         Saturation (defer, nocanput, norecvbuf, noxmtbuf)
#
# Author: Brendan Gregg  [Sydney, Australia]
#

use strict;
use Getopt::Std;
use Sun::Solaris::Kstat;
my $Kstat = Sun::Solaris::Kstat->new();


#
#  Process command line args
#
usage() if defined $ARGV[0] and $ARGV[0] eq "--help";
getopts('hi:sz') or usage();
usage() if defined $main::opt_h;
my $STYLE  = defined $main::opt_s ? $main::opt_s : 0;
my $SKIPZERO  = defined $main::opt_z ? $main::opt_z : 0;

# process [interval [count]],
my ($interval, $loop_max);
if (defined $ARGV[0]) {
    $interval = $ARGV[0];
    $loop_max = defined $ARGV[1] ? $ARGV[1] : 2**32;
    usage() if $interval == 0;
}
else {
    $interval = 1;
    $loop_max = 1;
}

# check for -i,
my %NetworkOnly;             # network interfaces to print
my $NETWORKONLY = 0;         # match on network interfaces
if (defined $main::opt_i) {
    foreach my $net (split /,/, $main::opt_i) {
        $NetworkOnly{$net} = 1;
    }
    $NETWORKONLY = 1;
}

# globals,
my $loop = 0;                # current loop number
my $PAGESIZE = 20;           # max lines per header
my $line = $PAGESIZE;        # counter for lines printed
my %NetworkNames;            # Kstat network interfaces
my %NetworkData;             # network interface data
my %NetworkDataOld;          # network interface data
$main::opt_h = 0;
$| = 1;                      # autoflush
### Determine network interfaces
unless (find_nets()) {
    if ($NETWORKONLY) {
        print STDERR "ERROR1: $main::opt_i matched no network interfaces.
";
    }
    else {
        print STDERR "ERROR1: No network interfaces found!
";
    }
    exit 1;
}

#
#  Main
#
while (1) {

    ### Print Header
    if ($line >= $PAGESIZE) {
        if ($STYLE == 0) {
            printf "%8s %5s %7s %7s %7s %7s %7s %7s %7s %7s
",
                   "Time", "Int", "rKb/s", "wKb/s", "rPk/s", "wPk/s", "rAvs",
                   "wAvs", "%Util", "Sat";
        }
        elsif ($STYLE == 1) {
            printf "%8s %8s %14s %14s
", "Time", "Int", "rKb/s", "wKb/s";
        }

        $line = 0;
    }

    ### Get new data
    my (@NetworkData) = fetch_net_data();

    foreach my $network_data (@NetworkData) {

        ### Extract values
        my ($int, $rbytes, $wbytes, $rpackets, $wpackets, $speed, $sat, $time)
            = split /:/, $network_data;

        ### Retrieve old values
        my ($old_rbytes, $old_wbytes, $old_rpackets, $old_wpackets, $old_sat,
            $old_time);
        if (defined $NetworkDataOld{$int}) {
            ($old_rbytes, $old_wbytes, $old_rpackets, $old_wpackets,
             $old_sat, $old_time) = split /:/, $NetworkDataOld{$int};
        }
        else {
            $old_rbytes = $old_wbytes = $old_rpackets = $old_wpackets
                = $old_sat = $old_time = 0;
        }

        #
        #  Calculate statistics
        #

        # delta time
        my $tdiff = $time - $old_time;

        # per second values
        my $rbps = ($rbytes - $old_rbytes) / $tdiff;
        my $wbps = ($wbytes - $old_wbytes) / $tdiff;
        my $rkps = $rbps / 1024;
        my $wkps = $wbps / 1024;
        my $rpps = ($rpackets - $old_rpackets) / $tdiff;
        my $wpps = ($wpackets - $old_wpackets) / $tdiff;
        my $ravs = $rpps > 0 ? $rbps / $rpps : 0;
        my $wavs = $wpps > 0 ? $wbps / $wpps : 0;
        # skip zero lines if asked
        next if $SKIPZERO and ($rbps + $wbps) == 0;

        # % utilisation
        my $util;
        if ($speed > 0) {
            # the following has a mysterious "800", it is 100
            # for the % conversion, and 8 for bytes2bits.
            $util = ($rbps + $wbps) * 800 / $speed;
            $util = 100 if $util > 100;
        }
        else {
            $util = 0;
        }

        # saturation per sec
        my $sats = ($sat - $old_sat) / $tdiff;

        #
        #  Print statistics
        #
        if ($rbps ne "") {
            my @Time = localtime();

            if ($STYLE == 0) {
                printf "%02d:%02d:%02d %5s " .
                       "%7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f
",
                       $Time[2], $Time[1], $Time[0], $int, $rkps, $wkps,
                       $rpps, $wpps, $ravs, $wavs, $util, $sats;
            }
            elsif ($STYLE == 1) {
                printf "%02d:%02d:%02d %8s %14.3f %14.3f
",
                       $Time[2], $Time[1], $Time[0], $int, $rkps, $wkps;
            }

            $line++;

            # for multiple interfaces, always print the header
            $line += $PAGESIZE if @NetworkData > 1;
        }

        ### Store old values
        $NetworkDataOld{$int}
            = "$rbytes:$wbytes:$rpackets:$wpackets:$sat:$time";
    }

    ### Check for end
    last if ++$loop == $loop_max;

    ### Interval
    sleep $interval;
}


# find_nets - walk Kstat to discover network interfaces.
#
# This walks %Kstat and populates a %NetworkNames with discovered
# network interfaces.
#
sub find_nets {
    my $found = 0;

    ### Loop over all Kstat modules
    foreach my $module (keys %$Kstat) {
        my $Modules = $Kstat->{$module};
        foreach my $instance (keys %$Modules) {
            my $Instances = $Modules->{$instance};

            foreach my $name (keys %$Instances) {

                ### Skip interface if asked
                if ($NETWORKONLY) {
                    next unless $NetworkOnly{$name};
                }

                my $Names = $Instances->{$name};

                # Check this is a network device.
                # Matching on ifspeed has been more reliable than "class"
                if (defined $$Names{ifspeed} and $$Names{ifspeed}) {

                    ### Save network interface
                    $NetworkNames{$name} = $Names;
                    $found++;
                }
            }
        }
    }

    return $found;
}

# fetch - fetch Kstat data for the network interfaces.
#
# This uses the interfaces in %NetworkNames and returns useful Kstat data.
# The Kstat values used are rbytes64, obytes64, ipackets64, opackets64
# (or the 32 bit versions if the 64 bit values are not there).
#
sub fetch_net_data {
    my ($rbytes, $wbytes, $rpackets, $wpackets, $speed, $time);
    my @NetworkData = ();

    $Kstat->update();

    ### Loop over previously found network interfaces
    foreach my $name (keys %NetworkNames) {
        my $Names = $NetworkNames{$name};

        if (defined $$Names{obytes} or defined $$Names{obytes64}) {

            ### Fetch write bytes
            if (defined $$Names{obytes64}) {
                $rbytes = $$Names{rbytes64};
                $wbytes = $$Names{obytes64};
            }
            else {
                $rbytes = $$Names{rbytes};
                $wbytes = $$Names{obytes};
            }

            ### Fetch read bytes
            if (defined $$Names{opackets64}) {
                $rpackets = $$Names{ipackets64};
                $wpackets = $$Names{opackets64};
            }
            else {
                $rpackets = $$Names{ipackets};
                $wpackets = $$Names{opackets};
            }
            ### Fetch interface speed
            if (defined $$Names{ifspeed}) {
                $speed = $$Names{ifspeed};
            }
            else {
                # if we can't fetch the speed, print the
                # %Util as 0.0 . To do this we,
                $speed = 2 ** 48;
            }

            ### Determine saturation value
            my $sat = 0;
            if (defined $$Names{nocanput} or defined $$Names{norcvbuf}) {
                $sat += defined $$Names{defer} ? $$Names{defer} : 0;
                $sat += defined $$Names{nocanput} ? $$Names{nocanput} : 0;
                $sat += defined $$Names{norcvbuf} ? $$Names{norcvbuf} : 0;
                $sat += defined $$Names{noxmtbuf} ? $$Names{noxmtbuf} : 0;
            }

            ### use the last snaptime value,
            $time = $$Names{snaptime};

            ### store data
            push @NetworkData, "$name:$rbytes:$wbytes:" .
             "$rpackets:$wpackets:$speed:$sat:$time";
        }
    }

    return @NetworkData;
}

# usage - print usage and exit.
#
sub usage {
        print STDERR <<END;
USAGE: nicstat [-hsz] [-i int[,int...]] | [interval [count]]
   eg, nicstat               # print summary since boot
       nicstat 1             # print continually every 1 second
       nicstat 1 5           # print 5 times, every 1 second
       nicstat -s            # summary output
       nicstat -i hme0       # print hme0 only
END
        exit 1;
}

A Performance Utility for CPU, Memory, Disk, and Net

#!/usr/bin/perl -w
#
# sysperfstat - System Performance Statistics. Solaris 8+, Perl.
#
# This displays utilisation and saturation for CPU, memory, disk and network.
# This can be useful to get an overall view of system performance, the
# "view from 20,000 feet".
#
# 19-Mar-2006, ver 0.85
#
# USAGE:    sysperfstat [-h] | [interval [count]]
#    eg,
#           sysperfstat                 # print summary since boot only
#           sysperfstat 5               # print continually, every 5 seconds
#           sysperfstat 1 5             # print 5 times, every 1 second
#           sysperfstat -h              # print help
#
# This program prints utilisation and saturation values from four areas
# on one line. The first line printed is the summary since boot.
# The values represent,
#
# Utilisation,
#           CPU            # usr + sys time across all CPUs
#           Memory         # free RAM. freemem from availrmem
#           Disk           # %busy. r+w times across all Disks
#           Network        # throughput. r+w bytes across all NICs
#
# Saturation,
#           CPU            # threads on the run queue
#           Memory         # scan rate of the page scanner
#           Disk           # operations on the wait queue
#           Network        # errors due to buffer saturation
#
# The utilisation values for CPU and Memory have maximum values of 100%,
# Disk and Network don't. 100% CPU means all CPUs are running at 100%, however
# 100% Disk means perhaps 1 disk is running at 100%, or 2 disks at 50%;
# a similar calculation is used for Network. There are some sensible
# reasons behind this decision that I hope to document at some point.
#
# The saturation values have been tuned to be similar to system load averages;
# A value of 1.00 indicates moderate saturation of the resource (usually bad),
# a value of 4.00 would indicate heavy saturation or demand for the resource.
# A value of 0.00 does not indicate idle or unused - rather not saturated.
#
# See other Solaris commands for further details on utilisation or saturation.
#
# NOTE: For new physical disk types, add their module name to the @Disk
# tunable in the code below.
#
# Author: Brendan Gregg  [Sydney, Australia]
#

use strict;
use Sun::Solaris::Kstat;
my $Kstat = Sun::Solaris::Kstat->new();

#
#  Tunables
#

#
# Default tick rate. use 1000 if hires_tick is on
#
my $HERTZ = 100;

#
# Default NIC speed (if detection fails). 100 Mbits/sec
#
my $NIC_SPEED = 100_000_000;

#
# Disk module names
# these are deliberatly hard-coded, so that we match physical
# disks and not metadevices (which from kstat look like disks).
# matching metadevices would overcount disk statistics.
#
my @Disk = qw(cmdk dad sd ssd);
#
#  Process command line args
#
usage() if defined $ARGV[0] and $ARGV[0] =~ /^(-h|--help|0)$/;

# process [interval [count]],
my ($interval, $loop_max);
if (defined $ARGV[0]) {
    $interval = $ARGV[0];
    $loop_max = defined $ARGV[1] ? $ARGV[1] : 2**32;
    usage() if $interval == 0;
}
else {
    $interval = 1;
    $loop_max = 1;
}

#
#  Variables
#
my $loop = 0;               # current loop number
my $PAGESIZE = 20;          # max lines per header
my $lines = $PAGESIZE;      # counter for lines printed
my $cycles  = 0;            # CPU ticks usr + sys
my $freepct = 0;            # Memory free
my $busy    = 0;            # Disk busy
my $thrput  = 0;            # Network r+w bytes
my $runque  = 0;            # CPU total run queue length
my $scan    = 0;            # Memory scan rate
my $wait    = 0;            # Disk wait sum
my $error   = 0;            # Network errors
$| = 1;
my ($update1, $update2, $update3, $update4);

### Set Disk and Network identify hashes
my (%Disk, %Network);
$Disk{$_} = 1 foreach (@Disk);
discover_net();


#
#  Main
#

while (1) {

    ### Print header
    if ($lines++ >= $PAGESIZE) {
        $lines = 0;
        printf "%8s %28s %28s
", "", "------ Utilisation ------",
               "------ Saturation ------";
        printf "%8s %7s %6s %6s %6s %7s %6s %6s %6s
", "Time", "%CPU",
               "%Mem", "%Disk", "%Net", "CPU", "Mem", "Disk", "Net";
    }

    #
    #  Store old values
    #
    my $oldupdate1 = $update1;
    my $oldupdate2 = $update2;
    my $oldupdate3 = $update3;
    my $oldupdate4 = $update4;
    my $oldcycles  = $cycles;
    my $oldbusy    = $busy;
    my $oldthrput  = $thrput;
    my $oldrunque  = $runque;
    my $oldscan     = $scan;
    my $oldwait     = $wait;
    my $olderror    = $error;

    #
    #  Get new values
    #
    $Kstat->update();
    ($cycles, $runque, $update1) = fetch_cpu();
    ($freepct, $scan, $update2)  = fetch_mem();
    ($busy, $wait, $update3)     = fetch_disk();
    ($thrput, $error, $update4)  = fetch_net();

    #
    #  Calculate utilisation
    #
    my $ucpu  = ratio($cycles, $oldcycles, $update1, $oldupdate1, 100);
    my $umem  = sprintf("%.2f", $freepct);
    my $udisk = ratio($busy, $oldbusy, $update3, $oldupdate3);
    my $unet  = ratio($thrput, $oldthrput, $update4, $oldupdate4);

    #
    #  Calculate saturation
    #
    my $scpu  = ratio($runque, $oldrunque, $update1, $oldupdate1);
    my $smem  = ratio($scan, $oldscan, $update2, $oldupdate2);
    my $sdisk = ratio($wait, $oldwait, $update3, $oldupdate3);
    my $snet  = ratio($error, $olderror, $update4, $oldupdate4);

    #
    #  Print utilisation and saturation
    #
    my @Time = localtime();
    printf "%02d:%02d:%02d %7s %6s %6s %6s %7s %6s %6s %6s
",
           $Time[2], $Time[1], $Time[0], $ucpu, $umem, $udisk, $unet,
           $scpu, $smem, $sdisk, $snet;

    ### Check for end
    last if ++$loop == $loop_max;

    ### Interval
    sleep $interval;
}


#
#  Subroutines
#

# fetch_cpu - fetch current usr + sys times, and the runque length.
#
sub fetch_cpu {

    ### Variables
    my ($runqueue, $time, $usr, $sys, $util, $numcpus);
    $usr = 0; $sys = 0;

    ### Loop over all CPUs
    my $Modules = $Kstat->{cpu_stat};
    foreach my $instance (keys(%$Modules)) {
        my $Instances = $Modules->{$instance};

        foreach my $name (keys(%$Instances)) {
            ### Utilisation - usr + sys
            my $Names = $Instances->{$name};
            if (defined $$Names{user}) {
                $usr += $$Names{user};
                $sys += $$Names{kernel};
                # use last time seen
                $time = $$Names{snaptime};
            }
        }
    }

    ### Saturation - runqueue length
    $runqueue = $Kstat->{unix}->{0}->{sysinfo}->{runque};

    ### Utilisation - usr + sys
    $numcpus = $Kstat->{unix}->{0}->{system_misc}->{ncpus};
    $numcpus = 1 if $numcpus == 0;
    $util = ($usr + $sys) / $numcpus;
    $util = $util * 100/$HERTZ if $HERTZ != 100;

    ### Return
    return ($util, $runqueue, $time);
}

# fetch_mem - return memory percent utilised and scanrate.
#
# To determine the memory utilised, we use availrmem as the limit of
# usable RAM by the VM system, and freemem as the amount of RAM
# currently free.
#
sub fetch_mem {

    ### Variables
    my ($scan, $time, $pct, $freemem, $availrmem);
    $scan = 0;

    ### Loop over all CPUs
    my $Modules = $Kstat->{cpu_stat};
    foreach my $instance (keys(%$Modules)) {
        my $Instances = $Modules->{$instance};

        foreach my $name (keys(%$Instances)) {
            my $Names = $Instances->{$name};

            ### Saturation - scan rate
            if (defined $$Names{scan}) {
                $scan += $$Names{scan};
                # use last time seen
                $time = $$Names{snaptime};
            }
        }
    }

    ### Utilisation - free RAM (freemem from availrmem)
    $availrmem = $Kstat->{unix}->{0}->{system_pages}->{availrmem};
    $freemem = $Kstat->{unix}->{0}->{system_pages}->{freemem};

    #
    # Process utilisation.
    # this is a little odd, most values from kstat are incremental
    # however these are absolute. we calculate and return the final
    # value as a percentage. page conversion is not necessary as
    # we divide that value away.
    #
    $pct = 100 - 100 * ($freemem / $availrmem);
    #
    # Process Saturation.
    # Divide scanrate by slowscan, to create sensible saturation values.
    # Eg, a consistant load of 1.00 indicates consistantly at slowscan.
    # slowscan is usually 100.
    #
    $scan = $scan / $Kstat->{unix}->{0}->{system_pages}->{slowscan};

    ### Return
    return ($pct, $scan, $time);
}

# fetch_disk - fetch kstat values for the disks.
#
# The values used are  the r+w times for utilisation, and wlentime
# for saturation.
#
sub fetch_disk {

    ### Variables
    my ($wait, $time, $rtime, $wtime, $disktime);
    $wait = $rtime = $wtime = 0;

    ### Loop over all Disks
    foreach my $module (keys(%$Kstat)) {

        # Check that this is a physical disk
        next unless $Disk{$module};
        my $Modules = $Kstat->{$module};

        foreach my $instance (keys(%$Modules)) {
            my $Instances = $Modules->{$instance};

            foreach my $name (keys(%$Instances)) {

                # Check that this isn't a slice
                next if $name =~ /,/;

                my $Names = $Instances->{$name};

                ### Utilisation - r+w times
                if (defined $$Names{rtime} or defined $$Names{rtime64}) {
                    # this is designed to be future safe
                    if (defined $$Names{rtime64}) {
                        $rtime += $$Names{rtime64};
                        $wtime += $$Names{wtime64};
                    }
                    else {
                        $rtime += $$Names{rtime};
                        $wtime += $$Names{wtime};
                    }
                }

                ### Saturation - wait queue
                if (defined $$Names{wlentime}) {
                    $wait += $$Names{wlentime};
                    $time = $$Names{snaptime};
                }
            }
        }
    }

    ### Process Utilisation
    $disktime = 100 * ($rtime + $wtime);
    ### Return
    return ($disktime, $wait, $time);
}

# fetch_net - fetch kstat values for the network interfaces.
#
# The values used are r+w bytes, defer, nocanput, norcvbuf and noxmtbuf.
# These error statistics aren't ideal, as they are not always triggered
# for network satruation. Future versions may pull this from the new tcp
# mib2 or net class kstats in Solaris 10.
#
sub fetch_net {

    ### Variables
    my ($err, $time, $speed, $util, $rbytes, $wbytes);
    $err = $util = 0;

    ### Loop over all NICs
    foreach my $module (keys(%$Kstat)) {

        # Check this is a network device
        next unless $Network{$module};
        my $Modules = $Kstat->{$module};

        foreach my $instance (keys(%$Modules)) {
            my $Instances = $Modules->{$instance};

            foreach my $name (keys(%$Instances)) {
                my $Names = $Instances->{$name};

                # Check that this is a network device
                next unless defined $$Names{ifspeed};

                ### Utilisation - r+w bytes
                if (defined $$Names{obytes} or defined $$Names{obytes64}) {
                    if (defined $$Names{obytes64}) {
                        $rbytes = $$Names{rbytes64};
                        $wbytes = $$Names{obytes64};
                    }
                    else {
                        $rbytes = $$Names{rbytes};
                        $wbytes = $$Names{obytes};
                    }

                    if (defined $$Names{ifspeed} and $$Names{ifspeed}) {
                        $speed = $$Names{ifspeed};
                    }
                    else {
                        $speed = $NIC_SPEED;
                    }

                    #
                    # Process Utilisation.
                    # the following has a mysterious "800", it is 100
                    # for the % conversion, and 8 for bytes2bits.
                    # $util is cumulative, and needs further processing.
                    #
                    $util += 800 * ($rbytes + $wbytes) / $speed;
                }

                ### Saturation - errors
                if (defined $$Names{nocanput} or defined $$Names{norcvbuf}) {
                    $err += defined $$Names{defer} ? $$Names{defer} : 0;
                    $err += defined $$Names{nocanput} ? $$Names{nocanput} : 0;
                    $err += defined $$Names{norcvbuf} ? $$Names{norcvbuf} : 0;
                    $err += defined $$Names{noxmtbuf} ? $$Names{noxmtbuf} : 0;
                    $time = $$Names{snaptime};
                }
            }
        }
    }

    #
    # Process Saturation.
    # Divide errors by 200. This gives more sensible load averages,
    # such as 4.00 meaning heavily saturated rather than 800.00.
    #
    $err = $err / 200;

    ### Return
    return ($util, $err, $time);
}

# discover_net - discover network modules, populate %Network.
#
# This could return an array of pointers to Kstat objects, but for
# now I've kept things simple.
#
sub discover_net {

    ### Loop over all NICs
    foreach my $module (keys(%$Kstat)) {

        my $Modules = $Kstat->{$module};
        foreach my $instance (keys(%$Modules)) {

            my $Instances = $Modules->{$instance};
            foreach my $name (keys(%$Instances)) {

                my $Names = $Instances->{$name};

                # Check this is a network device.
                # Matching on ifspeed has been more reliable than "class"
                if (defined $$Names{ifspeed}) {
                    $Network{$module} = 1;
                }
            }
        }
    }
}

# ratio - calculate the ratio of a count delta over time delta.
#
# Takes count and oldcount, time and oldtime. Returns a string
# of the value, or a null string if not enough data was provided.
#
sub ratio {

    my ($count, $oldcount, $time, $oldtime, $max) = @_;

    # Calculate deltas
    my $countd = $count - (defined $oldcount ? $oldcount : 0);
    my $timed = $time - (defined $oldtime ? $oldtime : 0);

    # Calculate ratio
    my $ratio = $timed > 0 ? $countd / $timed : 0;

    # Maximum cap
    if (defined $max) {
        $ratio = $max if $ratio > $max;
    }
    # Return as rounded string
    return sprintf "%.2f", $ratio;
}

# usage - print usage and exit.
#
sub usage {
        print STDERR <<END;
USAGE: sysperfstat [-h] | [interval [count]]
   eg, sysperfstat               # print summary since boot only
       sysperfstat 5             # print continually every 5 seconds
       sysperfstat 1 5           # print 5 times, every 1 second
END
        exit 1;
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.14.134.130