#!/bin/bash
#
# This benchmark measures how much IO in the background interferes with a
# target workload. For example, background IO can severely interefere with
# scheduling or cause a higher priority workload to be swapped out. This
# measures the effect.
#
# Copyright Mel Gorman 2012
###SHELLPACK preamble parallelio-bench 0
. $SHELLPACK_INCLUDE/include-sizes.sh

###SHELLPACK parseargBegin
###SHELLPACK parseargParam --workloads   PARALLELIO_WORKLOADS
###SHELLPACK parseargParam --min-io-size PARALLELIO_MIN_IOSIZE
###SHELLPACK parseargParam --max-io-size PARALLELIO_MAX_IOSIZE
###SHELLPACK parseargParam --io-load     PARALLELIO_IOLOAD
###SHELLPACK parseargParam --iterations  PARALLELIO_ITERATIONS
###SHELLPACK parseargParam --workload-duration PARALLELIO_WORKLOAD_DURATION
###SHELLPACK parseargEnd
###SHELLPACK monitor_hooks
###SHELLPACK init_complete

# Warmup runs
for WORKLOAD in $PARALLELIO_WORKLOADS; do
	echo Warmup background workload: $WORKLOAD
	cd $SHELLPACK_TOPLEVEL
	./bin/run-single-test.sh $WORKLOAD > /dev/null &
	WORKLOAD_PID=$!

	MEMUSED_BYTES=`free -b | grep Mem: | awk '{print $3}'`
	LAST_USED=0
	WARMUP_START=`date +%s`
	MINIMUM_WARMUP=120
	ORIGINAL_DURATION=$MEMCACHETEST_DURATION
	export MEMCACHETEST_DURATION=$((MEMCACHETEST_DURATION*2+MINIMUM_WARMUP))

	WARMUP_COUNT=1
	MAX_MEMUSED=0

	sleep $MINIMUM_WARMUP
	while [ $WARMUP_COUNT -lt 10 ]; do
		MEMUSED_MB=$((MEMUSED_BYTES/1048576))
		echo -n "o usage: $MEMUSED_MB MB"

		THIS_MEMUSED=$((MEMUSED_BYTES/1048576/1000))
		if [ $THIS_MEMUSED -gt $MAX_MEMUSED ]; then
			echo " new peak"
			MAX_MEMUSED=$THIS_MEMUSED
			WARMUP_COUNT=1
		else
			echo
			WARMUP_COUNT=$((WARMUP_COUNT+1))
		fi
		sleep 3
		MEMUSED_BYTES=`free -b | grep Mem: | awk '{print $3}'`
		if [ "`ps h --pid $WORKLOAD_PID`" = "" ]; then
			die Workload exited before warmup completed
		fi
	done
	sleep 5
	WARMUP_END=`date +%s`
	WARMUP_DURATION=$((WARMUP_END-WARMUP_START))
	export MEMCACHETEST_DURATION=$((ORIGINAL_DURATION+WARMUP_DURATION))
	echo Waiting on process to exit
	wait $WORKLOAD_PID

	rm -rf $SHELLPACK_LOG/$WORKLOAD
	rm -rf $SHELLPACK_DATA/*

done

# Run one test for ever size of parallel IO
for IO_STEP in `seq 0 $PARALLELIO_INCREMENTS`; do
	mmtests_activity io-step $IO_STEP
	if [ $IO_STEP -eq 0 ]; then
		IO_SIZE=0
	else
		IOSIZE_RANGE=$((PARALLELIO_MAX_IOSIZE-PARALLELIO_MIN_IOSIZE))
		IOSTEP_FACTOR=$((IO_STEP-1))
		# Use this value to get dense testing of smaller values
		#IO_SIZE=$((PARALLELIO_MIN_IOSIZE+($IOSTEP_FACTOR*$IOSTEP_FACTOR)*$PARALLELIO_MAX_IOSIZE/($PARALLELIO_INCREMENTS*$PARALLELIO_INCREMENTS)))

		# Evenly spaced increments
		IO_SIZE=$((PARALLELIO_MIN_IOSIZE+IOSTEP_FACTOR*(IOSIZE_RANGE/$PARALLELIO_INCREMENTS)))
	fi

	# Cycle through each of the requested workloads
	for WORKLOAD in $PARALLELIO_WORKLOADS; do
	monitor_pre_hook $LOGDIR_RESULTS $WORKLOAD-$IO_STEP
	###SHELLPACK iteration_begin $PARALLELIO_ITERATIONS
		echo Starting $WORKLOAD iteration $ITERATION
		cd $SHELLPACK_TOPLEVEL
		mkdir -p $LOGDIR_RESULTS

		# Record vmstat at start of test
		echo start: `date +%s` >  $LOGDIR_RESULTS/vmstat-$WORKLOAD-$IO_STEP-$ITERATION.log
		cat /proc/vmstat       >> $LOGDIR_RESULTS/vmstat-$WORKLOAD-$IO_STEP-$ITERATION.log

		echo Starting background workload: $WORKLOAD
		STARTTIME_WORKLOAD=`date +%s`
		./bin/run-single-test.sh $WORKLOAD > $LOGDIR_RESULTS/workload-$WORKLOAD-$IO_STEP-$ITERATION.log 2>&1 &
		WORKLOAD_PID=$!

		# Wait until workload reaches its peak size for 10 seconds
		echo Waiting $WARMUP_DURATION seconds for workload to warm up
		COUNT=0
		for i in `seq 1 $((WARMUP_DURATION/5))`; do
			MEMUSED_BYTES=`free -b | grep Mem: | awk '{print $3}'`
			MEMUSED_MB=$((MEMUSED_BYTES/1048576))
			echo "o usage: $MEMUSED_MB MB"
			sleep 5
			if [ "`ps h --pid $WORKLOAD_PID`" = "" ]; then
				die Workload exited before warmup completed
			fi
		done
		sleep 5
		WARMUP_DURATION=$((WARMUP_END-WARMUP_START))
		MEMUSED_BYTES=`free -b | grep Mem: | awk '{print $3}'`
		MEMUSED_MB=$((MEMUSED_BYTES/1048576))
		WARNING=
		echo $IO_STEP $IO_SIZE $ITERATION $WARMUP_DURATION $MEMUSED_MB $WARNING >> $LOGDIR_RESULTS/io-warmups.log

		# While workload is running, run parallel IO workload
		echo Starting parallel io: $PARALLELIO_IOLOAD $IO_SIZE
		STARTTIME_IO=`date +%s`
		if [ $IO_SIZE -gt 0 ]; then
			case $PARALLELIO_IOLOAD in
			dd)
				mkdir -p $SHELLPACK_DATA
				dd if=/dev/zero of=$SHELLPACK_DATA/largefile \
					bs=1M count=$((IO_SIZE/1048576)) \
					conv=fdatasync \
					> $LOGDIR_RESULTS/io-$IO_STEP-$ITERATION.log 2>&1
				if [ $? -ne 0 ]; then
					error DD Failed
					cat $LOGDIR_RESULTS/io-log-$IO_STEP-$ITERATION.log
					echo Waiting on $WORKLOAD $pid $WORKLOAD_PID to complete
					wait $WORKLOAD_PID
					die IO workload failed
				fi
				;;
			*)
				die Unrecognised parallel IO workload
			esac
		fi
		ENDTIME_IO=`date +%s`

		# Record the time it took to complete the IO
		DURATION=$((ENDTIME_IO-STARTTIME_IO))
		echo $IO_STEP $IO_SIZE $ITERATION $DURATION >> $LOGDIR_RESULTS/io-durations.log

		echo Waiting on $WORKLOAD pid $WORKLOAD_PID to complete
		wait $WORKLOAD_PID
		RETVAL=$?
		if [ $RETVAL -ne 0 ]; then
			error Background workload $WORKLOAD failed
			cat $LOGDIR_RESULTS/workload-$WORKLOAD.log
			die Aborting due to backgrounworkload failure
		fi

		ENDTIME_WORKLOAD=`date +%s`

		# Record vmstat at end of test
		echo end: `date +%s`   >> $LOGDIR_RESULTS/vmstat-$WORKLOAD-$IO_STEP-$ITERATION.log
		cat /proc/vmstat       >> $LOGDIR_RESULTS/vmstat-$WORKLOAD-$IO_STEP-$ITERATION.log

		# Record how long the workload took to complete
		echo $WORKLOAD $IO_STEP $ITERATION $((ENDTIME_WORKLOAD-STARTTIME_WORKLOAD)) >> $LOGDIR_RESULTS/workload-durations.log

		# Collect the data from the target workload and cleanup
		gzip $LOGDIR_RESULTS/workload-$WORKLOAD-$IO_STEP-$ITERATION.log
		mv $SHELLPACK_LOG/$WORKLOAD $LOGDIR_RESULTS/$WORKLOAD-$IO_STEP-$ITERATION
		rm -rf $SHELLPACK_DATA/*
	###SHELLPACK iteration_end
	monitor_post_hook $LOGDIR_RESULTS $WORKLOAD-$IO_STEP
	done
done

rm -rf $SHELLPACK_DATA
exit $SHELLPACK_SUCCESS
