#!/bin/bash
P=pgbench-bench
DEFAULT_VERSION=9.6.1
. $SHELLPACK_INCLUDE/common.sh
TIME_CMD=`which time`
if [ "$TIME_CMD" = "" ]; then
        TIMEFORMAT="%2Uuser %2Ssystem %Relapsed %P%%CPU"
        TIME_CMD="time"
fi
install-depends gnuplot

ROLE=`whoami`
DBUSER=nobody
EFFECTIVE_CACHESIZE=$((756*1048576))
SHARED_BUFFERS=$((32*1048576))
WORK_MEM=$((32*1048576))
MAX_TIME=
MAX_TRANSACTIONS=
READONLY_ARG=
SCALE_FACTOR=1
VACUUM_ARG=-n
RUN_CACHE_COLD=no
MIN_THREADS=1

. $SHELLPACK_INCLUDE/deferred-monitors.sh

# Basic argument parser
TASKSET_SERVER=
TASKSET_CLIENT=
SERVERSIDE_COMMAND=none
SERVERSIDE_NAME=`date +%Y%m%d-%H%M-%S`

while [ "$1" != "" ]; do
	case "$1" in
	-v)
		VERSION=$2
		shift 2
		;;
	--serverside-command)
		SERVERSIDE_COMMAND=$2
		shift 2
		;;
	--serverside-name)
		SERVERSIDE_NAME=$2
		shift 2
		;;
	--install-only)
		INSTALL_ONLY=yes
		shift
		;;
	--install-force)
		INSTALL_FORCE=yes
		shift
		;;
	--effective-cachesize)
		EFFECTIVE_CACHESIZE=$2
		shift 2
		;;
	--shared-buffers)
		SHARED_BUFFERS=$2
		shift 2
		;;
	--work-mem)
		WORK_MEM=$2
		shift 2
		;;

	--min-threads)
		MIN_THREADS=$2
		shift 2
		;;
	--max-threads)
		MAX_THREADS=$2
		shift 2
		;;
	--scale-factor)
		SCALE_FACTOR=$2
		shift 2
		;;
	--max-time)
		MAX_TIME=$2
		shift 2
		;;
	--max-transactions)
		MAX_TRANSACTIONS=$2
		shift 2
		;;
	--read-only)
		READONLY=yes
		shift
		;;
	--cache-cold)
		RUN_CACHE_COLD=yes
		shift
		;;
	*)
		echo Unrecognised option: $1
		shift
	esac
done
if [ "$TASKSET_SERVER" != "" ]; then
	echo TASKSET_SERVER: $TASKSET_SERVER
	echo TASKSET_CLIENT: $TASKSET_CLIENT
fi
if [ -z "$VERSION" ]; then
	VERSION=$DEFAULT_VERSION
fi

# Include monitor hooks
. $SHELLPACK_INCLUDE/include-monitor.sh

# Always scrub sources as the benchmark in question does not properly
# reinitialise itself if the data partitions gets scrubbed
if [ "$INSTALL_ONLY" = "yes" ]; then
	rm -rf $SHELLPACK_SOURCES/postgres*
fi

echo Copying database configuration
cp $SHELLPACK_DATA/pgdata/postgresql.conf $LOGDIR_RESULTS
export PGHOST=127.0.0.1
export PGPORT=5432
export PATH=$SHELLPACK_SOURCES/postgresbuild-${VERSION}-installed/bin:$PATH
export LD_LIBRARY_PATH=$SHELLPACK_SOURCES/postgresbuild-${VERSION}-installed/lib
PSQL=$SHELLPACK_SOURCES/postgresbuild-${VERSION}-installed/bin/psql
RUNDBUSER="su -s /bin/bash $DBUSER -c"

MID=$(((MEMTOTAL_BYTES-EFFECTIVE_CACHESIZE-SHARED_BUFFERS)/2))
if [ $MID -lt 0 ]; then
	MID=0
fi

if [ "$MAX_TRANSACTIONS" = "auto" ]; then
	if [ "$READONLY" = "yes" ]; then
		CEILING=20000000
		WEIGHT_MAINMEMORY=2
		WEIGHT_DISK=600
	else
		CEILING=2000000
		WEIGHT_MAINMEMORY=2
		WEIGHT_DISK=300
	fi
	FLOOR=15000
	WORKLOAD_SIZE=$((SCALE_FACTOR*15*1048576+30*1048576))
	cat > /tmp/points <<EOF
$SHARED_BUFFERS          $CEILING
$EFFECTIVE_CACHESIZE     $((CEILING/WEIGHT_MAINMEMORY))
$((EFFECTIVE_CACHESIZE+SHARED_BUFFERS))  $((CEILING/WEIGHT_MAINMEMORY/8))
$((MEMTOTAL_BYTES-MID))	 $((CEILING/WEIGHT_MAINMEMORY/32))
$MEMTOTAL_BYTES 	 $((CEILING/WEIGHT_MAINMEMORY/16))
$((MEMTOTAL_BYTES*3/2))  $((CEILING/WEIGHT_DISK*4))
$((MEMTOTAL_BYTES*3)) $((CEILING/WEIGHT_DISK))
$((MEMTOTAL_BYTES*4)) $((CEILING/WEIGHT_DISK*48))
$((MEMTOTAL_BYTES*8)) $((CEILING/WEIGHT_DISK*96))
EOF

	cat > /tmp/gnuplot.script <<EOF
set terminal dumb
set table "/tmp/coordinates"
plot '/tmp/points' smooth cspline
EOF
	cat /tmp/gnuplot.script | gnuplot > /dev/null

        MAX_TRANSACTIONS=`awk "{ if (\\$1 >= \$WORKLOAD_SIZE) print \\$2 }" /tmp/coordinates | head -1`
	MAX_TRANSACTIONS=`perl -e "print int $MAX_TRANSACTIONS"`
	if [ "$MAX_TRANSACTIONS" = "" ]; then
		MAX_TRANSACTIONS=$FLOOR
	fi
	if [ $MAX_TRANSACTIONS -lt $FLOOR ]; then
		MAX_TRANSACTIONS=$FLOOR
	fi
	mv /tmp/points $LOGDIR_RESULTS/pgbench-auto-points
	mv /tmp/coordinates $LOGDIR_RESULTS/pgbench-auto-coordinates
fi

if [ "$PGBENCH_DEBUG_AUTO_TRANSACTIONS" = "yes" ]; then
	cat $LOGDIR_RESULTS/pgbench-auto-points
	echo MAX_TRANSACTIONS = $MAX_TRANSACTIONS
	exit $SHELLPACK_SUCCESS
fi

if [ "$READONLY" = "yes" ]; then
	READONLY_ARG=-S
fi

if [ "$INSTALL_ONLY" = "yes" ]; then
	echo Starting database for first time as part of init
	$SHELLPACK_INCLUDE/shellpack-bench-postgresbuild --start \
		--effective_cachesize $EFFECTIVE_CACHESIZE \
		--shared_buffers $SHARED_BUFFERS \
		--work_mem $WORK_MEM \
		-v ${VERSION} || die Failed to get a usable postgres installation

	echo Stopping database to finish init
	$SHELLPACK_INCLUDE/shellpack-bench-postgresbuild --stop

	echo pgbench installed only as requested
	exit $SHELLPACK_SUCCESS
fi

echo Running pgbench
echo o maximum $MAX_THREADS threads
echo o scale factor: $SCALE_FACTOR 
echo $SCALE_FACTOR > $LOGDIR_RESULTS/pgbench-scale
LAST_THREAD=0

FIRST_TIME=yes

THREADS=
START_THREAD=$MIN_THREADS
END_THREAD=$MAX_THREADS
if [ $END_THREAD -ge 32 ]; then
	THREADS=`seq $START_THREAD 4 8`
	THREADS="$THREADS `seq 12 9 32`"
	THREADS="$THREADS `seq 48 31 $END_THREAD`"
elif [ $END_THREAD -ge 8 ]; then
	THREADS=`seq $START_THREAD 3 8`
	THREADS="$THREADS `seq 12 6 $END_THREAD`"
else
	THREADS=`seq $START_THREAD 2 $END_THREAD`
fi
if [ `echo $THREADS | awk '{print $NF}'` -ne $END_THREAD ]; then
	THREADS="$THREADS $END_THREAD"
fi
for NR_THREADS in $THREADS; do
	if [ $NR_THREADS -lt $MIN_THREADS ]; then
		continue
	fi
	mmtests_activity process $NR_THREADS/$END_THREAD
	# Do not repeat iterations due to thread count
	if [ $NR_THREADS -eq $LAST_THREAD ]; then
		continue
	fi

	PGBENCH_THREADS=$NUMNODES
	if [ $NR_THREADS -lt $NUMNODES ]; then
		PGBENCH_THREADS=1
	else
		NR_THREADS=$(((NR_THREADS+NUMNODES-1)&~(NUMNODES-1)))
	fi
	LAST_THREAD=$NR_THREADS

	if [ "$DATABASE_INIT_ONCE" != "yes" -o "$FIRST_TIME" = "yes" ]; then
		echo Starting database for initialisation
		mmtests_activity database-init
		$SHELLPACK_INCLUDE/shellpack-bench-postgresbuild --start \
			--effective_cachesize $EFFECTIVE_CACHESIZE \
			--shared_buffers $SHARED_BUFFERS \
			--work_mem $WORK_MEM \
			-v ${VERSION} || die Failed to get a usable postgres installation

		echo Preparing database
		$RUNDBUSER "$PSQL template1 -c 'DROP DATABASE pgbench;'"
		$RUNDBUSER "$PSQL template1 -c 'DROP ROLE $ROLE;'"
		$RUNDBUSER "$PSQL template1 -c 'CREATE DATABASE pgbench;'" || die Failed to setup database
		$RUNDBUSER "$PSQL template1 -c 'CREATE ROLE $ROLE with LOGIN;'" || die Failed to create $ROLE role

		echo Initialising database for pgbench: Scale factor $SCALE_FACTOR
		$TIME_CMD -o $LOGDIR_RESULTS/load-${NR_THREADS}.time \
			pgbench -h $PGHOST -p $PGPORT \
				-i $VACUUM_ARG -s $SCALE_FACTOR pgbench \
				> $LOGDIR_RESULTS/load-${NR_THREADS}.log 2>&1
	fi

	if [ "$DATABASE_INIT_ONCE" = "yes" -a "$FIRST_TIME" = "yes" ]; then
		mmtests_activity database-warmup
		echo Warming up database for 30 minutes
		pgbench -v -h $PGHOST -p $PGPORT -r \
			$VACUUM_ARG $READONLY_ARG -c $MAX_THREADS -j $MAX_THREADS \
			-T $((60*30)) pgbench
	fi

	FIRST_TIME=no

	if [ "$RUN_CACHE_COLD" = "yes" ]; then
		echo Stopping database to drop cache
		$SHELLPACK_INCLUDE/shellpack-bench-postgresbuild --stop

		echo Dumping cache to run database cache cold as requested
		echo 3 > /proc/sys/vm/drop_caches

		# Starting database
		echo Starting database cache cold
		$SHELLPACK_INCLUDE/shellpack-bench-postgresbuild --start \
			--effective_cachesize $EFFECTIVE_CACHESIZE \
			--shared_buffers $SHARED_BUFFERS \
			--work_mem $WORK_MEM \
			-v ${VERSION} || die Failed to get a usable postgres installation
	fi

	# Work out max time or max transactions commands
	MAX_TIME_COMMAND=
	MAX_TRANSACTIONS_COMMAND=
	if [ "$MAX_TIME" != "" ]; then
		MAX_TIME_COMMAND="-T $MAX_TIME"
		echo $MAX_TIME > $LOGDIR_RESULTS/pgbench-time
	else
		if [ "$MAX_TRANSACTIONS" != "" ]; then
			MAX_TRANSACTIONS_COMMAND="-t $((MAX_TRANSACTIONS/NR_THREADS))"
		else
			die Specify time or transactions
		fi
		echo $((MAX_TRANSACTIONS/NR_THREADS)) > $LOGDIR_RESULTS/pgbench-nr-transactions-$NR_THREADS
	fi

	monitor_pre_hook $LOGDIR_RESULTS $NR_THREADS
	mmtests_activity pgbench-$NR_THREADS
	echo o $NR_THREADS/$PGBENCH_MAX_THREADS threads $MAX_TRANSACTIONS transactions
	start_deferred_monitors "$NR_THREADS/$PGBENCH_MAX_THREADS threads $MAX_TRANSACTIONS transactions"
	$TIME_CMD -o $LOGDIR_RESULTS/time-${NR_THREADS} \
		pgbench -v -h $PGHOST -p $PGPORT -r \
			-l --aggregate-interval=1 \
			$VACUUM_ARG $READONLY_ARG -c $NR_THREADS -j $PGBENCH_THREADS \
			$MAX_TRANSACTIONS_COMMAND $MAX_TIME_COMMAND \
			pgbench > $LOGDIR_RESULTS/pgbench-raw-$NR_THREADS
	SYSRET=$?
	stop_deferred_monitors
	if [ $SYSRET -ne 0 ]; then
		cat $LOGDIR_RESULTS/pgbench-raw-$NR_THREADS
		die pgbench failed to execute
	fi
	COUNT=1
	for FILE in `ls pgbench_log.*`; do
		mv $FILE $LOGDIR_RESULTS/pgbench-transactions-$NR_THREADS-$COUNT
		COUNT=$((COUNT+1))
	done
	monitor_post_hook $LOGDIR_RESULTS $NR_THRADS
done

echo Cleaning up and shutting down
$RUNDBUSER "$PSQL template1 -c 'DROP DATABASE pgbench;'"
$RUNDBUSER "$PSQL template1 -c 'DROP ROLE $ROLE;'"
$SHELLPACK_INCLUDE/shellpack-bench-postgresbuild --stop
cp $SHELLPACK_SOURCES/postgresbuild-${VERSION}-installed/logfile $LOGDIR_RESULTS/dblog

echo pgbench successfully completed
exit $SHELLPACK_SUCCESS
#### Description Run the pgbench benchmark
#### Details pgbench-bench 165
