commit: convert pop_most_recent_commit() to prio_queue
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>
This commit is contained in:
committed by
Junio C Hamano
parent
16bd9f20a4
commit
d6ec08788e
13
fetch-pack.c
13
fetch-pack.c
@@ -34,6 +34,7 @@
|
||||
#include "commit-graph.h"
|
||||
#include "sigchain.h"
|
||||
#include "mergesort.h"
|
||||
#include "prio-queue.h"
|
||||
|
||||
static int transfer_unpack_limit = -1;
|
||||
static int fetch_unpack_limit = -1;
|
||||
@@ -600,7 +601,7 @@ done:
|
||||
return count ? retval : 0;
|
||||
}
|
||||
|
||||
static struct commit_list *complete;
|
||||
static struct prio_queue complete = { compare_commits_by_commit_date };
|
||||
|
||||
static int mark_complete(const struct object_id *oid)
|
||||
{
|
||||
@@ -608,7 +609,7 @@ static int mark_complete(const struct object_id *oid)
|
||||
|
||||
if (commit && !(commit->object.flags & COMPLETE)) {
|
||||
commit->object.flags |= COMPLETE;
|
||||
commit_list_insert(commit, &complete);
|
||||
prio_queue_put(&complete, commit);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -625,9 +626,12 @@ static int mark_complete_oid(const char *refname UNUSED,
|
||||
static void mark_recent_complete_commits(struct fetch_pack_args *args,
|
||||
timestamp_t cutoff)
|
||||
{
|
||||
while (complete && cutoff <= complete->item->date) {
|
||||
while (complete.nr) {
|
||||
struct commit *item = prio_queue_peek(&complete);
|
||||
if (item->date < cutoff)
|
||||
break;
|
||||
print_verbose(args, _("Marking %s as complete"),
|
||||
oid_to_hex(&complete->item->object.oid));
|
||||
oid_to_hex(&item->object.oid));
|
||||
pop_most_recent_commit(&complete, COMPLETE);
|
||||
}
|
||||
}
|
||||
@@ -797,7 +801,6 @@ static void mark_complete_and_common_ref(struct fetch_negotiator *negotiator,
|
||||
refs_for_each_rawref(get_main_ref_store(the_repository),
|
||||
mark_complete_oid, NULL);
|
||||
for_each_cached_alternate(NULL, mark_alternate_complete);
|
||||
commit_list_sort_by_date(&complete);
|
||||
if (cutoff)
|
||||
mark_recent_complete_commits(args, cutoff);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user