From b1c36cb84908a31ede05e5a16fbc584c7681cffb Mon Sep 17 00:00:00 2001 From: Jeff King Date: Tue, 2 Jul 2019 01:16:49 -0400 Subject: [PATCH 1/6] test-lib: introduce test_commit_bulk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some tests need to create a string of commits. Doing this with test_commit is very heavy-weight, as it needs at least one process per commit (and in fact, uses several). For bulk creation, we can do much better by using fast-import, but it's often a pain to generate the input. Let's provide a helper to do so. We'll use t5310 as a guinea pig, as it has three 10-commit loops. Here are hyperfine results before and after: [before] Benchmark #1: ./t5310-pack-bitmaps.sh --root=/var/ram/git-tests Time (mean ± σ): 2.846 s ± 0.305 s [User: 3.042 s, System: 0.919 s] Range (min … max): 2.250 s … 3.210 s 10 runs [after] Benchmark #1: ./t5310-pack-bitmaps.sh --root=/var/ram/git-tests Time (mean ± σ): 2.210 s ± 0.174 s [User: 2.570 s, System: 0.604 s] Range (min … max): 1.999 s … 2.590 s 10 runs So we're over 20% faster, while making the callers slightly shorter. We added a lot more lines in test-lib-function.sh, of course, and the helper is way more featureful than we need here. But my hope is that it will be flexible enough to use in more places. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t5310-pack-bitmaps.sh | 15 +---- t/test-lib-functions.sh | 123 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 12 deletions(-) diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh index a26c8ba9a2..3aab7024ca 100755 --- a/t/t5310-pack-bitmaps.sh +++ b/t/t5310-pack-bitmaps.sh @@ -21,15 +21,9 @@ has_any () { } test_expect_success 'setup repo with moderate-sized history' ' - for i in $(test_seq 1 10) - do - test_commit $i - done && + test_commit_bulk --id=file 10 && git checkout -b other HEAD~5 && - for i in $(test_seq 1 10) - do - test_commit side-$i - done && + test_commit_bulk --id=side 10 && git checkout master && bitmaptip=$(git rev-parse master) && blob=$(echo tagged-blob | git hash-object -w --stdin) && @@ -106,10 +100,7 @@ test_expect_success 'clone from bitmapped repository' ' ' test_expect_success 'setup further non-bitmapped commits' ' - for i in $(test_seq 1 10) - do - test_commit further-$i - done + test_commit_bulk --id=further 10 ' rev_list_tests 'partial bitmap' diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index 0367cec5fd..6083cf483a 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -233,6 +233,129 @@ test_merge () { git tag "$1" } +# Efficiently create commits, each with a unique number (from 1 to +# by default) in the commit message. +# +# Usage: test_commit_bulk [options] +# -C : +# Run all git commands in directory +# --ref=: +# ref on which to create commits (default: HEAD) +# --start=: +# number commit messages from (default: 1) +# --message=: +# use as the commit mesasge (default: "commit %s") +# --filename=: +# modify in each commit (default: %s.t) +# --contents=: +# place in each file (default: "content %s") +# --id=: +# shorthand to use and %s in message, filename, and contents +# +# The message, filename, and contents strings are evaluated by printf, with the +# first "%s" replaced by the current commit number. So you can do: +# +# test_commit_bulk --filename=file --contents="modification %s" +# +# to have every commit touch the same file, but with unique content. +# +test_commit_bulk () { + tmpfile=.bulk-commit.input + indir=. + ref=HEAD + n=1 + message='commit %s' + filename='%s.t' + contents='content %s' + while test $# -gt 0 + do + case "$1" in + -C) + indir=$2 + shift + ;; + --ref=*) + ref=${1#--*=} + ;; + --start=*) + n=${1#--*=} + ;; + --message=*) + message=${1#--*=} + ;; + --filename=*) + filename=${1#--*=} + ;; + --contents=*) + contents=${1#--*=} + ;; + --id=*) + message="${1#--*=} %s" + filename="${1#--*=}-%s.t" + contents="${1#--*=} %s" + ;; + -*) + BUG "invalid test_commit_bulk option: $1" + ;; + *) + break + ;; + esac + shift + done + total=$1 + + add_from= + if git -C "$indir" rev-parse --verify "$ref" + then + add_from=t + fi + + while test "$total" -gt 0 + do + test_tick && + echo "commit $ref" + printf 'author %s <%s> %s\n' \ + "$GIT_AUTHOR_NAME" \ + "$GIT_AUTHOR_EMAIL" \ + "$GIT_AUTHOR_DATE" + printf 'committer %s <%s> %s\n' \ + "$GIT_COMMITTER_NAME" \ + "$GIT_COMMITTER_EMAIL" \ + "$GIT_COMMITTER_DATE" + echo "data <"$tmpfile" + + git -C "$indir" \ + -c fastimport.unpacklimit=0 \ + fast-import <"$tmpfile" || return 1 + + # This will be left in place on failure, which may aid debugging. + rm -f "$tmpfile" + + # If we updated HEAD, then be nice and update the index and working + # tree, too. + if test "$ref" = "HEAD" + then + git -C "$indir" checkout -f HEAD || return 1 + fi + +} + # This function helps systems where core.filemode=false is set. # Use it instead of plain 'chmod +x' to set or unset the executable bit # of a file in the working directory and add it to the index. From 1ac96cd1ba5938d4da251bf6447f11da8692db05 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Fri, 28 Jun 2019 05:39:42 -0400 Subject: [PATCH 2/6] t5310: increase the number of bitmapped commits The bitmap index we compute in t5310 has only 20 commits in it. This gives poor coverage of bitmap_writer_select_commits(), which simply writes a bitmap for everything when there are fewer than 100 commits. Let's bump the number of commits in the test to cover the more complex code paths (this does drop coverage of the individual lines of the trivial path, but the complex path does everything it does and more). Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t5310-pack-bitmaps.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh index 3aab7024ca..6640329ebf 100755 --- a/t/t5310-pack-bitmaps.sh +++ b/t/t5310-pack-bitmaps.sh @@ -21,7 +21,7 @@ has_any () { } test_expect_success 'setup repo with moderate-sized history' ' - test_commit_bulk --id=file 10 && + test_commit_bulk --id=file 100 && git checkout -b other HEAD~5 && test_commit_bulk --id=side 10 && git checkout master && From 737b19b50ccecfea56875472e3377ad989a1659f Mon Sep 17 00:00:00 2001 From: Jeff King Date: Fri, 28 Jun 2019 05:41:35 -0400 Subject: [PATCH 3/6] t3311: use test_commit_bulk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One of the tests in t3311 creates 300 commits by running "test_commit" in a loop. This requires 900 processes. Instead, we can use test_commit_bulk to do it with only four. This improves the runtime of the script from: Benchmark #1: ./t3311-notes-merge-fanout.sh --root=/var/ram/git-tests Time (mean ± σ): 5.821 s ± 0.691 s [User: 3.146 s, System: 2.782 s] Range (min … max): 4.783 s … 6.841 s 10 runs to: Benchmark #1: ./t3311-notes-merge-fanout.sh --root=/var/ram/git-tests Time (mean ± σ): 1.743 s ± 0.116 s [User: 1.144 s, System: 0.691 s] Range (min … max): 1.629 s … 1.994 s 10 runs for an average speedup of over 70%. Unfortunately we still have to run 300 instances of "git notes add", since the point is to test the fanout that comes from adding notes one by one. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t3311-notes-merge-fanout.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/t/t3311-notes-merge-fanout.sh b/t/t3311-notes-merge-fanout.sh index 93516ef67c..37151a3adc 100755 --- a/t/t3311-notes-merge-fanout.sh +++ b/t/t3311-notes-merge-fanout.sh @@ -114,12 +114,12 @@ cp expect_log_x expect_log_y test_expect_success 'Add a few hundred commits w/notes to trigger fanout (x -> y)' ' git update-ref refs/notes/y refs/notes/x && git config core.notesRef refs/notes/y && - i=5 && - while test $i -lt $num + test_commit_bulk --start=6 --id=commit $((num - 5)) && + i=0 && + while test $i -lt $((num - 5)) do - i=$(($i + 1)) && - test_commit "commit$i" >/dev/null && - git notes add -m "notes for commit$i" || return 1 + git notes add -m "notes for commit$i" HEAD~$i || return 1 + i=$((i + 1)) done && test "$(git rev-parse refs/notes/y)" != "$(git rev-parse refs/notes/x)" && # Expected number of commits and notes From 9516345ea56f3ecb7f66e32735781d648da24a82 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Fri, 28 Jun 2019 05:41:54 -0400 Subject: [PATCH 4/6] t5702: use test_commit_bulk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are two loops that create 32 commits each using test_commit. Using test_commit_bulk speeds this up from: Benchmark #1: ./t5702-protocol-v2.sh --root=/var/ram/git-tests Time (mean ± σ): 5.409 s ± 0.513 s [User: 2.382 s, System: 2.466 s] Range (min … max): 4.633 s … 5.927 s 10 runs to: Benchmark #1: ./t5702-protocol-v2.sh --root=/var/ram/git-tests Time (mean ± σ): 3.956 s ± 0.242 s [User: 1.775 s, System: 1.627 s] Range (min … max): 3.449 s … 4.239 s 10 runs for an average savings of over 25%. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t5702-protocol-v2.sh | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh index 5b33f625dd..011b81d4fc 100755 --- a/t/t5702-protocol-v2.sh +++ b/t/t5702-protocol-v2.sh @@ -499,10 +499,7 @@ test_expect_success 'upload-pack respects client shallows' ' # Add extra commits to the client so that the whole fetch takes more # than 1 request (due to negotiation) - for i in $(test_seq 1 32) - do - test_commit -C client c$i - done && + test_commit_bulk -C client --id=c 32 && git -C server checkout -b newbranch base && test_commit -C server client_wants && @@ -711,10 +708,7 @@ test_expect_success 'when server does not send "ready", expect FLUSH' ' # Create many commits to extend the negotiation phase across multiple # requests, so that the server does not send "ready" in the first # request. - for i in $(test_seq 1 32) - do - test_commit -C http_child c$i - done && + test_commit_bulk -C http_child --id=c 32 && # After the acknowledgments section, pretend that a DELIM # (0001) was sent instead of a FLUSH (0000). From ac093d5508a4792a29ec9e2de19797abdb92a026 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Fri, 28 Jun 2019 05:42:07 -0400 Subject: [PATCH 5/6] t5703: use test_commit_bulk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are two loops that create 33 commits each using test_commit. Using test_commit_bulk speeds this up from: Benchmark #1: ./t5703-upload-pack-ref-in-want.sh --root=/var/ram/git-tests Time (mean ± σ): 2.142 s ± 0.161 s [User: 1.136 s, System: 0.974 s] Range (min … max): 1.903 s … 2.401 s 10 runs to: Benchmark #1: ./t5703-upload-pack-ref-in-want.sh --root=/var/ram/git-tests Time (mean ± σ): 1.440 s ± 0.114 s [User: 737.7 ms, System: 615.4 ms] Range (min … max): 1.230 s … 1.604 s 10 runs for an average savings of almost 33%. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t5703-upload-pack-ref-in-want.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh index 0951d1bbdc..de4b6106ef 100755 --- a/t/t5703-upload-pack-ref-in-want.sh +++ b/t/t5703-upload-pack-ref-in-want.sh @@ -176,7 +176,7 @@ test_expect_success 'setup repos for change-while-negotiating test' ' git clone "http://127.0.0.1:$LIB_HTTPD_PORT/smart/repo" "$LOCAL_PRISTINE" && cd "$LOCAL_PRISTINE" && git checkout -b side && - for i in $(test_seq 1 33); do test_commit s$i; done && + test_commit_bulk --id=s 33 && # Add novel commits to upstream git checkout master && @@ -287,7 +287,7 @@ test_expect_success 'setup repos for fetching with ref-in-want tests' ' git clone "file://$REPO" "$LOCAL_PRISTINE" && cd "$LOCAL_PRISTINE" && git checkout -b side && - for i in $(test_seq 1 33); do test_commit s$i; done && + test_commit_bulk --id=s 33 && # Add novel commits to upstream git checkout master && From 70b39fbede78313656e8a6bd9b38b238ab10db2f Mon Sep 17 00:00:00 2001 From: Jeff King Date: Fri, 19 Jul 2019 17:56:23 -0400 Subject: [PATCH 6/6] t6200: use test_commit_bulk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's a loop that creates 30 commits using test_commit. Using test_commit_bulk speeds this up from: Benchmark #1: ./t6200-fmt-merge-msg.sh --root=/var/ram/git-tests Time (mean ± σ): 1.926 s ± 0.240 s [User: 1.055 s, System: 0.963 s] Range (min … max): 1.431 s … 2.166 s 10 runs to: Benchmark #1: ./t6200-fmt-merge-msg.sh --root=/var/ram/git-tests Time (mean ± σ): 1.343 s ± 0.179 s [User: 766.5 ms, System: 662.9 ms] Range (min … max): 1.032 s … 1.664 s 10 runs for an average savings of over 30%. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t6200-fmt-merge-msg.sh | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh index 93f23cfa82..8a72b4c43a 100755 --- a/t/t6200-fmt-merge-msg.sh +++ b/t/t6200-fmt-merge-msg.sh @@ -66,12 +66,7 @@ test_expect_success setup ' git commit -a -m "Right #5" && git checkout -b long && - i=0 && - while test $i -lt 30 - do - test_commit $i one && - i=$(($i+1)) - done && + test_commit_bulk --start=0 --message=%s --filename=one 30 && git show-branch &&