#! /bin/bash
. acsstartupAcsPorts  #Import functions like this in bash=(
#*******************************************************************************
# E.S.O. - ACS project
#
# "@(#) $Id: acsutilProfiler,v 1.5 2006/01/10 23:17:40 dfugate Exp $"
#
# who       when      what
# --------  --------  ----------------------------------------------
# dfugate 2004-09-10 created
#

### ----------- Command Line Parsing ---------------------
# These will contain the parsing results (CL_XXX, CL = command line)
CL_RUNS=1
CL_BGROUND=
CL_FINISH=
CL_TIMEOUT=100
CL_MSG=
CL_DATABASE=
CL_ARBITR=

# Usage info. Be nice and keep this up-to-date!
function printUsage 
{
   echo "Profiles an executable"
   echo ""
   echo "Usage: `basename $0` [OPTIONS]  command_to_be_timed  main_args"
   echo "Options: "
   echo "  -r N                                Number of times the command should be executed."
   echo "  -f \"finish command\"                 Optional command executed after each completion"
   echo "                                      of the command being timed."
   echo "  -b \"output signifying completion\"   Optionally forces the command to be run as a background"
   echo "                                      process and this script waits until the specified string" 
   echo "                                      is sent to STDOUT before executing the 'finish command'."
   echo "  -t timeout                          Optional timeout (seconds) used with the -b option (i.e., amount"
   echo "                                      of time to wait for the specified string before giving up)."
   echo "  -m \"some useful message\"            Optional message to be used in place of the command name" 
   echo "                                      with respect to the ACS Profiler output."
   echo "  -d databaseLocation                 Optionally sends this program's output directly to an ACS"
   echo "                                      profiler database instead of STDOUT."
   echo "  -a key=value [ -a key=value ]       A mechanism for adding arbitrary key/value pairs to the output"
   echo "                                      of this script."
   echo "  -h                                  Prints this message and exits."
}

while getopts hr:b:f:t:m:d:a: OPT; do
	case $OPT in
       		h) printUsage; exit 0 ;;
		r) CL_RUNS=$OPTARG ;;
       		b) CL_BGROUND=$OPTARG ;;
		f) CL_FINISH=$OPTARG ;;
		t) CL_TIMEOUT=$OPTARG ;;
	        m) CL_MSG=$OPTARG ;;
	        d) CL_DATABASE=$OPTARG ;;
	        a) CL_ARBITR=$CL_ARBITR,\ $OPTARG ;;
		--) break ;;
   esac
done

shift `expr $OPTIND - 1`


### ---------- Nice, informative messages for the user ------------------
echo "The '$@' command will now run $CL_RUNS times."
if [ "$CL_FINISH" ]
then
	echo "After each run, the '$CL_FINISH' command will be executed."
fi

if [ "$CL_BGROUND" ]
then
	echo "The '$@' command will be run as a background process and this script will"
	echo "assume the command has completed once the '$CL_BGROUND' string has been detected"
	echo "in '$@' output."
	echo "If the '$@' command does not finish executing in $CL_TIMEOUT seconds on any given"
	echo "run, it will be terminated and the ACS executable profiler will terminate abruptly!"
fi

### ---------- Start with some initialization ---------------------------
totalTime="0"
minDuration="99999999999999999"
maxDuration="0"

### ---------- Run it a maximum of $CL_RUNS times -----------------------
i=0
while [ $i != $CL_RUNS ]
do
	start=`date +FORMAT=\ %s.%N| awk '{print $2}'`	

	#if it need not be run as a background process
	if [ ! "$CL_BGROUND" ]
	then	
		$@ > /tmp/acsutilProfiler.$$.$i

	else
		j=0
		$@ > /tmp/acsutilProfiler.$$.$i &
		processID=$!
		while [ $j ]
		do
			okToExit=`grep "$CL_BGROUND" /tmp/acsutilProfiler.$$.$i 2> /dev/null`

			if [ "$j" = "$CL_TIMEOUT" ]
  			then
      				echo "==> Error - process failed to emit '$CL_BGROUND' in allocated time" 1>&2
      				acsKillProc $processID || echo "==> Warning - cannot kill the process" 1>&2
      				exit 45
  			#got the output we need
  			elif [ "X$okToExit" != "X" ] 
  			then
      				break
  			else
      				j=$(( $j + 1 ))
				sleep 1
  			fi
		done
	fi

	stop=`date +FORMAT=\ %s.%N| awk '{print $2}'`

	##perform some final calculations########################
	#looks like bash cannot do decimal arithmetic??? for now use Python
	elapsed=`python -c "print $stop - $start"`
	totalTime=`python -c "print $elapsed + $totalTime"`

	minDuration="`python -c "print min($minDuration,$elapsed)"`"
	maxDuration="`python -c "print max($maxDuration,$elapsed)"`"

	##cleanup if needed######################################
	if [ "$CL_FINISH" ]
	then
		$CL_FINISH > /tmp/acsutilProfiler.$$.$i.finish
	fi	

	i=$(( $i + 1 ))
done


###Statistical analysis here######################################
averageTime=`python -c "print $totalTime / $CL_RUNS"`

###Host info retrieved here#######################################
procSpeed=`dmesg | grep "MHz processor." | awk '{print $2}'`MHz
memSize=`dmesg | grep "Memory:" | awk '{print $2}'`
currentDate=`date -u +%FT%T.%3N`
localIP=`getIP`

if [ ! "$CL_MSG" ]
then
    CL_MSG=$@
fi


OUTPUT="#ACS PROFILER# msg=$CL_MSG, avg=$averageTime, runs=$CL_RUNS, mindur=$minDuration, maxdur=$maxDuration, cpu=$procSpeed, mem=$memSize, date=$currentDate, ip=$localIP, lang=Unknown, units=seconds $CL_ARBITR"

if [ ! $CL_DATABASE ]
then
    #just send it to standard out
    echo $OUTPUT
else
    TMP_PERF_FILE=/tmp/acsutilProfiler.output.$$
    echo "Writing performance analysis data to temporary file '$TMP_PERF_FILE'"
    echo $OUTPUT > $TMP_PERF_FILE
    
    echo "Importing performance analysis data into the '$CL_DATABASE' database"
    ACSPerfAnalyzer $CL_DATABASE $TMP_PERF_FILE
fi
