e3efa94be9
As this developer has no access to MacOSX developer setups anymore, Travis becomes the best bet to run performance tests on that OS. However, on MacOSX /usr/bin/time is that good old BSD executable that no Linux user cares about, as demonstrated by the perf-lib.sh's use of GNU-ish extensions. And by the hard-coded path. Let's just work around this issue by using gtime on MacOSX, the Homebrew-provided GNU implementation onto which pretty much every MacOSX power user falls back anyway. To help other developers use Travis to run performance tests on MacOSX, the .travis.yml file now sports a commented-out line that installs GNU time via Homebrew. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Reviewed-by: Lars Schneider <larsxschneider@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
217 lines
6.0 KiB
Bash
217 lines
6.0 KiB
Bash
# 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.
|
|
#
|
|
# 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
|
|
TEST_NO_MALLOC_CHECK=t
|
|
|
|
. ../test-lib.sh
|
|
|
|
# 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
|
|
|
|
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="$(git -C "$source" rev-parse --git-dir)"
|
|
objects_dir="$(git -C "$source" rev-parse --git-path objects)"
|
|
mkdir -p "$repo/.git"
|
|
(
|
|
cd "$source" &&
|
|
{ cp -Rl "$objects_dir" "$repo/.git/" 2>/dev/null ||
|
|
cp -R "$objects_dir" "$repo/.git/"; } &&
|
|
for stuff in "$source_git"/*; do
|
|
case "$stuff" in
|
|
*/objects|*/hooks|*/config|*/commondir)
|
|
;;
|
|
*)
|
|
cp -R "$stuff" "$repo/.git/" || exit 1
|
|
;;
|
|
esac
|
|
done
|
|
) &&
|
|
(
|
|
cd "$repo" &&
|
|
git init -q && {
|
|
test_have_prereq SYMLINKS ||
|
|
git config core.symlinks false
|
|
} &&
|
|
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
|
|
|
|
# Perf tests require GNU time
|
|
case "$(uname -s)" in Darwin) GTIME="${GTIME:-gtime}";; esac
|
|
GTIME="${GTIME:-/usr/bin/time}"
|
|
|
|
test_run_perf_ () {
|
|
test_cleanup=:
|
|
test_export_="test_cleanup"
|
|
export test_cleanup test_export_
|
|
"$GTIME" -f "%E %U %S" -o test_time.$i "$SHELL" -c '
|
|
. '"$TEST_DIRECTORY"/test-lib-functions.sh'
|
|
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 () {
|
|
test_start_
|
|
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
|
|
printf "%s" "perf $test_count - $1:"
|
|
else
|
|
echo "perf $test_count - $1:"
|
|
fi
|
|
for i in $(test_seq 1 $GIT_PERF_REPEAT_COUNT); do
|
|
say >&3 "running: $2"
|
|
if test_run_perf_ "$2"
|
|
then
|
|
if test -z "$verbose"; then
|
|
printf " %s" "$i"
|
|
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
|
|
test_finish_
|
|
}
|
|
|
|
# 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 "$@"
|
|
}
|