#!/bin/sh -e
# NAME=HDD benchmark: Bonnie
# DESCRIPTION=This test uses bonnie++ benchmark to test hard drives performance on different filesystems. For every hard drive in a system, test sequently creates specified filesystems on it and then runs bonnie++ benchmark itself. There are two sections to the program’s operations. The first is to test the IO throughput in a fashion that is designed to simulate some types of database applications. The  second is to test creation, reading, and deleting many small files in a fashion similar to the usage patterns of programs such as Squid or INN. Bonnie++ tests some of them and for each test gives a result of the amount of work done per second and the percentage of CPU time this took. This test uses unstable Bonnie++ 1.9x version.
# DESTROYS_HDD=true
# POWEROFF_DURING_TEST=false
# VERSION=0.2
# TAGS=benchmark,hdd,filesystem
# DEPENDS=HDD
# VAR=FILESYSTEMS:string:ext2 ext3 vfat reiserfs xfs:Space-separated list of filesystems to be benchmarked
# VAR=NUMBER_OF_FILES:int:2:The number of files for the file creation test. This is measured in multiples of 1024 files
# VAR=MINIMAL_FILE_SIZE:int:10:Minimal files size, KiB
# VAR=MAXIMAL_FILE_SIZE:int:1024:Maximal files size, KiB
# VAR=DIRECTORIES_NUMBER:int:256:Number of directories to randomly distribute test files among them

. _inq-config-global; . $SHARE_DIR/functions-test

exit_handler()
{
	[ -f "$RESULT_FILE" ] && rm -fr "$RESULT_FILE"
	if [ -d "$SCRATCH_DIRECTORY" ]; then
		umount -f $SCRATCH_DIRECTORY >$DEBUG_TTY 2>&1 || true
		rmdir $SCRATCH_DIRECTORY
	fi
}

RESULT_FILE=`mktemp`
SCRATCH_DIRECTORY=`mktemp -d`
STAGES_QUANTITY=$(( `c=0; for i in $FILESYSTEMS; do c=$(( $c + 1)); done; echo $c` * `get_hdds_list | wc -l`))

perform_benchmark()
{
	local drive=$1

	for fs in $FILESYSTEMS; do
		benchmark_drive "$drive" "$fs"
	done
}

benchmark_drive()
{
	local drive=$1
	local filesystem=$2

	# We have to use -f/--force/-F options to force filesystem
	# creation on a partition that already contains one. As a rule
	# this flags are used.
	echo -n "Preparing $filesystem filesystem on $drive drive..."
	mkfs.$filesystem -F $drive >$DEBUG_TTY 2>&1 ||
	mkfs.$filesystem -f $drive >$DEBUG_TTY 2>&1 ||
	mkfs.$filesystem --force $drive >$DEBUG_TTY 2>&1 ||
	mkfs.$filesystem $drive >$DEBUG_TTY 2>&1 || test_failed 'Filesystem creation failed'

	mount $drive $SCRATCH_DIRECTORY
	echo_success

	echo -n "Performing benchmark..."
	TOTAL_TEST_FILES_SIZE=$(( `echo $MAXIMAL_FILE_SIZE | sed -n 's/^\([0-9]*\).$/\1/p'` * $NUMBER_OF_FILES ))
	bonnie++ -u root -r 0 -d $SCRATCH_DIRECTORY -s $TOTAL_TEST_FILES_SIZE \
		-n $NUMBER_OF_FILES:$MAXIMAL_FILE_SIZE:$MINIMAL_FILE_SIZE:$DIRECTORIES_NUMBER \
		-m benchmark 2>&1 | tee $RESULT_FILE >$DEBUG_TTY
	echo_success
	
	# Example CSV output
	# 1.93c,1.93c,smatveev,1,1218007303,200M,,517,99,56805,13,35644,9,1220,
	# 99,+++++,+++,6683,57,1,1048576,,,256,53,7,1268,61,+++++,+++,44,5,294,
	# 14,271,0,24479us,34686us,58995us,16505us,342us,141ms,847ms,2292us,
	# 273ms,776ms,78187us,823ms

	benchmark_submit_float "Drive: $drive FS: $filesystem Write char speed" `sed -n '$p' < $RESULT_FILE | awk -F, '{print $8}'` "KiB/sec"
	benchmark_submit_float "Drive: $drive FS: $filesystem Write char CPU load" `sed -n '$p' < $RESULT_FILE | awk -F, '{print $9}'` "%"
	benchmark_submit_float "Drive: $drive FS: $filesystem Write char latency" \
		`sed -n '$p' < $RESULT_FILE | awk -F, '{print $37}' | sed 's/^\([0-9]*\)\([a-z]*\)$/\1/g'` \
		`sed -n '$p' < $RESULT_FILE | awk -F, '{print $37}' | sed 's/^\([0-9]*\)\([a-z]*\)$/\2/g'`

	benchmark_submit_float "Drive: $drive FS: $filesystem Write block speed" `sed -n '$p' < $RESULT_FILE | awk -F, '{print $10}'` "KiB/sec"
	benchmark_submit_float "Drive: $drive FS: $filesystem Write block CPU load" `sed -n '$p' < $RESULT_FILE | awk -F, '{print $11}'` "%"
	benchmark_submit_float "Drive: $drive FS: $filesystem Write block latency" \
		`sed -n '$p' < $RESULT_FILE | awk -F, '{print $38}' | sed 's/^\([0-9]*\)\([a-z]*\)$/\1/g'` \
		`sed -n '$p' < $RESULT_FILE | awk -F, '{print $38}' | sed 's/^\([0-9]*\)\([a-z]*\)$/\2/g'`

	benchmark_submit_float "Drive: $drive FS: $filesystem Rewrite speed" `sed -n '$p' < $RESULT_FILE | awk -F, '{print $12}'` "KiB/sec"
	benchmark_submit_float "Drive: $drive FS: $filesystem Rewrite CPU load" `sed -n '$p' < $RESULT_FILE | awk -F, '{print $13}'` "%"
	benchmark_submit_float "Drive: $drive FS: $filesystem Rewrite latency" \
		`sed -n '$p' < $RESULT_FILE | awk -F, '{print $39}' | sed 's/^\([0-9]*\)\([a-z]*\)$/\1/g'` \
		`sed -n '$p' < $RESULT_FILE | awk -F, '{print $39}' | sed 's/^\([0-9]*\)\([a-z]*\)$/\2/g'`

	benchmark_submit_float "Drive: $drive FS: $filesystem Read char speed" `sed -n '$p' < $RESULT_FILE | awk -F, '{print $14}'` "KiB/sec"
	benchmark_submit_float "Drive: $drive FS: $filesystem Read char CPU load" `sed -n '$p' < $RESULT_FILE | awk -F, '{print $15}'` "%"
	benchmark_submit_float "Drive: $drive FS: $filesystem Read char latency" \
		`sed -n '$p' < $RESULT_FILE | awk -F, '{print $40}' | sed 's/^\([0-9]*\)\([a-z]*\)$/\1/g'` \
		`sed -n '$p' < $RESULT_FILE | awk -F, '{print $40}' | sed 's/^\([0-9]*\)\([a-z]*\)$/\2/g'`

	benchmark_submit_float "Drive: $drive FS: $filesystem Read block speed" `sed -n '$p' < $RESULT_FILE | awk -F, '{print $16}'` "KiB/sec"
	benchmark_submit_float "Drive: $drive FS: $filesystem Read block CPU load" `sed -n '$p' < $RESULT_FILE | awk -F, '{print $17}'` "%"
	benchmark_submit_float "Drive: $drive FS: $filesystem Read block latency" \
		`sed -n '$p' < $RESULT_FILE | awk -F, '{print $41}' | sed 's/^\([0-9]*\)\([a-z]*\)$/\1/g'` \
		`sed -n '$p' < $RESULT_FILE | awk -F, '{print $41}' | sed 's/^\([0-9]*\)\([a-z]*\)$/\2/g'`

	benchmark_submit_float "Drive: $drive FS: $filesystem Random seeks time" `sed -n '$p' < $RESULT_FILE | awk -F, '{print $18}'` "sec"
	benchmark_submit_float "Drive: $drive FS: $filesystem Random seeks CPU load" `sed -n '$p' < $RESULT_FILE | awk -F, '{print $19}'` "%"
	benchmark_submit_float "Drive: $drive FS: $filesystem Random seeks latency" \
		`sed -n '$p' < $RESULT_FILE | awk -F, '{print $42}' | sed 's/^\([0-9]*\)\([a-z]*\)$/\1/g'` \
		`sed -n '$p' < $RESULT_FILE | awk -F, '{print $42}' | sed 's/^\([0-9]*\)\([a-z]*\)$/\2/g'`

	benchmark_submit_float "Drive: $drive FS: $filesystem Sequential file create time" `sed -n '$p' < $RESULT_FILE | awk -F, '{print $25}'` "sec"
	benchmark_submit_float "Drive: $drive FS: $filesystem Sequential file create CPU load" `sed -n '$p' < $RESULT_FILE | awk -F, '{print $26}'` "%"
	benchmark_submit_float "Drive: $drive FS: $filesystem Sequential file create latency" \
		`sed -n '$p' < $RESULT_FILE | awk -F, '{print $43}' | sed 's/^\([0-9]*\)\([a-z]*\)$/\1/g'` \
		`sed -n '$p' < $RESULT_FILE | awk -F, '{print $43}' | sed 's/^\([0-9]*\)\([a-z]*\)$/\2/g'`

	benchmark_submit_float "Drive: $drive FS: $filesystem Sequential file read time" `sed -n '$p' < $RESULT_FILE | awk -F, '{print $27}'` "sec"
	benchmark_submit_float "Drive: $drive FS: $filesystem Sequential file read CPU load" `sed -n '$p' < $RESULT_FILE | awk -F, '{print $28}'` "%"
	benchmark_submit_float "Drive: $drive FS: $filesystem Sequential file read latency" \
		`sed -n '$p' < $RESULT_FILE | awk -F, '{print $44}' | sed 's/^\([0-9]*\)\([a-z]*\)$/\1/g'` \
		`sed -n '$p' < $RESULT_FILE | awk -F, '{print $44}' | sed 's/^\([0-9]*\)\([a-z]*\)$/\2/g'`

	benchmark_submit_float "Drive: $drive FS: $filesystem Sequential file delete time" `sed -n '$p' < $RESULT_FILE | awk -F, '{print $29}'` "sec"
	benchmark_submit_float "Drive: $drive FS: $filesystem Sequential file delete CPU load" `sed -n '$p' < $RESULT_FILE | awk -F, '{print $30}'` "%"
	benchmark_submit_float "Drive: $drive FS: $filesystem Sequential file delete latency" \
		`sed -n '$p' < $RESULT_FILE | awk -F, '{print $45}' | sed 's/^\([0-9]*\)\([a-z]*\)$/\1/g'` \
		`sed -n '$p' < $RESULT_FILE | awk -F, '{print $45}' | sed 's/^\([0-9]*\)\([a-z]*\)$/\2/g'`

	benchmark_submit_float "Drive: $drive FS: $filesystem Random file create time" `sed -n '$p' < $RESULT_FILE | awk -F, '{print $31}'` "sec"
	benchmark_submit_float "Drive: $drive FS: $filesystem Random file create CPU load" `sed -n '$p' < $RESULT_FILE | awk -F, '{print $32}'` "%"
	benchmark_submit_float "Drive: $drive FS: $filesystem Random file create latency" \
		`sed -n '$p' < $RESULT_FILE | awk -F, '{print $46}' | sed 's/^\([0-9]*\)\([a-z]*\)$/\1/g'` \
		`sed -n '$p' < $RESULT_FILE | awk -F, '{print $46}' | sed 's/^\([0-9]*\)\([a-z]*\)$/\2/g'`

	benchmark_submit_float "Drive: $drive FS: $filesystem Random file read time" `sed -n '$p' < $RESULT_FILE | awk -F, '{print $33}'` "sec"
	benchmark_submit_float "Drive: $drive FS: $filesystem Random file read CPU load" `sed -n '$p' < $RESULT_FILE | awk -F, '{print $34}'` "%"
	benchmark_submit_float "Drive: $drive FS: $filesystem Random file read latency" \
		`sed -n '$p' < $RESULT_FILE | awk -F, '{print $47}' | sed 's/^\([0-9]*\)\([a-z]*\)$/\1/g'` \
		`sed -n '$p' < $RESULT_FILE | awk -F, '{print $47}' | sed 's/^\([0-9]*\)\([a-z]*\)$/\2/g'`

	benchmark_submit_float "Drive: $drive FS: $filesystem Random file delete time" `sed -n '$p' < $RESULT_FILE | awk -F, '{print $35}'` "sec"
	benchmark_submit_float "Drive: $drive FS: $filesystem Random file delete CPU load" `sed -n '$p' < $RESULT_FILE | awk -F, '{print $36}'` "%"
	benchmark_submit_float "Drive: $drive FS: $filesystem Random file delete latency" \
		`sed -n '$p' < $RESULT_FILE | awk -F, '{print $48}' | sed 's/^\([0-9]*\)\([a-z]*\)$/\1/g'` \
		`sed -n '$p' < $RESULT_FILE | awk -F, '{print $48}' | sed 's/^\([0-9]*\)\([a-z]*\)$/\2/g'`

	umount $SCRATCH_DIRECTORY

	TESTED_QUANTITY=$(( $TESTED_QUANTITY + 1 ))
	test_progress $TESTED_QUANTITY $STAGES_QUANTITY
}

test_succeed_if_no hdds

TESTED_QUANTITY=0
for BLOCK_DEV in `get_hdds_list`; do
	perform_benchmark $BLOCK_DEV
done

test_succeeded
