mirror of
https://github.com/git/git.git
synced 2025-12-12 20:36:24 +01:00
pop_most_recent_commit() calls commit_list_insert_by_date() for parent
commits, which is itself called in a loop. This can lead to quadratic
complexity if there are many merges. Replace the commit_list with a
prio_queue to ensure logarithmic worst case complexity and convert all
three users.
Add a performance test that exercises one of them using a pathological
history that consists of 50% merges and 50% root commits to demonstrate
the speedup:
Test v2.50.1 HEAD
----------------------------------------------------------------------
1501.2: rev-parse ':/65535' 2.48(2.47+0.00) 0.20(0.19+0.00) -91.9%
Alas, sane histories don't benefit from the conversion much, and
traversing Git's own history takes a 1% performance hit on my machine:
$ hyperfine -w3 -L git ./git_2.50.1,./git '{git} rev-parse :/^Initial.revision'
Benchmark 1: ./git_2.50.1 rev-parse :/^Initial.revision
Time (mean ± σ): 1.071 s ± 0.004 s [User: 1.052 s, System: 0.017 s]
Range (min … max): 1.067 s … 1.078 s 10 runs
Benchmark 2: ./git rev-parse :/^Initial.revision
Time (mean ± σ): 1.079 s ± 0.003 s [User: 1.060 s, System: 0.017 s]
Range (min … max): 1.074 s … 1.083 s 10 runs
Summary
./git_2.50.1 rev-parse :/^Initial.revision ran
1.01 ± 0.00 times faster than ./git rev-parse :/^Initial.revision
Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
72 lines
1.7 KiB
Bash
Executable File
72 lines
1.7 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
test_description='Test :/ object name notation'
|
|
|
|
. ./perf-lib.sh
|
|
|
|
test_perf_fresh_repo
|
|
|
|
#
|
|
# Creates lots of merges to make history traversal costly. In
|
|
# particular it creates 2^($max_level-1)-1 2-way merges on top of
|
|
# 2^($max_level-1) root commits. E.g., the commit history looks like
|
|
# this for a $max_level of 3:
|
|
#
|
|
# _1_
|
|
# / \
|
|
# 2 3
|
|
# / \ / \
|
|
# 4 5 6 7
|
|
#
|
|
# The numbers are the fast-import marks, which also are the commit
|
|
# messages. 1 is the HEAD commit and a merge, 2 and 3 are also merges,
|
|
# 4-7 are the root commits.
|
|
#
|
|
build_history () {
|
|
local max_level="$1" &&
|
|
local level="${2:-1}" &&
|
|
local mark="${3:-1}" &&
|
|
if test $level -eq $max_level
|
|
then
|
|
echo "reset refs/heads/master" &&
|
|
echo "from $ZERO_OID" &&
|
|
echo "commit refs/heads/master" &&
|
|
echo "mark :$mark" &&
|
|
echo "committer C <c@example.com> 1234567890 +0000" &&
|
|
echo "data <<EOF" &&
|
|
echo "$mark" &&
|
|
echo "EOF"
|
|
else
|
|
local level1=$((level+1)) &&
|
|
local mark1=$((2*mark)) &&
|
|
local mark2=$((2*mark+1)) &&
|
|
build_history $max_level $level1 $mark1 &&
|
|
build_history $max_level $level1 $mark2 &&
|
|
echo "commit refs/heads/master" &&
|
|
echo "mark :$mark" &&
|
|
echo "committer C <c@example.com> 1234567890 +0000" &&
|
|
echo "data <<EOF" &&
|
|
echo "$mark" &&
|
|
echo "EOF" &&
|
|
echo "from :$mark1" &&
|
|
echo "merge :$mark2"
|
|
fi
|
|
}
|
|
|
|
test_expect_success 'setup' '
|
|
build_history 16 | git fast-import &&
|
|
git log --format="%H %s" --reverse >commits &&
|
|
sed -n -e "s/ .*$//p" -e "q" <commits >expect &&
|
|
sed -n -e "s/^.* //p" -e "q" <commits >needle
|
|
'
|
|
|
|
test_perf "rev-parse :/$(cat needle)" '
|
|
git rev-parse :/$(cat needle) >actual
|
|
'
|
|
|
|
test_expect_success 'verify result' '
|
|
test_cmp expect actual
|
|
'
|
|
|
|
test_done
|