CasperSecurity

Current Path : /usr/share/doc/sysstat/examples/
Upload File :
Current File : //usr/share/doc/sysstat/examples/irqtop

#!/usr/bin/perl
# irqtop
#
# by Robert Elliott, HP
# contributed to the sysstat project
#
#########################################################################
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published  by  the
# Free Software Foundation; either version 2 of the License, or (at  your
# option) any later version.
#
# This program is distributed in the hope that it  will  be  useful,  but
# WITHOUT ANY WARRANTY; without 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
#########################################################################
#
# Monitor differences in /proc/interrupts and /proc/softirqs
# per CPU, along with CPU statistics
#
# Usage: irqtop [interval]
#
# Displays interrupts that have occurred since this program
# began, filtering those that have always been zeros.
#
# TODO features:
# * increase column widths automatically
# * add an all-CPU column
# * add option to choose between
#     - online CPUs
#     - just the all-CPU column
#     - select CPUs (e.g., ranges like in smp_affinity_list)
# * automatically determine interrupts to total (e.g.
#   all mpt3sas or hpsaN interrupts) based on them having
#   common prefixes in their names or common names
#
use strict;
use Getopt::Long;

my $myname = "irqtop";
my $myversion = "0.2";

sub print_usage {
		print "Usage: $myname [interval] [-V | --version] [-h | --help]\n\n";
		print "  [internal]        time in seconds between updates (default: 1 second)\n";
		print "  [-V | --version]  display version number\n";
		print "  [-h | --help]     display usage\n\n";
		print "Use Control-C to exit\n";
}

#my $mpstat = "../sysstat/mpstat";
my $mpstat = "mpstat";

# calculate total interrupt stats for this list
#my @track_list = ();
my @track_list = ("eth", "hpsa1", "hpsa2", "mpt3sas");

# exclude these from per-vector display (e.g., eth while studying storage)
# still included in totals if also in track_list
#my @exclude_list = ();
my @exclude_list = ("eth");

my $interval = 1;	# default interval in seconds

# hashes of arrays
# key is the interrupt number or name (e.g., 95 or TIMER)
# array is the interrupt counts and the description on the right
my %current;
my %delta;	# hold the deltas between collection and printing

# hash of values
my %ever_changed; 	# indicates if this row ever changed
my %track_interrupts;	# number of each type

my $online_cpus;	# as seen by process_hardirq, used to filter columns in softirq

# return 1 to exclude, 0 to not
sub is_excluded {
	my ($line) = @_;

	foreach (@exclude_list) {
		return 1 if ($line =~ /$_/);
	}
	return 0;
}

# convert affinity_list bitmask (64-bit binary) into numbered list
# Example: 5800a000f -> "0-3,17,19,31-32,34"
# used for parsing /proc/irq/NN/affinity_hint
sub bitmask_to_list {
	my ($bitmask) = @_;
	my $inrange;
	my $rangelist;
	my $rangenew;
	my $lowcpu;
	my $highcpu;

	for (my $i = 0; $i < 63; $i++) {
		if (!$inrange && $bitmask & 1) {
			$inrange = 1;
			$lowcpu = $i;
			$highcpu = $i;
		} elsif ($inrange && $bitmask & 1) {
			$highcpu = $i;
		} elsif ($inrange && !($bitmask & 1)) {
			$inrange = 0;
			if ($lowcpu == $highcpu) {
				$rangenew = "$lowcpu";
			} else {
				$rangenew = "$lowcpu-$highcpu";
			}

			if ($rangelist) {
				$rangelist = "$rangelist,$rangenew";
			} else {
				$rangelist = "$rangenew";
			}
		}

		$bitmask = $bitmask >> 1;
	}
	if ($inrange) {
		$rangelist = "$rangelist,$lowcpu-$highcpu";
	}
	if (!$rangelist) {
		$rangelist = "none";
	}
	return $rangelist;
}

# process /proc/interrupts
# argument:
# 0 do not display - use the first time to not display values since reboot
# 1 display - use on all subsequent calls
sub collect_hardirqs {
	my ($firstpass) = @_;

	open HARDIRQFILE, "/proc/interrupts" or die "Cannot open $_";

	foreach (@track_list) {
		$track_interrupts{$_} = 0;
	}

	# /proc/interrupts lists only online cpus
	# first line contains CPUnn headers for each column
	#            CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7       CPU8       CPU9       CPU10      CPU11
	$_ = <HARDIRQFILE>;
	my @cpulist = split;
	$online_cpus = $#cpulist + 1;	# hardirqs are a source of online_cpus

	# remaining lines contain vector number: per-cpu counts, interrupt type, device
	# or vector name, per-CPU counts, interrupt type, description
	while (<HARDIRQFILE>) {
		my @values = split;
		my $irqname = $values[0];
		my $cpu;
		my $line = $_;

		for ($cpu = 0; $cpu < $online_cpus; $cpu++) {
			$delta{$irqname}[$cpu] = $values[$cpu + 1] - $current{$irqname}[$cpu];
			$current{$irqname}[$cpu] = $values[$cpu + 1];

			# if this is not the first pass,
			# keep track of whether the values have changed
			if ($delta{$irqname}[$cpu] && !$firstpass && !is_excluded($line)) {
				$ever_changed{$irqname} = 1;
			}

			foreach (@track_list) {
				if ($line =~ /$_/) {
					$track_interrupts{$_} += $delta{$irqname}[$cpu];
				}
			}
		}
		# capture the rest of the line (interrupt type, handlers)
		# these are not really per-cpu values, but continue storing
		# each word in %current since it's convenient
		for (; $cpu < $#values + 1; $cpu++ ) {
			$current{$irqname}[$cpu] = $values[$cpu + 1];
		}
	}
	close HARDIRQFILE;

}

# process /proc/softirqs
# argument:
# 0 do not display - use the first time to not display values since reboot
# 1 display - use on all subsequent calls
sub collect_softirqs {
	my ($firstpass) = @_;

	open SOFTIRQFILE, "/proc/softirqs" or die "Cannot open $_";

	# /proc/softirqs includes all possible cpus, not all online cpus
	# this function ignores all those extra cpus
	# first line contains CPUnn headers for each column
	#            CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7       CPU8       CPU9       CPU10      CPU11
	$_ = <SOFTIRQFILE>;
	my @cpulist = split;	# discard the first line

	# remaining lines contain
	#    vector number: per-cpu counts, interrupt type, device
	# or   vector name: per-cpu counts, interrupt type, description
	while (<SOFTIRQFILE>) {
		my @values = split;
		my $irqname = $values[0];
		my $line = $_;

		# just remember the values for online cpus, not offline cpus
		for (my $cpu = 0; $cpu < $online_cpus; $cpu++) {
			$delta{$irqname}[$cpu] = $values[$cpu + 1] - $current{$irqname}[$cpu];
			$current{$irqname}[$cpu] = $values[$cpu + 1];
			if ($delta{$irqname}[$cpu] && !$firstpass && !is_excluded($line)) {
				$ever_changed{$irqname} = 1;
			}
		}
	}
	close SOFTIRQFILE;
}

# print the CPU0 CPU1 CPU2... header line for the online cpus
sub print_cpulist {
	for (my $cpu = 0; $cpu < $online_cpus; $cpu++) {
		my $cpustring;
		$cpustring = sprintf("CPU%d", $cpu);
		printf("%6s ", $cpustring);
	}
	print "\n";
}

# print hardirqs and softirqs from %delta that have ever %changed
sub print_irqs {

	# header line
	printf("%13s ", "--- IRQs ---");
	# print_cpulist(); # uncomment if print_mpstat is not used, since that prints the header line
	print "\n";

	foreach (sort keys %delta) {
		my $irqname = $_;
		# if any values have ever changed for an interrupt, print the delta values
		if ($ever_changed{$irqname}) {
			# match the width of softirq names 12 characters plus :
			printf("%13s ", $irqname);
			my $cpu;
			for ($cpu = 0; $cpu < $online_cpus; $cpu++) {
				printf("%6d ", $delta{$irqname}[$cpu]);
			}
			# print the rest of the line (interrupt type, handlers)
			for (; $cpu < @{$current{$irqname}} + 1; $cpu++ ) {
				print "$current{$irqname}[$cpu] ";
			}

			# print the irq smp affinity list, if any
			my $irqname_nocolon = $irqname;
			$irqname_nocolon =~ s/://;

			if (!($irqname =~ /[A-Z]/)) {
				my $affinity_hint_file = "/proc/irq/$irqname_nocolon/affinity_hint";
				if (-e $affinity_hint_file) {
					open IRQAFF, "<$affinity_hint_file";
					my $affhint = <IRQAFF>;
					close IRQAFF;
					chomp $affhint;
					my ($affhigh,$afflow) = $affhint =~ /(.*),(.*)/;
					my $aff = hex $affhigh << 32 | hex $afflow;
					printf("hint=%s,", bitmask_to_list($aff));
				} else {
					print "hint=none,";
				}
				my $smp_affinity_list_file = "/proc/irq/$irqname_nocolon/smp_affinity_list";
				if (-e $smp_affinity_list_file) {
					open IRQAFF, "<$smp_affinity_list_file";
					my $afflist = <IRQAFF>;
					close IRQAFF;
					chomp $afflist;
					print "aff=$afflist";
				} else {
					print "aff=none";
				}
			}

			print "\n";
		}
	}

	# print summary of selected sets of interrupts
	foreach (@track_list) {
		printf("%12s: total=%-7d, average=%-7d; total/s=%-7d, average/s=%-7d\n",
			$_,
			$track_interrupts{$_},
			$track_interrupts{$_} / $online_cpus,
			$track_interrupts{$_} / $interval,
			$track_interrupts{$_} / $interval / $online_cpus);
	}
}

# collect interesting CPU statistics from mpstat
#	%usr, %sys, %iowait, %idle, %irq, %soft
# mpstat displays:
# 06:14:48 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
# plain "mpstat" shows averages since boot, which is not useful
# so, use the interval option based on the first argument to this function,
# which also causes this function to incur the delay.
# per-cpu arrays of value strings
my @usr;
my @sys;
my @irq;
my @soft;
my @iowait;
my @idle;

sub collect_mpstat {
	my ($delay) = @_;

	open MPSTATFILE, "$mpstat -P ON -u $delay 1 |" or sleep($delay);
	while (<MPSTATFILE>) {
		if (/CPU/ || /all/ || /^$/ || /Average/) {
			next;
		}
		my ($time, $ampm, $cpu, $usr, $nice, $sys, $iowait, $irq, $soft, $steal, $guest, $idle) = split;
		$usr[$cpu] = $usr;
		$sys[$cpu] = $sys;
		$irq[$cpu] = $irq;
		$soft[$cpu] = $soft;
		$iowait[$cpu] = $iowait;
		$idle[$cpu] = $idle;
		$online_cpus = $cpu + 1;	# mpstat is a source for # online CPUs
	}
	close MPSTATFILE;
}

# print the interesting CPU statistics from mpstat
# collected in collect_mpstat()
sub print_mpstat {

	# header line
	printf("%13s ", "CPU usage:");
	print_cpulist();

	printf("%13s ", "\%usr:");
	for (my $cpu = 0; $cpu < $online_cpus; $cpu++) {
		printf("%6s ", $usr[$cpu]);
	}
	print "\n";
	printf("%13s ", "\%sys:");
	for (my $cpu = 0; $cpu < $online_cpus; $cpu++) {
		printf("%6s ", $sys[$cpu]);
	}
	print "\n";
	printf("%13s ", "\%irq:");
	for (my $cpu = 0; $cpu < $online_cpus; $cpu++) {
		printf("%6s ", $irq[$cpu]);
	}
	print "\n";
	printf("%13s ", "\%soft:");
	for (my $cpu = 0; $cpu < $online_cpus; $cpu++) {
		printf("%6s ", $soft[$cpu]);
	}
	print "\n";
	printf("%13s ", "\%iowait idle:"); # clarify that iowait is really idle time
	for (my $cpu = 0; $cpu < $online_cpus; $cpu++) {
		printf("%6s ", $iowait[$cpu]);
	}
	print "\n";
	printf("%13s ", "\%idle:");
	for (my $cpu = 0; $cpu < $online_cpus; $cpu++) {
		printf("%6s ", $idle[$cpu]);
	}
	print "\n";
}

#
# start of program
#
foreach (@ARGV) {
	if (/--version/ || /-V/) {
		print "$myname version $myversion\n";
		exit;
	} elsif (/--help/ || /-h/) {
		print_usage();
		exit;
	} elsif (!/[a-z]/) {
		# assume an all-numeric argument is the interval
		$interval = $_;
	}
	print "Collecting CPU and interrupt activity for $interval seconds between updates\n";
}

# remember the clear screen characters to avoid system() during run time
my $clearscreen = `clear`;
collect_hardirqs(1);
collect_softirqs(1);
while (1) {
	collect_hardirqs(0);
	collect_softirqs(0);
	collect_mpstat($interval);
	my $datestring = localtime();
	print "${clearscreen}$myname $datestring interval: $interval s\n";
	print_mpstat();
	print_irqs();

	# if collect_mpstat(), which delays, is commented out, sleep here
	# sleep($interval);
}
Hacker Blog, Shell İndir, Sql İnjection, XSS Attacks, LFI Attacks, Social Hacking, Exploit Bot, Proxy Tools, Web Shell, PHP Shell, Alfa Shell İndir, Hacking Training Set, DDoS Script, Denial Of Service, Botnet, RFI Attacks, Encryption
Telegram @BIBIL_0DAY