#!/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

# Warmup runs
for WORKLOAD in $PARALLELIO_WORKLOADS; do
	echo Warmup background workload: $WORKLOAD
	cd $SHELLPACK_TOPLEVEL
	./run-single-test.sh $WORKLOAD || die Failed to run warmup of $WORKLOAD
	rm -rf $SHELLPACK_LOG/$WORKLOAD
	rm -rf $TESTDISK_DIR/*
done

# Run one test for ever size of parallel IO
for IO_STEP in `seq 0 $PARALLELIO_INCREMENTS`; do
	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
	for ITERATION in `seq 1 $PARALLELIO_ITERATIONS`; do
	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`
		./run-single-test.sh $WORKLOAD > $LOGDIR_RESULTS/workload-$WORKLOAD-$IO_STEP-$ITERATION.log 2>&1 &
		WORKLOAD_PID=$!

		# Wait until workload reaches 80% of the target size
		WARMUP_WORKLOAD_SIZE=$((PARALLELIO_TARGETLOAD_SIZE*8/10))
		echo Waiting for workload to warm up to $((WARMUP_WORKLOAD_SIZE/1048576)) MB
		MAXIMUM_WARMUP_TIME=$((PARALLELIO_WORKLOAD_DURATION/3))
		MEMUSED_BYTES=`free -b | grep Mem: | awk '{print $3}'`
		LAST_USED=0
		WARMUP_START=`date +%s`
		while [ $MEMUSED_BYTES -lt $WARMUP_WORKLOAD_SIZE ]; do
			MEMUSED_MB=$((MEMUSED_BYTES/1048576))
			if [ $LAST_USED -ne $MEMUSED_MB ]; then
				echo o usage: $MEMUSED_MB MB
				LAST_USED=$((MEMUSED_MB))
			fi
			sleep 2
			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))
		MEMUSED_BYTES=`free -b | grep Mem: | awk '{print $3}'`
		MEMUSED_MB=$((MEMUSED_BYTES/1048576))
		WARNING=
		echo Warmup time: $WARMUP_DURATION seconds, $MEMUSED_MB MB
		if [ $WARMUP_DURATION -gt $MAXIMUM_WARMUP_TIME ]; then
			warn Warmup duration longer than desired time of $MAXIMUM_WARMUP_TIME
			WARNING="WARNING:$WARMUP_DURATION:$MAXIMUM_WARMUP_TIME"
		fi
		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 $TESTDISK_DIR
				dd if=/dev/zero of=$TESTDISK_DIR/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
		mv $SHELLPACK_LOG/$WORKLOAD $LOGDIR_RESULTS/$WORKLOAD-$IO_STEP-$ITERATION
		rm -rf $TESTDISK_DIR/*
	done
	monitor_post_hook $LOGDIR_RESULTS $WORKLOAD-$IO_STEP
	done
done

rm -rf $TESTDISK_DIR
exit $SHELLPACK_SUCCESS
