Вы находитесь на странице: 1из 7

#!

/usr/bin/perl -w
#
# nicstat - print network traffic, Kbyte/s read and written.
#
Solaris 8+, Perl (Sun::Solaris::Kstat).
#
# "netstat -i" only gives a packet count, this program gives Kbytes.
#
# 30-Sep-2006, ver 1.00 (check for new versions, http://www.brendangregg.com)
#
# 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)
#
# NOTES:
#
# - Some unusual network cards may not provide all the details to Kstat,
# (or provide different symbols). Check for newer versions of this program,
# and the @Network array in the code below.
# - Utilisation is based on bytes transferred divided by speed of the interface
# (if the speed is known). It should be impossible to reach 100% as there
# are overheads due to bus negotiation and timing.
# - Loopback interfaces may only provide packet counts (if anything), and so
# bytes and %util will always be zero. Newer versions of Solaris (newer than
# Solaris 10 6/06) may provide loopback byte stats.
# - Saturation is determined by counting read and write errors caused by the
# interface running at saturation. This approach is not ideal, and the value
# reported is often lower than it should be (eg, 0.0). Reading the rKB/s and
# wKB/s fields may be more useful.
#
# SEE ALSO:
#
nicstat.c
# the C version, also on my website
#
kstat -n hme0 [interval [count]]
# or qfe0, ...
#
netstat -iI hme0 [interval [count]]
#
se netstat.se [interval]
# SE Toolkit
#
se nx.se [interval]
# SE Toolkit
#
# COPYRIGHT: Copyright (c) 2006 Brendan Gregg.

#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#

This program is
modify it under
as published by
of the License,

free software; you can redistribute it and/or


the terms of the GNU General Public License
the Free Software Foundation; either version 2
or (at your option) any later version.

This program is distributed in the hope that it will be useful,


but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
(http://www.gnu.org/copyleft/gpl.html)
Author: Brendan Gregg [Sydney, Australia]
18-Jul-2004
07-Jan-2005
07-Jan-2005
23-Jan-2006
11-Aug-2006
30-Sep-2006

Brendan Gregg
"
"
"
"
"
"
"
"
"
"

Created this.
added saturation value.
added summary style (from Peter Tribble).
Tweaked style.
Improved output neatness.
Added loopback, tweaked output.

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;
my $PAGESIZE = 20;
my $line = $PAGESIZE;
my %NetworkNames;
my %NetworkData;
my %NetworkDataOld;
$main::opt_h = 0;
$| = 1;

#
#
#
#
#
#

current loop number


max lines per header
counter for lines printed
Kstat network interfaces
network interface data
network interface data

# autoflush

### Determine network interfaces


unless (find_nets()) {
if ($NETWORKONLY) {
print STDERR "ERROR1: $main::opt_i matched no network interfaces.\n";
}
else {
print STDERR "ERROR1: No network interfaces found!\n";
}
exit 1;
}
#
# Main
#
while (1) {
### Print Header
if ($line >= $PAGESIZE) {
if ($STYLE == 0) {
printf "%8s %7s %7s %7s %7s %7s %7s %7s %7s %6s\n",
"Time", "Int", "rKB/s", "wKB/s", "rPk/s", "wPk/s", "rAvs",
"wAvs", "%Util", "Sat";
}
elsif ($STYLE == 1) {
printf "%8s %8s %14s %14s\n", "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 %7s ",
$Time[2], $Time[1], $Time[0], $int;
print_neat($rkps);
print_neat($wkps);
print_neat($rpps);
print_neat($wpps);
print_neat($ravs);
print_neat($wavs);
printf "%7.2f %6.2f\n", $util, $sats;
}
elsif ($STYLE == 1) {
printf "%02d:%02d:%02d %8s %14.3f %14.3f\n",
$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};
}
### Skip if not the regular statistic set
next unless $name =~ /^$module/;
my $Names = $Instances->{$name};
# Check this is a network device.
# Matching on ifspeed has been more reliable than "class"
# we also match loopback interfaces.
if (defined $$Names{ifspeed} || $module eq "lo") {
### 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{opackets}) {
### Fetch write bytes
if (defined $$Names{obytes64}) {
$rbytes = $$Names{rbytes64};
$wbytes = $$Names{obytes64};
}
elsif (defined $$Names{obytes}) {
$rbytes = $$Names{rbytes};
$wbytes = $$Names{obytes};
} else {
$rbytes = $wbytes = 0;
}
### 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;
}
# print_neat - print a float with decimal places if appropriate.
#
# This specifically keeps the width to 7 characters, if possible, plus
# a trailing space.
#
sub print_neat {
my $num = shift;
if ($num >= 100000) {
printf "%7d ", $num;
} elsif ($num >= 100) {
printf "%7.1f ", $num;
} else {
printf "%7.2f ", $num;
}
}
# 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;
}

Вам также может понравиться