#!/bin/bash
#
# Wrapper script for easily running a survey of zpios based tests
#

basedir="$(dirname $0)"

SCRIPT_COMMON=common.sh
if [ -f "${basedir}/${SCRIPT_COMMON}" ]; then
. "${basedir}/${SCRIPT_COMMON}"
else
echo "Missing helper script ${SCRIPT_COMMON}" && exit 1
fi

PROG=zpios-survey.sh

usage() {
cat << EOF
USAGE:
$0 [hvp] <-c config> <-t test>

DESCRIPTION:
        Helper script for easy zpios survey benchmarking.

OPTIONS:
        -h      Show this message
        -v      Verbose
        -p      Enable profiling
        -c      Zpool configuration
        -t      Zpios test
        -l      Zpios survey log

EOF
}

print_header() {
tee -a ${ZPIOS_SURVEY_LOG} << EOF

================================================================
Test: $1
EOF
}

# Baseline performance for an out of the box config with no manual tuning.
# Ideally, we want everything to be automatically tuned for your system and
# for this to perform reasonably well.
zpios_survey_base() {
	TEST_NAME="${ZPOOL_CONFIG}+${ZPIOS_TEST}+baseline"
	print_header ${TEST_NAME}

	${ZFS_SH} ${VERBOSE_FLAG} | \
		tee -a ${ZPIOS_SURVEY_LOG}
	${ZPIOS_SH} ${VERBOSE_FLAG} -c ${ZPOOL_CONFIG} -t ${ZPIOS_TEST} | \
		tee -a ${ZPIOS_SURVEY_LOG}
	${ZFS_SH} -u ${VERBOSE_FLAG} | \
		tee -a ${ZPIOS_SURVEY_LOG}
}

# Disable ZFS's prefetching.  For some reason still not clear to me
# current prefetching policy is quite bad for a random workload.
# Allowing the algorithm to detect a random workload and not do 
# anything may be the way to address this issue.
zpios_survey_prefetch() {
	TEST_NAME="${ZPOOL_CONFIG}+${ZPIOS_TEST}+prefetch"
	print_header ${TEST_NAME}

	${ZFS_SH} ${VERBOSE_FLAG}               \
		tee -a ${ZPIOS_SURVEY_LOG}
	${ZPIOS_SH} ${VERBOSE_FLAG} -c ${ZPOOL_CONFIG} -t ${ZPIOS_TEST} \
		-o "--noprefetch" |                                    \
		tee -a ${ZPIOS_SURVEY_LOG}
	${ZFS_SH} -u ${VERBOSE_FLAG} | \
		tee -a ${ZPIOS_SURVEY_LOG}
}

# Simulating a zerocopy IO path should improve performance by freeing up
# lots of CPU which is wasted move data between buffers.
zpios_survey_zerocopy() {
	TEST_NAME="${ZPOOL_CONFIG}+${ZPIOS_TEST}+zerocopy"
	print_header ${TEST_NAME}

	${ZFS_SH} ${VERBOSE_FLAG} | \
		tee -a ${ZPIOS_SURVEY_LOG}
	${ZPIOS_SH} ${VERBOSE_FLAG} -c ${ZPOOL_CONFIG} -t ${ZPIOS_TEST} \
		-o "--zerocopy" |                                      \
		tee -a ${ZPIOS_SURVEY_LOG}
	${ZFS_SH} -u ${VERBOSE_FLAG} | \
		tee -a ${ZPIOS_SURVEY_LOG}
}

# Disabling checksumming should show some (if small) improvement
# simply due to freeing up a modest amount of CPU.
zpios_survey_checksum() {
	TEST_NAME="${ZPOOL_CONFIG}+${ZPIOS_TEST}+checksum"
	print_header ${TEST_NAME}

	${ZFS_SH} ${VERBOSE_FLAG} | \
		tee -a ${ZPIOS_SURVEY_LOG}
	${ZPIOS_SH} ${VERBOSE_FLAG} -c ${ZPOOL_CONFIG} -t ${ZPIOS_TEST} \
		-s "set checksum=off" |                                \
		tee -a ${ZPIOS_SURVEY_LOG}
	${ZFS_SH} -u ${VERBOSE_FLAG} | \
		tee -a ${ZPIOS_SURVEY_LOG}
}

# Increasing the pending IO depth also seems to improve things likely
# at the expense of latency.  This should be explored more because I'm
# seeing a much bigger impact there that I would have expected.  There
# may be some low hanging fruit to be found here.
zpios_survey_pending() {
	TEST_NAME="${ZPOOL_CONFIG}+${ZPIOS_TEST}+pending"
	print_header ${TEST_NAME}

	${ZFS_SH} ${VERBOSE_FLAG}                  \
		zfs="zfs_vdev_max_pending=1024" | \
		tee -a ${ZPIOS_SURVEY_LOG}
	${ZPIOS_SH} ${VERBOSE_FLAG} -c ${ZPOOL_CONFIG} -t ${ZPIOS_TEST} | \
		tee -a ${ZPIOS_SURVEY_LOG}
	${ZFS_SH} -u ${VERBOSE_FLAG} | \
		tee -a ${ZPIOS_SURVEY_LOG}
}

# To avoid memory fragmentation issues our slab implementation can be
# based on a virtual address space.  Interestingly, we take a pretty
# substantial performance penalty for this somewhere in the low level
# IO drivers.  If we back the slab with kmem pages we see far better
# read performance numbers at the cost of memory fragmention and general
# system instability due to large allocations.  This may be because of
# an optimization in the low level drivers due to the contigeous kmem
# based memory.  This needs to be explained.  The good news here is that
# with zerocopy interfaces added at the DMU layer we could gaurentee
# kmem based memory for a pool of pages.
#
# 0x100 = KMC_KMEM - Force kmem_* based slab
# 0x200 = KMC_VMEM - Force vmem_* based slab
zpios_survey_kmem() {
	TEST_NAME="${ZPOOL_CONFIG}+${ZPIOS_TEST}+kmem"
	print_header ${TEST_NAME}

	${ZFS_SH} ${VERBOSE_FLAG}             \  
		zfs="zio_bulk_flags=0x100" | \
		tee -a ${ZPIOS_SURVEY_LOG}
	${ZPIOS_SH} ${VERBOSE_FLAG} -c ${ZPOOL_CONFIG} -t ${ZPIOS_TEST} | \
		tee -a ${ZPIOS_SURVEY_LOG}
	${ZFS_SH} -u ${VERBOSE_FLAG} | \
		tee -a ${ZPIOS_SURVEY_LOG}
}

# Apply all possible turning concurrently to get a best case number
zpios_survey_all() {
	TEST_NAME="${ZPOOL_CONFIG}+${ZPIOS_TEST}+all"
	print_header ${TEST_NAME}

	${ZFS_SH} ${VERBOSE_FLAG}                \  
		zfs="zfs_vdev_max_pending=1024" \
		zfs="zio_bulk_flags=0x100" |    \
		tee -a ${ZPIOS_SURVEY_LOG}
	${ZPIOS_SH} ${VERBOSE_FLAG} -c ${ZPOOL_CONFIG} -t ${ZPIOS_TEST} \
		-o "--noprefetch --zerocopy"                           \
		-s "set checksum=off" |                                \
		tee -a ${ZPIOS_SURVEY_LOG}
	${ZFS_SH} -u ${VERBOSE_FLAG} | \
		tee -a ${ZPIOS_SURVEY_LOG}
}


PROFILE=
ZPOOL_NAME=zpios-survey
ZPOOL_CONFIG=zpool-config.sh
ZPIOS_TEST=zpios-test.sh
ZPIOS_SURVEY_LOG=/dev/null

while getopts 'hvpc:t:l:' OPTION; do
	case $OPTION in
	h)
		usage
		exit 1
		;;
	v)
		VERBOSE=1
		VERBOSE_FLAG="-v"
		;;
	p)
		PROFILE=1
		PROFILE_FLAG="-p"
		;;
	c)
		ZPOOL_CONFIG=${OPTARG}
		;;
	t)
		ZPIOS_TEST=${OPTARG}
		;;
	l)
		ZPIOS_SURVEY_LOG=${OPTARG}
		;;
	?)
		usage
		exit
		;;
	esac
done

if [ $(id -u) != 0 ]; then
	die "Must run as root"
fi

zpios_survey_base
zpios_survey_prefetch
zpios_survey_zerocopy
zpios_survey_checksum
zpios_survey_pending
zpios_survey_kmem
zpios_survey_all

exit 0
