perf-lib.sh 5.7 KB
Newer Older
1 2 3
# Performance testing framework.  Each perf script starts much like
# a normal test script, except it sources this library instead of
# test-lib.sh.  See t/perf/README for documentation.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
#
# Copyright (c) 2011 Thomas Rast
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see http://www.gnu.org/licenses/ .

# do the --tee work early; it otherwise confuses our careful
# GIT_BUILD_DIR mangling
case "$GIT_TEST_TEE_STARTED, $* " in
done,*)
	# do not redirect again
	;;
*' --tee '*|*' --va'*)
	mkdir -p test-results
	BASE=test-results/$(basename "$0" .sh)
	(GIT_TEST_TEE_STARTED=done ${SHELL-sh} "$0" "$@" 2>&1;
	 echo $? > $BASE.exit) | tee $BASE.out
	test "$(cat $BASE.exit)" = 0
	exit
	;;
esac

TEST_DIRECTORY=$(pwd)/..
TEST_OUTPUT_DIRECTORY=$(pwd)
if test -z "$GIT_TEST_INSTALLED"; then
	perf_results_prefix=
else
	perf_results_prefix=$(printf "%s" "${GIT_TEST_INSTALLED%/bin-wrappers}" | tr -c "[a-zA-Z0-9]" "[_*]")"."
	# make the tested dir absolute
	GIT_TEST_INSTALLED=$(cd "$GIT_TEST_INSTALLED" && pwd)
fi

TEST_NO_CREATE_REPO=t
47
TEST_NO_MALLOC_CHECK=t
48 49 50

. ../test-lib.sh

51 52 53 54
# Variables from test-lib that are normally internal to the tests; we
# need to export them for test_perf subshells
export TEST_DIRECTORY TRASH_DIRECTORY GIT_BUILD_DIR GIT_TEST_CMP

55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
perf_results_dir=$TEST_OUTPUT_DIRECTORY/test-results
mkdir -p "$perf_results_dir"
rm -f "$perf_results_dir"/$(basename "$0" .sh).subtests

if test -z "$GIT_PERF_REPEAT_COUNT"; then
	GIT_PERF_REPEAT_COUNT=3
fi
die_if_build_dir_not_repo () {
	if ! ( cd "$TEST_DIRECTORY/.." &&
		    git rev-parse --build-dir >/dev/null 2>&1 ); then
		error "No $1 defined, and your build directory is not a repo"
	fi
}

if test -z "$GIT_PERF_REPO"; then
	die_if_build_dir_not_repo '$GIT_PERF_REPO'
	GIT_PERF_REPO=$TEST_DIRECTORY/..
fi
if test -z "$GIT_PERF_LARGE_REPO"; then
	die_if_build_dir_not_repo '$GIT_PERF_LARGE_REPO'
	GIT_PERF_LARGE_REPO=$TEST_DIRECTORY/..
fi

test_perf_create_repo_from () {
	test "$#" = 2 ||
	error "bug in the test script: not 2 parameters to test-create-repo"
	repo="$1"
	source="$2"
	source_git=$source/$(cd "$source" && git rev-parse --git-dir)
	mkdir -p "$repo/.git"
	(
		cd "$repo/.git" &&
		{ cp -Rl "$source_git/objects" . 2>/dev/null ||
			cp -R "$source_git/objects" .; } &&
		for stuff in "$source_git"/*; do
			case "$stuff" in
				*/objects|*/hooks|*/config)
					;;
				*)
94
					cp -R "$stuff" . || exit 1
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
					;;
			esac
		done &&
		cd .. &&
		git init -q &&
		mv .git/hooks .git/hooks-disabled 2>/dev/null
	) || error "failed to copy repository '$source' to '$repo'"
}

# call at least one of these to establish an appropriately-sized repository
test_perf_default_repo () {
	test_perf_create_repo_from "${1:-$TRASH_DIRECTORY}" "$GIT_PERF_REPO"
}
test_perf_large_repo () {
	if test "$GIT_PERF_LARGE_REPO" = "$GIT_BUILD_DIR"; then
		echo "warning: \$GIT_PERF_LARGE_REPO is \$GIT_BUILD_DIR." >&2
		echo "warning: This will work, but may not be a sufficiently large repo" >&2
		echo "warning: for representative measurements." >&2
	fi
	test_perf_create_repo_from "${1:-$TRASH_DIRECTORY}" "$GIT_PERF_LARGE_REPO"
}
test_checkout_worktree () {
	git checkout-index -u -a ||
	error "git checkout-index failed"
}

# Performance tests should never fail.  If they do, stop immediately
immediate=t

test_run_perf_ () {
	test_cleanup=:
	test_export_="test_cleanup"
	export test_cleanup test_export_
	/usr/bin/time -f "%E %U %S" -o test_time.$i "$SHELL" -c '
129
. '"$TEST_DIRECTORY"/test-lib-functions.sh'
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
test_export () {
	[ $# != 0 ] || return 0
	test_export_="$test_export_\\|$1"
	shift
	test_export "$@"
}
'"$1"'
ret=$?
set | sed -n "s'"/'/'\\\\''/g"';s/^\\($test_export_\\)/export '"'&'"'/p" >test_vars
exit $ret' >&3 2>&4
	eval_ret=$?

	if test $eval_ret = 0 || test -n "$expecting_failure"
	then
		test_eval_ "$test_cleanup"
		. ./test_vars || error "failed to load updated environment"
	fi
	if test "$verbose" = "t" && test -n "$HARNESS_ACTIVE"; then
		echo ""
	fi
	return "$eval_ret"
}


test_perf () {
155
	test_start_
156 157 158 159 160 161 162 163 164 165
	test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
	test "$#" = 2 ||
	error "bug in the test script: not 2 or 3 parameters to test-expect-success"
	export test_prereq
	if ! test_skip "$@"
	then
		base=$(basename "$0" .sh)
		echo "$test_count" >>"$perf_results_dir"/$base.subtests
		echo "$1" >"$perf_results_dir"/$base.$test_count.descr
		if test -z "$verbose"; then
L
Lukas Fleischer 已提交
166
			printf "%s" "perf $test_count - $1:"
167 168 169
		else
			echo "perf $test_count - $1:"
		fi
M
Michał Kiedrowicz 已提交
170
		for i in $(test_seq 1 $GIT_PERF_REPEAT_COUNT); do
171 172 173 174
			say >&3 "running: $2"
			if test_run_perf_ "$2"
			then
				if test -z "$verbose"; then
L
Lukas Fleischer 已提交
175
					printf " %s" "$i"
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
				else
					echo "* timing run $i/$GIT_PERF_REPEAT_COUNT:"
				fi
			else
				test -z "$verbose" && echo
				test_failure_ "$@"
				break
			fi
		done
		if test -z "$verbose"; then
			echo " ok"
		else
			test_ok_ "$1"
		fi
		base="$perf_results_dir"/"$perf_results_prefix$(basename "$0" .sh)"."$test_count"
		"$TEST_DIRECTORY"/perf/min_time.perl test_time.* >"$base".times
	fi
193
	test_finish_
194 195 196 197 198 199 200 201 202 203 204 205 206
}

# We extend test_done to print timings at the end (./run disables this
# and does it after running everything)
test_at_end_hook_ () {
	if test -z "$GIT_PERF_AGGREGATING_LATER"; then
		( cd "$TEST_DIRECTORY"/perf && ./aggregate.perl $(basename "$0") )
	fi
}

test_export () {
	export "$@"
}