Skip to content

Commit 66e2adb

Browse files
rscharfegitster
authored andcommitted
describe: use prio_queue
Replace the use a list-based priority queue whose order is maintained by commit_list_insert_by_date() with a prio_queue. This avoids quadratic worst-case complexity. And in the somewhat contrived example of describing the 4751 commits from v2.41.0 to v2.47.0 in one go (to get a sizable chunk of describe work with minimal ref loading overhead) it's significantly faster: Benchmark 1: ./git_2.50.1 describe $(git rev-list v2.41.0..v2.47.0) Time (mean ± σ): 1.558 s ± 0.002 s [User: 1.492 s, System: 0.051 s] Range (min … max): 1.557 s … 1.562 s 10 runs Benchmark 2: ./git describe $(git rev-list v2.41.0..v2.47.0) Time (mean ± σ): 1.209 s ± 0.006 s [User: 1.143 s, System: 0.051 s] Range (min … max): 1.201 s … 1.219 s 10 runs Summary ./git describe $(git rev-list v2.41.0..v2.47.0) ran 1.29 ± 0.01 times faster than ./git_2.50.1 describe $(git rev-list v2.41.0..v2.47.0) Signed-off-by: René Scharfe <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 866e6a3 commit 66e2adb

File tree

1 file changed

+27
-24
lines changed

1 file changed

+27
-24
lines changed

builtin/describe.c

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "list-objects.h"
2424
#include "commit-slab.h"
2525
#include "wildmatch.h"
26+
#include "prio-queue.h"
2627

2728
#define MAX_TAGS (FLAG_BITS - 1)
2829
#define DEFAULT_CANDIDATES 10
@@ -249,32 +250,34 @@ static int compare_pt(const void *a_, const void *b_)
249250
return 0;
250251
}
251252

252-
static unsigned long finish_depth_computation(
253-
struct commit_list **list,
254-
struct possible_tag *best)
253+
static bool all_have_flag(const struct prio_queue *queue, unsigned flag)
254+
{
255+
for (size_t i = 0; i < queue->nr; i++) {
256+
struct commit *commit = queue->array[i].data;
257+
if (!(commit->object.flags & flag))
258+
return false;
259+
}
260+
return true;
261+
}
262+
263+
static unsigned long finish_depth_computation(struct prio_queue *queue,
264+
struct possible_tag *best)
255265
{
256266
unsigned long seen_commits = 0;
257-
while (*list) {
258-
struct commit *c = pop_commit(list);
267+
while (queue->nr) {
268+
struct commit *c = prio_queue_get(queue);
259269
struct commit_list *parents = c->parents;
260270
seen_commits++;
261271
if (c->object.flags & best->flag_within) {
262-
struct commit_list *a = *list;
263-
while (a) {
264-
struct commit *i = a->item;
265-
if (!(i->object.flags & best->flag_within))
266-
break;
267-
a = a->next;
268-
}
269-
if (!a)
272+
if (all_have_flag(queue, best->flag_within))
270273
break;
271274
} else
272275
best->depth++;
273276
while (parents) {
274277
struct commit *p = parents->item;
275278
repo_parse_commit(the_repository, p);
276279
if (!(p->object.flags & SEEN))
277-
commit_list_insert_by_date(p, list);
280+
prio_queue_put(queue, p);
278281
p->object.flags |= c->object.flags;
279282
parents = parents->next;
280283
}
@@ -316,7 +319,7 @@ static void append_suffix(int depth, const struct object_id *oid, struct strbuf
316319
static void describe_commit(struct object_id *oid, struct strbuf *dst)
317320
{
318321
struct commit *cmit, *gave_up_on = NULL;
319-
struct commit_list *list;
322+
struct prio_queue queue = { compare_commits_by_commit_date };
320323
struct commit_name *n;
321324
struct possible_tag all_matches[MAX_TAGS];
322325
unsigned int match_cnt = 0, annotated_cnt = 0, cur_match;
@@ -359,11 +362,10 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
359362
have_util = 1;
360363
}
361364

362-
list = NULL;
363365
cmit->object.flags = SEEN;
364-
commit_list_insert(cmit, &list);
365-
while (list) {
366-
struct commit *c = pop_commit(&list);
366+
prio_queue_put(&queue, cmit);
367+
while (queue.nr) {
368+
struct commit *c = prio_queue_get(&queue);
367369
struct commit_list *parents = c->parents;
368370
struct commit_name **slot;
369371

@@ -397,7 +399,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
397399
t->depth++;
398400
}
399401
/* Stop if last remaining path already covered by best candidate(s) */
400-
if (annotated_cnt && !list) {
402+
if (annotated_cnt && !queue.nr) {
401403
int best_depth = INT_MAX;
402404
unsigned best_within = 0;
403405
for (cur_match = 0; cur_match < match_cnt; cur_match++) {
@@ -420,7 +422,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
420422
struct commit *p = parents->item;
421423
repo_parse_commit(the_repository, p);
422424
if (!(p->object.flags & SEEN))
423-
commit_list_insert_by_date(p, &list);
425+
prio_queue_put(&queue, p);
424426
p->object.flags |= c->object.flags;
425427
parents = parents->next;
426428

@@ -435,6 +437,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
435437
strbuf_add_unique_abbrev(dst, cmit_oid, abbrev);
436438
if (suffix)
437439
strbuf_addstr(dst, suffix);
440+
clear_prio_queue(&queue);
438441
return;
439442
}
440443
if (unannotated_cnt)
@@ -450,11 +453,11 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
450453
QSORT(all_matches, match_cnt, compare_pt);
451454

452455
if (gave_up_on) {
453-
commit_list_insert_by_date(gave_up_on, &list);
456+
prio_queue_put(&queue, gave_up_on);
454457
seen_commits--;
455458
}
456-
seen_commits += finish_depth_computation(&list, &all_matches[0]);
457-
free_commit_list(list);
459+
seen_commits += finish_depth_computation(&queue, &all_matches[0]);
460+
clear_prio_queue(&queue);
458461

459462
if (debug) {
460463
static int label_width = -1;

0 commit comments

Comments
 (0)