Skip to content

Commit 66eb375

Browse files
committed
commit-slab: avoid large realloc
Instead of using a single "slab" and keep reallocating it as we find that we need to deal with commits with larger values of commit->index, make a "slab" an array of many "slab_piece"s. Each access may need two levels of indirections, but we only need to reallocate the first level array of pointers when we have to grow the table this way. Signed-off-by: Junio C Hamano <[email protected]>
1 parent 96c4f4a commit 66eb375

File tree

1 file changed

+42
-20
lines changed

1 file changed

+42
-20
lines changed

commit.c

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -501,34 +501,56 @@ struct commit *pop_commit(struct commit_list **stack)
501501
return item;
502502
}
503503

504+
struct commit_slab_piece {
505+
int buf;
506+
};
507+
504508
struct commit_slab {
505-
int *buf;
506-
int alloc;
509+
int piece_size;
510+
int piece_count;
511+
struct commit_slab_piece **piece;
507512
};
508513

509514
static void slab_init(struct commit_slab *s)
510515
{
511-
memset(s, 0, sizeof(*s));
516+
/* allocate ~512kB at once, allowing for malloc overhead */
517+
int size = (512*1024-32) / sizeof(struct commit_slab_piece);
518+
519+
s->piece_size = size;
520+
s->piece_count = 0;
521+
s->piece = NULL;
512522
}
513523

514524
static void slab_clear(struct commit_slab *s)
515525
{
516-
free(s->buf);
517-
slab_init(s);
526+
int i;
527+
528+
for (i = 0; i < s->piece_count; i++)
529+
free(s->piece[i]);
530+
s->piece_count = 0;
531+
free(s->piece);
532+
s->piece = NULL;
518533
}
519534

520-
static inline int *slab_at(struct commit_slab *s, const struct commit *c)
535+
static inline struct commit_slab_piece *slab_at(struct commit_slab *s,
536+
const struct commit *c)
521537
{
522-
if (s->alloc <= c->index) {
523-
int new_alloc = alloc_nr(s->alloc);
524-
if (new_alloc <= c->index)
525-
new_alloc = c->index + 1;
526-
527-
s->buf = xrealloc(s->buf, new_alloc * sizeof(*s->buf));
528-
memset(s->buf + s->alloc, 0, new_alloc - s->alloc);
529-
s->alloc = new_alloc;
538+
int nth_piece, nth_slot;
539+
540+
nth_piece = c->index / s->piece_size;
541+
nth_slot = c->index % s->piece_size;
542+
543+
if (s->piece_count <= nth_piece) {
544+
int i;
545+
546+
s->piece = xrealloc(s->piece, (nth_piece + 1) * sizeof(s->piece));
547+
for (i = s->piece_count; i <= nth_piece; i++)
548+
s->piece[i] = NULL;
549+
s->piece_count = nth_piece + 1;
530550
}
531-
return s->buf + c->index;
551+
if (!s->piece[nth_piece])
552+
s->piece[nth_piece] = xcalloc(s->piece_size, sizeof(**s->piece));
553+
return &s->piece[nth_piece][nth_slot];
532554
}
533555

534556
/*
@@ -550,15 +572,15 @@ void sort_in_topological_order(struct commit_list ** list, int lifo)
550572
/* Mark them and clear the indegree */
551573
for (next = orig; next; next = next->next) {
552574
struct commit *commit = next->item;
553-
*slab_at(&indegree, commit) = 1;
575+
slab_at(&indegree, commit)->buf = 1;
554576
}
555577

556578
/* update the indegree */
557579
for (next = orig; next; next = next->next) {
558580
struct commit_list * parents = next->item->parents;
559581
while (parents) {
560582
struct commit *parent = parents->item;
561-
int *pi = slab_at(&indegree, parent);
583+
int *pi = &slab_at(&indegree, parent)->buf;
562584

563585
if (*pi)
564586
(*pi)++;
@@ -578,7 +600,7 @@ void sort_in_topological_order(struct commit_list ** list, int lifo)
578600
for (next = orig; next; next = next->next) {
579601
struct commit *commit = next->item;
580602

581-
if (*slab_at(&indegree, commit) == 1)
603+
if (slab_at(&indegree, commit)->buf == 1)
582604
insert = &commit_list_insert(commit, insert)->next;
583605
}
584606

@@ -599,7 +621,7 @@ void sort_in_topological_order(struct commit_list ** list, int lifo)
599621
commit = work_item->item;
600622
for (parents = commit->parents; parents ; parents = parents->next) {
601623
struct commit *parent = parents->item;
602-
int *pi = slab_at(&indegree, parent);
624+
int *pi = &slab_at(&indegree, parent)->buf;
603625

604626
if (!*pi)
605627
continue;
@@ -620,7 +642,7 @@ void sort_in_topological_order(struct commit_list ** list, int lifo)
620642
* work_item is a commit all of whose children
621643
* have already been emitted. we can emit it now.
622644
*/
623-
*slab_at(&indegree, commit) = 0;
645+
slab_at(&indegree, commit)->buf = 0;
624646
*pptr = work_item;
625647
pptr = &work_item->next;
626648
}

0 commit comments

Comments
 (0)