1 2 3 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 47 48 49 50 51 52 53 54 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 94 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 129 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 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
|
#!/bin/sh
test_description="Test core.fsmonitor"
. ./perf-lib.sh
#
# Performance test for the fsmonitor feature which enables git to talk to a
# file system change monitor and avoid having to scan the working directory
# for new or modified files.
#
# By default, the performance test will utilize the Watchman file system
# monitor if it is installed. If Watchman is not installed, it will use a
# dummy integration script that does not report any new or modified files.
# The dummy script has very little overhead which provides optimistic results.
#
# The performance test will also use the untracked cache feature if it is
# available as fsmonitor uses it to speed up scanning for untracked files.
#
# There are 3 environment variables that can be used to alter the default
# behavior of the performance test:
#
# GIT_PERF_7519_UNTRACKED_CACHE: used to configure core.untrackedCache
# GIT_PERF_7519_SPLIT_INDEX: used to configure core.splitIndex
# GIT_PERF_7519_FSMONITOR: used to configure core.fsMonitor. May be an
# absolute path to an integration. May be a space delimited list of
# absolute paths to integrations.
#
# The big win for using fsmonitor is the elimination of the need to scan the
# working directory looking for changed and untracked files. If the file
# information is all cached in RAM, the benefits are reduced.
#
# GIT_PERF_7519_DROP_CACHE: if set, the OS caches are dropped between tests
#
# GIT_PERF_7519_TRACE: if set, enable trace logging during the test.
# Trace logs will be grouped by fsmonitor provider.
test_perf_large_repo
test_checkout_worktree
test_lazy_prereq UNTRACKED_CACHE '
{ git update-index --test-untracked-cache; ret=$?; } &&
test $ret -ne 1
'
test_lazy_prereq WATCHMAN '
command -v watchman
'
if test_have_prereq WATCHMAN
then
# Convert unix style paths to escaped Windows style paths for Watchman
case "$(uname -s)" in
MSYS_NT*)
GIT_WORK_TREE="$(cygpath -aw "$PWD" | sed 's,\\,/,g')"
;;
*)
GIT_WORK_TREE="$PWD"
;;
esac
fi
trace_start () {
if test -n "$GIT_PERF_7519_TRACE"
then
name="$1"
TEST_TRACE_DIR="$TEST_OUTPUT_DIRECTORY/test-trace/p7519/"
echo "Writing trace logging to $TEST_TRACE_DIR"
mkdir -p "$TEST_TRACE_DIR"
# Start Trace2 logging and any other GIT_TRACE_* logs that you
# want for this named test case.
GIT_TRACE2_PERF="$TEST_TRACE_DIR/$name.trace2perf"
export GIT_TRACE2_PERF
>"$GIT_TRACE2_PERF"
fi
}
trace_stop () {
if test -n "$GIT_PERF_7519_TRACE"
then
unset GIT_TRACE2_PERF
fi
}
touch_files () {
n=$1 &&
d="$n"_files &&
(cd $d && test_seq 1 $n | xargs touch )
}
test_expect_success "one time repo setup" '
# set untrackedCache depending on the environment
if test -n "$GIT_PERF_7519_UNTRACKED_CACHE"
then
git config core.untrackedCache "$GIT_PERF_7519_UNTRACKED_CACHE"
else
if test_have_prereq UNTRACKED_CACHE
then
git config core.untrackedCache true
else
git config core.untrackedCache false
fi
fi &&
# set core.splitindex depending on the environment
if test -n "$GIT_PERF_7519_SPLIT_INDEX"
then
git config core.splitIndex "$GIT_PERF_7519_SPLIT_INDEX"
fi &&
mkdir 1_file 10_files 100_files 1000_files 10000_files &&
: 1_file directory should be left empty &&
touch_files 10 &&
touch_files 100 &&
touch_files 1000 &&
touch_files 10000 &&
git add 1_file 10_files 100_files 1000_files 10000_files &&
git commit -qm "Add files" &&
# If Watchman exists, watch the work tree and attempt a query.
if test_have_prereq WATCHMAN; then
watchman watch "$GIT_WORK_TREE" &&
watchman watch-list | grep -q -F "p7519-fsmonitor"
fi
'
setup_for_fsmonitor_hook () {
# set INTEGRATION_SCRIPT depending on the environment
if test -n "$INTEGRATION_PATH"
then
INTEGRATION_SCRIPT="$INTEGRATION_PATH"
else
#
# Choose integration script based on existence of Watchman.
# Fall back to an empty integration script.
#
mkdir .git/hooks &&
if test_have_prereq WATCHMAN
then
INTEGRATION_SCRIPT=".git/hooks/fsmonitor-watchman" &&
cp "$TEST_DIRECTORY/../templates/hooks--fsmonitor-watchman.sample" "$INTEGRATION_SCRIPT"
else
INTEGRATION_SCRIPT=".git/hooks/fsmonitor-empty" &&
write_script "$INTEGRATION_SCRIPT"<<-\EOF
EOF
fi
fi &&
git config core.fsmonitor "$INTEGRATION_SCRIPT" &&
git update-index --fsmonitor 2>error &&
if test_have_prereq WATCHMAN
then
test_must_be_empty error # ensure no silent error
else
grep "Empty last update token" error
fi
}
test_perf_w_drop_caches () {
if test -n "$GIT_PERF_7519_DROP_CACHE"; then
test_perf "$1" --setup "test-tool drop-caches" "$2"
else
test_perf "$@"
fi
}
test_fsmonitor_suite () {
if test -n "$USE_FSMONITOR_DAEMON"
then
DESC="builtin fsmonitor--daemon"
elif test -n "$INTEGRATION_SCRIPT"
then
DESC="fsmonitor=$(basename $INTEGRATION_SCRIPT)"
else
DESC="fsmonitor=disabled"
fi
test_expect_success "test_initialization" '
git reset --hard &&
git status # Warm caches
'
test_perf_w_drop_caches "status ($DESC)" '
git status
'
test_perf_w_drop_caches "status -uno ($DESC)" '
git status -uno
'
test_perf_w_drop_caches "status -uall ($DESC)" '
git status -uall
'
# Update the mtimes on upto 100k files to make status think
# that they are dirty. For simplicity, omit any files with
# LFs (i.e. anything that ls-files thinks it needs to dquote)
# and any files with whitespace so that they pass thru xargs
# properly.
#
test_perf_w_drop_caches "status (dirty) ($DESC)" '
git ls-files | \
head -100000 | \
grep -v \" | \
grep -v " ." | \
xargs test-tool chmtime -300 &&
git status
'
test_perf_w_drop_caches "diff ($DESC)" '
git diff
'
test_perf_w_drop_caches "diff HEAD ($DESC)" '
git diff HEAD
'
test_perf_w_drop_caches "diff -- 0_files ($DESC)" '
git diff -- 1_file
'
test_perf_w_drop_caches "diff -- 10_files ($DESC)" '
git diff -- 10_files
'
test_perf_w_drop_caches "diff -- 100_files ($DESC)" '
git diff -- 100_files
'
test_perf_w_drop_caches "diff -- 1000_files ($DESC)" '
git diff -- 1000_files
'
test_perf_w_drop_caches "diff -- 10000_files ($DESC)" '
git diff -- 10000_files
'
test_perf_w_drop_caches "add ($DESC)" '
git add --all
'
}
#
# Run a full set of perf tests using each Hook-based fsmonitor provider,
# such as Watchman.
#
trace_start fsmonitor-watchman
if test -n "$GIT_PERF_7519_FSMONITOR"; then
for INTEGRATION_PATH in $GIT_PERF_7519_FSMONITOR; do
test_expect_success "setup for fsmonitor $INTEGRATION_PATH" 'setup_for_fsmonitor_hook'
test_fsmonitor_suite
done
else
test_expect_success "setup for fsmonitor hook" 'setup_for_fsmonitor_hook'
test_fsmonitor_suite
fi
if test_have_prereq WATCHMAN
then
watchman watch-del "$GIT_WORK_TREE" >/dev/null 2>&1 &&
# Work around Watchman bug on Windows where it holds on to handles
# preventing the removal of the trash directory
watchman shutdown-server >/dev/null 2>&1
fi
trace_stop
#
# Run a full set of perf tests with the fsmonitor feature disabled.
#
trace_start fsmonitor-disabled
test_expect_success "setup without fsmonitor" '
unset INTEGRATION_SCRIPT &&
git config --unset core.fsmonitor &&
git update-index --no-fsmonitor
'
test_fsmonitor_suite
trace_stop
#
# Run a full set of perf tests using the built-in fsmonitor--daemon.
# It does not use the Hook API, so it has a different setup.
# Explicitly start the daemon here and before we start client commands
# so that we can later add custom tracing.
#
if test_have_prereq FSMONITOR_DAEMON
then
USE_FSMONITOR_DAEMON=t
test_expect_success "setup for builtin fsmonitor" '
trace_start fsmonitor--daemon--server &&
git fsmonitor--daemon start &&
trace_start fsmonitor--daemon--client &&
git config core.fsmonitor true &&
git update-index --fsmonitor
'
test_fsmonitor_suite
git fsmonitor--daemon stop
trace_stop
fi
test_done
|