pack-bitmap: reuse stored selected bitmaps

When `fill_bitmap_commit()` reaches an ancestor that was selected for its own bitmap and processed earlier, its object closure is already stored in `writer->bitmaps` as an EWAH bitmap. As a result, walking through that commit's tree and parents again is redundant. Teach `fill_bitmap_commit()` to notice that case. For non-root commits in the walk, look for a stored selected bitmap and OR it into the bitmap being built. If one exists, skip the commit, its tree, and its parents. Building bitmaps from scratch on the same test repository from the previous commits yields a significant speed-up: +------------------+-------------+-------------+---------------------+ | | HEAD^ | HEAD | Delta | +------------------+-------------+-------------+---------------------+ | elapsed | 562.8 s | 324.8 s | -237.9 s (-42.3%) | | cycles | 2,621.3 B | 1,508.6 B | -1,112.7 B (-42.4%) | | instructions | 2,348.9 B | 1,436.6 B | -912.3 B (-38.8%) | | CPI | 1.116 | 1.050 | -0.066 (-5.9%) | +------------------+-------------+-------------+---------------------+ In our testing repository, there are 1,261 commits selected for bitmap coverage, and 1,382 maximal commits induced as a result of that. Of the 1,382 calls made to `fill_bitmap_commit()` (one per maximal commit), 131 of them can be short-circuited at some point during their traversal as a consequence of this change. In large repositories where the cost of filling the bitmap for any individual commit is large, being able to short-circuit even ~9.5% of the calls to `fill_bitmap_commit()` results in a significant savings. Signed-off-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Taylor Blau committed May 27, 2026 at 15:55 UTC 3ea5fe8482e44fe8636b2725edffcadc81b22161
1 file changed +34
pack-bitmap-write.c
+34
@@ -509,6 +509,9 @@ static int fill_bitmap_tree(struct bitmap_writer *writer,
509 static int reused_bitmaps_nr;
510 static int reused_pseudo_merge_bitmaps_nr;
511
512 +static int fill_bitmap_commit_calls_nr;
513 +static int fill_bitmap_commit_found_ancestor_nr;
514 +
515 static int fill_bitmap_commit(struct bitmap_writer *writer,
516 struct bb_commit *ent,
517 struct commit *commit,
@@ -519,6 +522,9 @@ static int fill_bitmap_commit(struct bitmap_writer *writer,
522 {
523 int found;
524 uint32_t pos;
525 +
526 + fill_bitmap_commit_calls_nr++;
527 +
528 if (!ent->bitmap)
529 ent->bitmap = bitmap_new();
530
@@ -553,6 +559,28 @@ static int fill_bitmap_commit(struct bitmap_writer *writer,
559 bitmap_free(remapped);
560 }
561
562 + /*
563 + * If we encounter an ancestor for which we have already
564 + * computed a bitmap during this build (i.e. a regular
565 + * selected commit processed earlier in topo order), we can
566 + * short-circuit the walk: its stored bitmap already covers
567 + * the commit itself, its tree, and all of its ancestors.
568 + */
569 + if (c != commit) {
570 + khiter_t hash_pos = kh_get_oid_map(writer->bitmaps,
571 + c->object.oid);
572 + if (hash_pos != kh_end(writer->bitmaps)) {
573 + struct bitmapped_commit *stored =
574 + kh_value(writer->bitmaps, hash_pos);
575 + if (stored && stored->bitmap) {
576 + fill_bitmap_commit_found_ancestor_nr++;
577 + bitmap_or_ewah(ent->bitmap,
578 + stored->bitmap);
579 + continue;
580 + }
581 + }
582 + }
583 +
584 /*
585 * Mark ourselves and queue our tree. The commit
586 * walk ensures we cover all parents.
@@ -692,6 +720,12 @@ int bitmap_writer_build(struct bitmap_writer *writer)
720 trace2_data_intmax("pack-bitmap-write", writer->repo,
721 "building_bitmaps_pseudo_merge_reused",
722 reused_pseudo_merge_bitmaps_nr);
723 + trace2_data_intmax("pack-bitmap-write", writer->repo,
724 + "fill_bitmap_commit_calls_nr",
725 + fill_bitmap_commit_calls_nr);
726 + trace2_data_intmax("pack-bitmap-write", writer->repo,
727 + "fill_bitmap_commit_found_ancestor_nr",
728 + fill_bitmap_commit_found_ancestor_nr);
729
730 stop_progress(&writer->progress);
731