#!/bin/sh
# Send FIO statistics to perf server
pgm="${0##*/}"		# Program basename
progdir="${0%/*}"	# Program directory

usage()
{
	cat <<EOF
Description:

This is a set of scripts for testing I/O disk subsystem using the FIO utility. 
The scripts have several profiles (easily extensible) and you can adjust some parameters. 
The final result is printed on the screen and can be sent to an external resource.

Can work both interactively and fully automatically (unattended mode).

Options/Environments for unattended:

FIO_AUTO_PROFILE - select profile for test (can be multiple, use ',' for delimer):
  'randread'  - random READ;
  'randrw'    - (mixed): random READ/WRITE(mixer). FIO_AUTO_RWMIXREAD can be used (default: 50);
  'randwrite' - random WRITE;
  'read'      - sequential READ;
  'rw'        - (mixer): sequential READ/WRITE. FIO_AUTO_RWMIXREAD can be used (default: 50);
  'write'     - sequential WRITE.
FIO_AUTO_RWMIXREAD - balance between read and write, default: 50;
                     FIO_AUTO_RWMIXREAD=30  would mean that 30% of the I/O will be READs and 70% will be WRITEs;
FIO_AUTO_POST      - post statistic to external SpaceVM-perf service. FIO_CHECKIN_SERVER can be used:
  '1' - to send statistics (by default);
  '0' - to skip;
FIO_CHECKIN_SERVER - override destination server for post statistics. Default: inherits ISO source site;
FIO_AUTO_BS        - change 'fio' BS settings. Default: '4k';
FIO_AUTO_DEPTH     - change 'fio' DEPTH settings;
FIO_AUTO_JOBS      - change 'fio' JOBS settings;

Example:

env FIO_AUTO_POST=0 FIO_AUTO_PROFILE=read spacevm-perf-fio-run
env FIO_AUTO_PROFILE=rw,randrw FIO_AUTO_RWMIXREAD=30 spacevm-perf-fio-run
env CHECKIN_SERVER=https://perf.example.local spacevm-perf-fio-run

EOF
}

while getopts "h" opt; do
	case "${opt}" in
		h)
			usage
			exit 0
			;;
	esac
	shift $(($OPTIND - 1))
done

if [ -n "${DESTROY_DISK_DATA}" ]; then
	DESTROY_DISK_DATA="${DESTROY_DISK_DATA}"
else
	DESTROY_DISK_DATA=0
fi
CBSD_PERF_DISTRO=0

[ -r /etc/rc.conf ] && . /etc/rc.conf

# options
#
export PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin"
CURR_VERSION="0.1"
USE_TOR=NO
DO_LOG_NET_TRAFFIC=1

set -e
. /usr/local/etc/spacevm-perf-fio.conf
. /usr/local/share/spacevm/fio-subr/color.subr
. /usr/local/share/spacevm/fio-subr/system.subr
. /usr/local/share/spacevm/fio-subr/network.subr
set +e

# main loop. can be overriden via subr/${OPSYS}.subr
fio_loop()
{
	local _auto_profile_env _auto_profile
	local _ret _all_profiles

	if [ -z "${FIO_AUTO_PROFILE}" ]; then
		_auto_profile_env=$( kenv mfsbsd.fio_auto_profile 2>/dev/null )
		_ret=$?
	else
		# get from env
		_auto_profile_env="${FIO_AUTO_PROFILE}"
		_ret=0
	fi

	# debug
	if [ ${_ret} -eq 0 -a -n "${_auto_profile_env}" ]; then
			case "${_auto_profile_env}" in
				all)
					echo "${CURL_CMD} -o /tmp/index.conf ${BENCH_INDEX_URL}"
					${CURL_CMD} -s -o /tmp/index.conf ${BENCH_INDEX_URL} > /tmp/curl.$$ 2>&1
					ret=$?

					trap "${RM_CMD} -f /tmp/curl.$$" HUP INT ABRT BUS TERM EXIT

					${CP_CMD} -a /tmp/curl.$$ /tmp/curl

					if [ ${ret} -ne 0 ]; then
						echo "curl error: ${ret}"
						${CAT_CMD} /tmp/curl.$$
						exit 1
					else
						echo "fetched config:"
						${CAT_CMD} /tmp/index.conf
						echo
					fi
					_all_profiles=$( ${CAT_CMD} /tmp/index.conf | ${CUT_CMD} -d : -f1 | ${TR_CMD} '\r\n' ' ' )
					;;
				*)
					_all_profiles="${_auto_profile_env}"
					;;
			esac
	fi

	if [ -n "${_all_profiles}" ]; then
		for i in ${_all_profiles}; do
			/usr/local/bin/spacevm-perf-fio-fioloop -t ${i} && /usr/local/bin/spacevm-perf-fio-send
		done
	else
		/usr/local/bin/spacevm-perf-fio-fioloop && /usr/local/bin/spacevm-perf-fio-send
	fi

	return 0
}

check_head_disk()
{
	local _res

	[ -z "${1}" ] && return 2

	${DD_CMD} if=${1} of=${tmpdir}/is_empty.$$ bs=256k count=1 > /dev/null 2>&1
	_res=$( ${STRINGS_CMD} ${tmpdir}/is_empty.$$ | ${WC_CMD} -w | ${AWK_CMD} {'printf $1'} )
	${RM_CMD} -f ${tmpdir}/is_empty.$$
	if [ "${_res}" = "0" ]; then
		return 0
	else
		return 1
	fi
}

## MAIN
init_color

${ECHO} "${N1_COLOR}OS: ${N2_COLOR}${OS}${N0_COLOR}"
${ECHO} "${N1_COLOR}OPSYS: ${N2_COLOR}${OPSYS}${N0_COLOR}"

select_disks()
{
	local clean_disk_num=1
	local clean_disk=
	local _kern_disks=$( /sbin/sysctl -qn kern.disks )
	local DISK_LIST=
	local _def_method=
	local _tmpdir=
	local _tmpfile=

	DISK_LIST=$( for i in ${_kern_disks}; do
		case "${i}" in
			acd[0-9]*|cd[0-9]*|scd[0-9]*) continue ;;
		esac
		echo "${i}"
	done | ${SORT_CMD} -u )

	_tmpdir=$( ${MKTEMP_CMD} -d )
	_tmpfile=$( ${MKTEMP_CMD} )

	for i in ${DISK_LIST}; do
		if [ "${DESTROY_DISK_DATA}" != "1" ]; then
			check_head_disk /dev/${i}
			_ret=$?
		else
			_ret=0
		fi

		case "${_ret}" in
			0)
				status="${clean_disk_num} - ${N2_COLOR}${i} ${H2_COLOR}[clean]${N0_COLOR}"
				export clean_disk_name${clean_disk_num}="/dev/${i}"
				[ ${clean_disk_num} -eq 1 ] && _def_method="${i}"
				dsk_info ${i}

				conv2human ${BSIZE}
				SIZE="${human_val}"

				echo "0:${i}:" >> ${_tmpdir}/${i}.item
				${ECHO} "${H3_COLOR}${DSK_INFO}, Size: ${SIZE}${N0_COLOR}" > ${_tmpdir}/${i}.descr

				if [ -z "${clean_disk}" ]; then
					clean_disk="/dev/${i}"
				else
					clean_disk="${clean_disk} /dev/${i}"
				fi
				clean_disk_num=$(( clean_disk_num + 1 ))
				;;
			1)
				dsk_info ${i}
				conv2human ${BSIZE}
				SIZE="${human_val}"

				status="  - ${H2_COLOR}${i} [${DSK_INFO}, Size: ${SIZE} - DIRTY] (needs env DESTROY_DISK_DATA=1 to use this disk) ${N0_COLOR}"
				;;
		esac
		${ECHO} "${status}"
	done

	if [ -z "${clean_disk}" ]; then
		${ECHO} "No clean disk found, please add/use empty disk!"
		[ -n "${DISK_LIST}" ] && ${ECHO} "Or re-run '${pgm}' scrript with DESTROY_DISK_DATA=1 env, e.g.: ${N2_COLOR}env DESTROY_DISK_DATA=1 ${pgm}${N0_COLOR} (Destroy the disk data for I/O perf test)"
		exit 0
	fi

	SELECTED_DISK=

	if [ ${clean_disk_num} -eq 1 ]; then
		#eval _val="\$clean_disk_name$i"
		eval _val="\$clean_disk_name0"
		SELECTED_DISK="${_val}"
		return 0
	fi

	clean_disk_num=$(( clean_disk_num - 1 ))

	local subject="Select base sources:"
	${ECHO} "${N1_COLOR}${subject}${N0_COLOR}"

	#/usr/local/bin/spacevm-perf-fio-run ${_tmpdir} ${_tmpfile} item ${_def_method}
	/usr/local/bin/spacevm-select-item ${_tmpdir} ${_tmpfile} item ${_def_method} 2>/dev/null
	_ret=$?
	${RM_CMD} -rf ${_tmpdir}

	if [ ${_ret} -ne 0 ]; then
		# break or cancel
		choose="0"
	fi
	SELECTED_DISK=$( ${CAT_CMD} ${_tmpfile} )
	SELECTED_DISK="/dev/${SELECTED_DISK}"
	${RM_CMD} ${_tmpfile}

#	echo "Choose: 1-${clean_disk_num}, 0 to cancel"
#	choose=$( while [ true ]; do
#		read p;
#		case ${p} in
#			[0-${clean_disk_num}])
#				echo "${p}"
#				exit 0
#				;;
#			*)
#				continue
#				;;
#		esac
#	done )

	if [ "${choose}" = "0" ]; then
		exit 0
	fi
#	eval _val="\$clean_disk_name${choose}"
#	SELECTED_DISK="${_val}"
}

if [ "${CBSD_PERF_DISTRO}" = "1" ]; then
	${ECHO} "${N1_COLOR}Disks found:${N0_COLOR}"
	select_disks
	if [ ! -e "${SELECTED_DISK}" ]; then
		echo "no such ${SELECTED_DISK}"
		exit 1
	fi
	echo "SELECTED ${SELECTED_DISK}"
	sysrc -qf /etc/rc.conf FIO_SELECTED_DISK="${SELECTED_DISK}"
fi


# network setup
setup_proxies

${ECHO} "${N1_COLOR}Checkin server: ${N2_COLOR}${checkin_server}${N0_COLOR}"
url="${checkin_server}"

test_connection
_ret=$?

if [ ${_ret} -ne 0 ]; then
	${ECHO} "${N1_COLOR}Connection failed, please try lates: ${N2_COLOR}${checkin_server}${N0_COLOR}"
	exit 0
fi

log "INIT" "Connected to ${checkin_server_description}"

if [ -r "/usr/local/share/spacevm/fio-subr/${OPSYS}.subr" ]; then
	. "/usr/local/share/spacevm/fio-subr/${OPSYS}.subr"
	${ECHO} "${N1_COLOR}Found extra helper for ${OPSYS}: ${N2_COLOR}/usr/local/share/spacevm/fio-subr/${OPSYS}.subr${N0_COLOR}"
fi

fio_loop
ret=$?

${ECHO} "${N2_COLOR}Please type for re-run: ${N2_COLOR}/usr/local/bin/spacevm-perf-fio-run${N0_COLOR}"

exit ${ret}
