mirror of
https://github.com/git/git.git
synced 2026-01-09 17:46:37 +00:00
show-branch: use prio_queue
Building a list using commit_list_insert_by_date() has quadratic worst
case complexity. Avoid it by using prio_queue.
Use prio_queue_peek()+prio_queue_replace() instead of prio_queue_get()+
prio_queue_put() if possible, as the former only rebalance the
prio_queue heap once instead of twice.
In sane repositories this won't make much of a difference because the
number of items in the list or queue won't be very high:
Benchmark 1: ./git_v2.52.0 show-branch origin/main origin/next origin/seen origin/todo
Time (mean ± σ): 538.2 ms ± 0.8 ms [User: 527.6 ms, System: 9.6 ms]
Range (min … max): 537.0 ms … 539.2 ms 10 runs
Benchmark 2: ./git show-branch origin/main origin/next origin/seen origin/todo
Time (mean ± σ): 530.6 ms ± 0.4 ms [User: 519.8 ms, System: 9.8 ms]
Range (min … max): 530.1 ms … 531.3 ms 10 runs
Summary
./git show-branch origin/main origin/next origin/seen origin/todo ran
1.01 ± 0.00 times faster than ./git_v2.52.0 show-branch origin/main origin/next origin/seen origin/todo
That number is not limited, though, and in pathological cases like the
one in p6010 we see a sizable improvement:
Test v2.52.0 HEAD
------------------------------------------------------------------
6010.4: git show-branch 2.19(2.19+0.00) 0.03(0.02+0.00) -98.6%
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
9a2fb147f2
commit
abf05d856f
@@ -18,6 +18,7 @@
|
|||||||
#include "commit-slab.h"
|
#include "commit-slab.h"
|
||||||
#include "date.h"
|
#include "date.h"
|
||||||
#include "wildmatch.h"
|
#include "wildmatch.h"
|
||||||
|
#include "prio-queue.h"
|
||||||
|
|
||||||
static const char*const show_branch_usage[] = {
|
static const char*const show_branch_usage[] = {
|
||||||
N_("git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n"
|
N_("git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n"
|
||||||
@@ -59,11 +60,10 @@ static const char *get_color_reset_code(void)
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct commit *interesting(struct commit_list *list)
|
static struct commit *interesting(struct prio_queue *queue)
|
||||||
{
|
{
|
||||||
while (list) {
|
for (size_t i = 0; i < queue->nr; i++) {
|
||||||
struct commit *commit = list->item;
|
struct commit *commit = queue->array[i].data;
|
||||||
list = list->next;
|
|
||||||
if (commit->object.flags & UNINTERESTING)
|
if (commit->object.flags & UNINTERESTING)
|
||||||
continue;
|
continue;
|
||||||
return commit;
|
return commit;
|
||||||
@@ -222,17 +222,18 @@ static int mark_seen(struct commit *commit, struct commit_list **seen_p)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void join_revs(struct commit_list **list_p,
|
static void join_revs(struct prio_queue *queue,
|
||||||
struct commit_list **seen_p,
|
struct commit_list **seen_p,
|
||||||
int num_rev, int extra)
|
int num_rev, int extra)
|
||||||
{
|
{
|
||||||
int all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
|
int all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
|
||||||
int all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
|
int all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
|
||||||
|
|
||||||
while (*list_p) {
|
while (queue->nr) {
|
||||||
struct commit_list *parents;
|
struct commit_list *parents;
|
||||||
int still_interesting = !!interesting(*list_p);
|
int still_interesting = !!interesting(queue);
|
||||||
struct commit *commit = pop_commit(list_p);
|
struct commit *commit = prio_queue_peek(queue);
|
||||||
|
bool get_pending = true;
|
||||||
int flags = commit->object.flags & all_mask;
|
int flags = commit->object.flags & all_mask;
|
||||||
|
|
||||||
if (!still_interesting && extra <= 0)
|
if (!still_interesting && extra <= 0)
|
||||||
@@ -253,8 +254,14 @@ static void join_revs(struct commit_list **list_p,
|
|||||||
if (mark_seen(p, seen_p) && !still_interesting)
|
if (mark_seen(p, seen_p) && !still_interesting)
|
||||||
extra--;
|
extra--;
|
||||||
p->object.flags |= flags;
|
p->object.flags |= flags;
|
||||||
commit_list_insert_by_date(p, list_p);
|
if (get_pending)
|
||||||
|
prio_queue_replace(queue, p);
|
||||||
|
else
|
||||||
|
prio_queue_put(queue, p);
|
||||||
|
get_pending = false;
|
||||||
}
|
}
|
||||||
|
if (get_pending)
|
||||||
|
prio_queue_get(queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -642,7 +649,8 @@ int cmd_show_branch(int ac,
|
|||||||
{
|
{
|
||||||
struct commit *rev[MAX_REVS], *commit;
|
struct commit *rev[MAX_REVS], *commit;
|
||||||
char *reflog_msg[MAX_REVS] = {0};
|
char *reflog_msg[MAX_REVS] = {0};
|
||||||
struct commit_list *list = NULL, *seen = NULL;
|
struct commit_list *seen = NULL;
|
||||||
|
struct prio_queue queue = { compare_commits_by_commit_date };
|
||||||
unsigned int rev_mask[MAX_REVS];
|
unsigned int rev_mask[MAX_REVS];
|
||||||
int num_rev, i, extra = 0;
|
int num_rev, i, extra = 0;
|
||||||
int all_heads = 0, all_remotes = 0;
|
int all_heads = 0, all_remotes = 0;
|
||||||
@@ -886,14 +894,14 @@ int cmd_show_branch(int ac,
|
|||||||
*/
|
*/
|
||||||
commit->object.flags |= flag;
|
commit->object.flags |= flag;
|
||||||
if (commit->object.flags == flag)
|
if (commit->object.flags == flag)
|
||||||
commit_list_insert_by_date(commit, &list);
|
prio_queue_put(&queue, commit);
|
||||||
rev[num_rev] = commit;
|
rev[num_rev] = commit;
|
||||||
}
|
}
|
||||||
for (i = 0; i < num_rev; i++)
|
for (i = 0; i < num_rev; i++)
|
||||||
rev_mask[i] = rev[i]->object.flags;
|
rev_mask[i] = rev[i]->object.flags;
|
||||||
|
|
||||||
if (0 <= extra)
|
if (0 <= extra)
|
||||||
join_revs(&list, &seen, num_rev, extra);
|
join_revs(&queue, &seen, num_rev, extra);
|
||||||
|
|
||||||
commit_list_sort_by_date(&seen);
|
commit_list_sort_by_date(&seen);
|
||||||
|
|
||||||
@@ -1004,7 +1012,7 @@ out:
|
|||||||
for (size_t i = 0; i < ARRAY_SIZE(reflog_msg); i++)
|
for (size_t i = 0; i < ARRAY_SIZE(reflog_msg); i++)
|
||||||
free(reflog_msg[i]);
|
free(reflog_msg[i]);
|
||||||
free_commit_list(seen);
|
free_commit_list(seen);
|
||||||
free_commit_list(list);
|
clear_prio_queue(&queue);
|
||||||
free(args_copy);
|
free(args_copy);
|
||||||
free(head);
|
free(head);
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -83,9 +83,9 @@ build_history2 () {
|
|||||||
test_expect_success 'setup' '
|
test_expect_success 'setup' '
|
||||||
max_level=15 &&
|
max_level=15 &&
|
||||||
build_history $max_level | git fast-import --export-marks=marks &&
|
build_history $max_level | git fast-import --export-marks=marks &&
|
||||||
git tag one &&
|
git branch one &&
|
||||||
build_history2 $max_level | git fast-import --import-marks=marks --force &&
|
build_history2 $max_level | git fast-import --import-marks=marks --force &&
|
||||||
git tag two &&
|
git branch two &&
|
||||||
git gc &&
|
git gc &&
|
||||||
git log --format=%H --no-merges >expect
|
git log --format=%H --no-merges >expect
|
||||||
'
|
'
|
||||||
@@ -98,4 +98,8 @@ test_expect_success 'verify result' '
|
|||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_perf 'git show-branch' '
|
||||||
|
git show-branch one two
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
|||||||
Reference in New Issue
Block a user