#!/usr/bin/perl
#
# $Revision: 1.9 $
# Copyright 2008 Teleflora
#
# System Performance gathering and analysis for an RTI system.
#

use strict;
use warnings;
use POSIX;
use Getopt::Long;


my $VMSTAT_SLEEP = 3;
my $IOSTAT_SLEEP = 30;
my $PS_SLEEP = 60;
my $DF_SLEEP = 300;
my $LOGFILE = "/tmp/performance_results.txt";
my $OS = "";
my $analyze = 0;


GetOptions(
	"analyze!" => \$analyze
);


if($analyze != 0) {
	analyze_data();
	exit(0);
}




# Which OS is this?
$OS = `uname`;
chomp($OS);
if($OS =~ /Linux/i) {
	$OS = "linux";
} else {
	$OS = "sco";
}



header_info();
run_ps();
run_df();

if($OS eq "linux") {
	run_vmstat();
	run_iostat();
} else {
	run_sar();
}

print "Logging results to $LOGFILE\n";
exit 0;



sub header_info
{

	open LOG, ">> $LOGFILE";

	# System Name
	open PIPE, "uname -a |";
	while(<PIPE>) {
		print LOG strftime("%Y%m%d%H%M%S:", localtime());
		print LOG "$OS:uname: $_";
	}
	close PIPE;


	if($OS eq "linux") {

		# Which distro?
		open PIPE, "< /etc/redhat-release";
		while(<PIPE>) {
			print LOG strftime("%Y%m%d%H%M%S:", localtime());
			print LOG "$OS:redhat-release: $_";
		}
		close PIPE;


		# What kind of processors? How many?
		open PIPE, "< /proc/cpuinfo";
		while(<PIPE>) {
			print LOG strftime("%Y%m%d%H%M%S:", localtime());
			print LOG "$OS:cpuinfo: $_";
		}
		close PIPE;


		# How much RAM, how much configured swap?
		open PIPE, "< /proc/meminfo";
		while(<PIPE>) {
			print LOG strftime("%Y%m%d%H%M%S:", localtime());
			print LOG "$OS:meminfo: $_";
		}
		close PIPE;


		# What network devices? 
		open PIPE, "/sbin/ifconfig |";
		while(<PIPE>) {
			print LOG strftime("%Y%m%d%H%M%S:", localtime());
			print LOG "$OS:ifconfig: $_";
		}
		close PIPE;


		# Basicically, a log of all hardware and drivers loaded.
		open PIPE, "dmesg |";
		while(<PIPE>) {
			print LOG strftime("%Y%m%d%H%M%S:", localtime());
			print LOG "$OS:dmesg: $_";
		}
		close PIPE;


		# When was last rebooted?
		open PIPE, "last reboot |";
		while(<PIPE>) {
			print LOG strftime("%Y%m%d%H%M%S:", localtime());
			print LOG "$OS:last: $_";
		}
		close PIPE;
	}




	close LOG;


	return 0;
}



#
# Basic IO, swap, CPU usage.
#
sub run_vmstat
{
	my $pid = 0;

	$pid = fork();
	if($pid != 0) {
		print "VMStat backgrounded as PID $pid\n";
		return "";
	}

	# Child from here down.
	open LOG, ">> $LOGFILE";


	open VMSTAT, "vmstat $VMSTAT_SLEEP |";
	while (<VMSTAT>) {
		print LOG strftime("%Y%m%d%H%M%S:", localtime());
		print LOG "$OS:vmstat: $_";
	}
	close LOG;
	close VMSTAT;

	exit 0;
}



#
# Basic status of where the disks are.
#
sub run_iostat
{
	my $pid = 0;
	my $device = "";

	$pid = fork();
	if($pid != 0) {
		print "IOStat backgrounded as PID $pid\n";
		return "";
	}

	# Child from here down.
	open LOG, ">> $LOGFILE";


	open IOSTAT, "iostat -d -x $IOSTAT_SLEEP |";
	while (<IOSTAT>) {
		if(/^\/dev\//) {
			chomp;
			$device = $_;
			next;
		}
		print LOG strftime("%Y%m%d%H%M%S:", localtime());
		print LOG "$OS:iostat: $device $_";
	}
	close LOG;
	close IOSTAT;

	exit 0;

}



#
# Look at all running processes.
#
sub run_ps
{
	my $pid = 0;

	$pid = fork();
	if($pid != 0) {
		print "PS backgrounded as PID $pid\n";
		return "";
	}

	# Child from here down.
	open LOG, ">> $LOGFILE";


	while(1) {
		sleep $PS_SLEEP;
		if($OS eq "linux") {
			open PS, "ps wwaux  |";
		} else {
			open PS, "ps -ef -o pid,size,pcpu,s,vsz,time,ppid,user,stime,args |";
		}
		while (<PS>) {
			print LOG strftime("%Y%m%d%H%M%S:", localtime());
			print LOG "$OS:ps: $_";
		}
		close PS;
	}
	close LOG;

	exit 0;

}



#
# "Sar" utility under SCO.
#
sub run_sar
{
	my $pid = 0;



	$pid = fork();
	if($pid != 0) {
		print "SAR backgrounded as PID $pid\n";
		return "";
	}

	# Child from here down.
	open LOG, ">> $LOGFILE";
	open SAR, "sar -A $VMSTAT_SLEEP 60 |";
	while (<SAR>) {
		print LOG strftime("%Y%m%d%H%M%S:", localtime());
		print LOG "$OS:sar: $_";
	}
	close LOG;
	close SAR;



	exit 0;
}





#
# See disk capacities.
#
sub run_df
{
	my $pid = 0;



	$pid = fork();
	if($pid != 0) {
		print "DF backgrounded as PID $pid\n";
		return "";
	}

	# Child from here down.
	open LOG, ">> $LOGFILE";

	while(1) {
		sleep $DF_SLEEP;
		open DF, "df -k |";
		while (<DF>) {
			print LOG strftime("%Y%m%d%H%M%S:", localtime());
			print LOG "$OS:df: $_";
		}
		close DF;
	}

	exit 0;
}


sub analyze_data
{
	my $line = "";
	my %record = ();

	my @vmstat_fields = (
		"cpu_user",
		"cpu_system",
		"cpu_idle",
		"cpu_wait",
		"free_kB",
		"swap_out"
	);

	my @iostat_fields = (
		"device",
		"percent_util",
		"rkb_per_sec",
		"wkb_per_sec",
	);




	# Open "iostat.txt" and print header.
	open IOSTAT, "> iostat.txt";
	print IOSTAT "\"timestamp\"";
	foreach(@iostat_fields) {
		print IOSTAT ",\"$_\"";
	}
	print IOSTAT "\n";


	# Open "vmstat.txt" and print header.
	open VMSTAT, "> vmstat.txt";
	print VMSTAT "\"timestamp\"";
	foreach(@vmstat_fields) {
		print VMSTAT ",\"$_\"";
	}
	print VMSTAT "\n";


	# Open "ps.txt" and print header.
	open PS, "> ps.txt";
	print PS "\"timestamp\"";
	print PS "\"pid\"";
	print PS "\"cpu_percent\"";
	print PS "\"mem_percent\"";
	print PS "\"mem_vsz\"";
	print PS "\"mem_rss\"";
	print PS "\"command\"";
	print PS "\n";



	while(<STDIN>) {
		chomp;
		$line = $_;

		# YYYYMMDDHHMMSS should always start us off.
		# next if ($line !~ /^(\d{14})/);
		next if ($line !~ /^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/);

		# linux PS
		if( $line =~ /

			# Timestamp
			^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})
			(:linux:ps:)
			([[:space:]]{0,1})

			# user
			([[:alnum:]]+)
			([[:space:]]+)

			# pid
			([[:digit:]]+)
			([[:space:]]+)

			# CPU
			([0-9\.]+)
			([[:space:]]+)

			# Mem
			([0-9\.]+)
			([[:space:]]+)

			# VSZ
			([[:digit:]]+)
			([[:space:]]+)

			# RSS
			([[:digit:]]+)
			([[:space:]]+)

			# TTY
			(\S+)
			([[:space:]]+)

			# STAT
			(\S+)
			([[:space:]]+)

			# START
			(\S+)
			([[:space:]]+)

			# TIME
			(\S+)
			([[:space:]]+)
			
			# Command
			([[:print:]]+)$

			/x) {

				$record{'year'} = $1;
				$record{'month'} = $2;
				$record{'day'} = $3;
				$record{'hour'} = $4;
				$record{'minute'} = $5;
				$record{'second'} = $6;
				$record{'timestamp'} = "$record{'year'}/$record{'month'}/$record{'day'} $record{'hour'}:$record{'minute'}:$record{'second'}";
				$record{'user'} = $9;
				$record{'pid'} = $11;
				$record{'cpu_percent'} = $13;
				$record{'mem_percent'} = $15;
				$record{'mem_vsz'} = $17;
				$record{'mem_rss'} = $19;
				$record{'tty'} = $21;
				$record{'stat'} = $23;
				$record{'start'} = $25;
				$record{'time'} = $27;

				# Some, "command" -> Some 'command'
				$record{'command'} = $29;
				$record{'command'} =~ s/\"/\'/g;
				$record{'command'} =~ s/\,/ /g;

				if($record{'cpu_percent'} > 10
				|| $record{'mem_percent'} > 10
				) {
					print PS "\"$record{'timestamp'}\"";
					print PS
						",$record{'pid'}" 
						. ",$record{'cpu_percent'}"
						. ",$record{'mem_percent'}"
						. ",$record{'mem_vsz'}"
						. ",$record{'mem_rss'}"
						. ",\"$record{'command'}\""
						. "\n";
				}


		# Linux Vmstat
		} elsif( $line =~ /

			# Timestamp
			^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})
			(:linux:vmstat:)
			([[:space:]]+)

			# r
			([[:digit:]]+)
			([[:space:]]+)

			# b
			([[:digit:]]+)
			([[:space:]]+)

			# swpd
			([[:digit:]]+)
			([[:space:]]+)

			# free
			([[:digit:]]+)
			([[:space:]]+)

			# buff
			([[:digit:]]+)
			([[:space:]]+)

			# cache
			([[:digit:]]+)
			([[:space:]]+)

			# si (swap in)
			([[:digit:]]+)
			([[:space:]]+)

			# so (swap out)
			([[:digit:]]+)
			([[:space:]]+)

			# bi (blocks in)
			([[:digit:]]+)
			([[:space:]]+)

			# bo (blocks out)
			([[:digit:]]+)
			([[:space:]]+)

			# in
			([[:digit:]]+)
			([[:space:]]+)

			# cs (Context Switches)
			([[:digit:]]+)
			([[:space:]]+)

			# us (User CPU Time)
			([[:digit:]]+)
			([[:space:]]+)

			# sy (System CPU time)
			([[:digit:]]+)
			([[:space:]]+)

			# id (Idle CPU Time)
			([[:digit:]]+)
			([[:space:]]+)

			# wa (Wait CPU Time)
			([[:digit:]]+)
			([[:space:]]*)

		/x) {
			$record{'year'} = $1;
			$record{'month'} = $2;
			$record{'day'} = $3;
			$record{'hour'} = $4;
			$record{'minute'} = $5;
			$record{'second'} = $6;
			$record{'timestamp'} = "$record{'year'}/$record{'month'}/$record{'day'} $record{'hour'}:$record{'minute'}:$record{'second'}";
			$record{'r'} = $9;
			$record{'b'} = $11;
			$record{'swpd'} = $13;
			$record{'free_kB'} = $15;
			$record{'buff'} = $17;
			$record{'cache'} = $19;
			$record{'swap_in'} = $21;
			$record{'swap_out'} = $23;
			$record{'block_in'} = $25;
			$record{'block_out'} = $27;
			$record{'in'} = $29;
			$record{'context_switches'} = $31;
			$record{'cpu_user'} = $33;
			$record{'cpu_system'} = $35;
			$record{'cpu_idle'} = $37;
			$record{'cpu_wait'} = $39;


			print VMSTAT "\"$record{'timestamp'}\"";
			foreach(@vmstat_fields) {
				print VMSTAT "," . $record{$_};
			}
			print VMSTAT "\n";

		# Linux IOStat
		} elsif ( $line =~ /

			# Timestamp
			^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})
			(:linux:iostat:)
			([[:space:]]+)


			# Device
			(sd[abcde])
			([[:space:]]+)

			# rrqm per s
			(\d+\.\d+)
			([[:space:]]+)

			# wrqm per s
			(\d+\.\d+)
			([[:space:]]+)

			# r per s
			(\d+\.\d+)
			([[:space:]]+)

			# w per s
			(\d+\.\d+)
			([[:space:]]+)

			# rsec per sec
			(\d+\.\d+)
			([[:space:]]+)

			# wsec per sec
			(\d+\.\d+)
			([[:space:]]+)

			# rkB per sec
			(\d+\.\d+)
			([[:space:]]+)

			# wkB per sec
			(\d+\.\d+)
			([[:space:]]+)

			# avgrq size
			#(\d+\.\d+)
			#([[:space:]]+)

			# await
			(\d+\.\d+)
			([[:space:]]+)

			# svctm
			(\d+\.\d+)
			([[:space:]]+)

			# percent util
			(\d+\.\d+)
			([[:space:]]*)

		/x) {

			$record{'year'} = $1;
			$record{'month'} = $2;
			$record{'day'} = $3;
			$record{'hour'} = $4;
			$record{'minute'} = $5;
			$record{'second'} = $6;
			$record{'timestamp'} = "$record{'year'}/$record{'month'}/$record{'day'} $record{'hour'}:$record{'minute'}:$record{'second'}";
			$record{'device'} = $9;
			$record{'rrqm_per_sec'} = $11;
			$record{'wrqm_per_sec'} = $13;
			$record{'r_per_sec'} = $15;
			$record{'w_per_sec'} = $17;
			$record{'rsec_per_sec'} = $19;
			$record{'wsec_per_sec'} = $21;
			$record{'rkb_per_sec'} = $23;
			$record{'wkb_per_sec'} = $25;
			#$record{'avgrq_size'} = $27;
			$record{'await'} = $27;
			$record{'svctm'} = $29;
			$record{'percent_util'} = $31;


			print IOSTAT "\"$record{'timestamp'}\"";
			foreach(@iostat_fields) {
				print IOSTAT "," . $record{$_};
			}
			print IOSTAT "\n";

		}

	}
	close VMSTAT;
	close IOSTAT;
	close PS;



	return 0;
}
