Skip to content

Commit

Permalink
commit: add short-circuit to paint_down_to_common()
Browse files Browse the repository at this point in the history
When running 'git branch --contains', the in_merge_bases_many()
method calls paint_down_to_common() to discover if a specific
commit is reachable from a set of branches. Commits with lower
generation number are not needed to correctly answer the
containment query of in_merge_bases_many().

Add a new parameter, min_generation, to paint_down_to_common() that
prevents walking commits with generation number strictly less than
min_generation. If 0 is given, then there is no functional change.

For in_merge_bases_many(), we can pass commit->generation as the
cutoff, and this saves time during 'git branch --contains' queries
that would otherwise walk "around" the commit we are inspecting.

For a copy of the Linux repository, where HEAD is checked out at
v4.13~100, we get the following performance improvement for
'git branch --contains' over the previous commit:

Before: 0.21s
After:  0.13s
Rel %: -38%

Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
  • Loading branch information
derrickstolee committed Apr 10, 2018
1 parent d94fa55 commit 8d28bd8
Showing 1 changed file with 9 additions and 4 deletions.
13 changes: 9 additions & 4 deletions commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -796,7 +796,9 @@ static int queue_has_nonstale(struct prio_queue *queue, uint32_t min_gen)
}

/* all input commits in one and twos[] must have been parsed! */
static struct commit_list *paint_down_to_common(struct commit *one, int n, struct commit **twos)
static struct commit_list *paint_down_to_common(struct commit *one, int n,
struct commit **twos,
int min_generation)
{
struct prio_queue queue = { compare_commits_by_gen_then_commit_date };
struct commit_list *result = NULL;
Expand Down Expand Up @@ -830,6 +832,9 @@ static struct commit_list *paint_down_to_common(struct commit *one, int n, struc

last_gen = commit->generation;

if (commit->generation < min_generation)
break;

flags = commit->object.flags & (PARENT1 | PARENT2 | STALE);
if (flags == (PARENT1 | PARENT2)) {
if (!(commit->object.flags & RESULT)) {
Expand Down Expand Up @@ -882,7 +887,7 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co
return NULL;
}

list = paint_down_to_common(one, n, twos);
list = paint_down_to_common(one, n, twos, 0);

while (list) {
struct commit *commit = pop_commit(&list);
Expand Down Expand Up @@ -949,7 +954,7 @@ static int remove_redundant(struct commit **array, int cnt)
filled_index[filled] = j;
work[filled++] = array[j];
}
common = paint_down_to_common(array[i], filled, work);
common = paint_down_to_common(array[i], filled, work, 0);
if (array[i]->object.flags & PARENT2)
redundant[i] = 1;
for (j = 0; j < filled; j++)
Expand Down Expand Up @@ -1073,7 +1078,7 @@ int in_merge_bases_many(struct commit *commit, int nr_reference, struct commit *
if (commit->generation > min_generation)
return 0;

bases = paint_down_to_common(commit, nr_reference, reference);
bases = paint_down_to_common(commit, nr_reference, reference, commit->generation);
if (commit->object.flags & PARENT2)
ret = 1;
clear_commit_marks(commit, all_flags);
Expand Down

0 comments on commit 8d28bd8

Please sign in to comment.