pack-bitmap-write: pass ownership of intermediate bitmaps

Our algorithm to generate reachability bitmaps walks through the commit graph from the bottom up, passing bitmap data from each commit to its descendants. For a linear stretch of history like: A -- B -- C our sequence of steps is: - compute the bitmap for A by walking its trees, etc - duplicate A's bitmap as a starting point for B; we can now free A's bitmap, since we only needed it as an intermediate result - OR in any extra objects that B can reach into its bitmap - duplicate B's bitmap as a starting point for C; likewise, free B's bitmap - OR in objects for C, and so on... Rather than duplicating bitmaps and immediately freeing the original, we can just pass ownership from commit to commit. Note that this doesn't always work: - the recipient may be a merge which already has an intermediate bitmap from its other ancestor. In that case we have to OR our result into it. Note that the first ancestor to reach the merge does get to pass ownership, though. - we may have multiple children; we can only pass ownership to one of them However, it happens often enough and copying bitmaps is expensive enough that this provides a noticeable speedup. On a clone of linux.git, this reduces the time to generate bitmaps from 205s to 70s. This is about the same amount of time it took to generate bitmaps using our old "many traversals" algorithm (the previous commit measures the identical scenario as taking 63s). It unfortunately provides only a very modest reduction in the peak memory usage, though. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Dec 8, 2020 at 17:03 UTC 010e5eacfb004218087da054a61772da8fc40463
1 file changed +8 -2
pack-bitmap-write.c
+8 -2
@@ -333,6 +333,7 @@ void bitmap_writer_build(struct packing_data *to_pack)
333 struct commit *commit = bb.commits[i-1];
334 struct bb_commit *ent = bb_data_at(&bb.data, commit);
335 struct commit *child;
336 + int reused = 0;
337
338 fill_bitmap_commit(ent, commit);
339
@@ -348,10 +349,15 @@ void bitmap_writer_build(struct packing_data *to_pack)
349
350 if (child_ent->bitmap)
351 bitmap_or(child_ent->bitmap, ent->bitmap);
351 - else
352 + else if (reused)
353 child_ent->bitmap = bitmap_dup(ent->bitmap);
354 + else {
355 + child_ent->bitmap = ent->bitmap;
356 + reused = 1;
357 + }
358 }
354 - bitmap_free(ent->bitmap);
359 + if (!reused)
360 + bitmap_free(ent->bitmap);
361 ent->bitmap = NULL;
362 }
363 bitmap_builder_clear(&bb);