Re: [PATCH 11/24] pack-bitmap: simplify `reuse_partial_packfile_from_bitmap()` signature
- From
Taylor Blau <me@ttaylorr.com>
- Date
- Dec 7, 2023, 14:36 UTC
- Message-ID
- <ZXHYetGa/e1VjwLn@nand.local>
- In-Reply-To
- <ZXHE7_KwukSRBET1@tanuki>
On Thu, Dec 07, 2023 at 02:13:19PM +0100, Patrick Steinhardt wrote:
Show 11 quoted lines
> > + if (reuse_packfile) {
> > + reuse_packfile_objects = bitmap_popcount(reuse_packfile_bitmap);
> > + if (!reuse_packfile_objects)
> > + BUG("expected non-empty reuse bitmap");
>
> We're now re-computing `bitmap_popcount()` for the bitmap a second time.
> But I really don't think this is ever going to be a problem in practice
> given that it only does a bunch of math. Any performance regression
> would thus ultimately be drowned out by everything else.
>
> In other words: this is probably fine.I definitely agree that any performance regression from calling bitmap_popcount() twice would be drowned out by the rest of what pack-objects is doing.
For what it's worth:
- The bitmap_popcount() call is a loop over ewah_bit_popcount64() for each of the allocated words. And the latter is more or less three copies of:
b7: 55 55 55
ba: 48 23 45 f8 and -0x8(%rbp),%rax
be: 48 8b 55 f8 mov -0x8(%rbp),%rdx
c2: 48 89 d1 mov %rdx,%rcx
c5: 48 d1 e9 shr %rcx
c8: 48 ba 55 55 55 55 55 movabs $0x5555555555555555,%rdx
cf: 55 55 55
d2: 48 21 ca and %rcx,%rdx
d5: 48 01 d0 add %rdx,%rax
d8: 48 89 45 f8 mov %rax,-0x8(%rbp)
dc: 48 b8 33 33 33 33 33 movabs $0x3333333333333333,%raxFollowed by:
144: 48 0f af c2 imul %rdx,%rax
148: 48 c1 e8 38 shr $0x38,%rax
14c: 5d pop %rbp
14d: c3 retWith the usual x86 ABI preamble and postamble. So this should be an extremely cheap function to compute.
- But, the earlier bitmap_popcount() call in reuse_partial_packfile_from_bitmap() is not necessary, since we only care whether or not there are _any_ bits set in the bitmap, not how many of them there are.
So we could write something like `bitmap_empty(reuse)` instead, which would be much cheaper (again, not that I think we'll notice this either way, but throwing away the result of bitmap_popcount() and calling it twice does leave me a little unsatisfied).
So I think we could reasonably do something like:
--- 8< ---
diff --git a/ewah/bitmap.c b/ewah/bitmap.c index 7b525b1ecd..ac7e0af622 100644 --- a/ewah/bitmap.c +++ b/ewah/bitmap.c @@ -169,6 +169,15 @@ size_t bitmap_popcount(struct bitmap *self) return count; } +int bitmap_is_empty(struct bitmap *self) +{ + size_t i; + for (i = 0; i < self->word_alloc; i++) + if (self->words[i]) + return 0; + return 1; +} + int bitmap_equals(struct bitmap *self, struct bitmap *other) { struct bitmap *big, *small; diff --git a/ewah/ewok.h b/ewah/ewok.h index 7eb8b9b630..c11d76c6f3 100644 --- a/ewah/ewok.h +++ b/ewah/ewok.h @@ -189,5 +189,6 @@ void bitmap_or_ewah(struct bitmap *self, struct ewah_bitmap *other); void bitmap_or(struct bitmap *self, const struct bitmap *other); size_t bitmap_popcount(struct bitmap *self); +int bitmap_is_empty(struct bitmap *self); #endif diff --git a/pack-bitmap.c b/pack-bitmap.c index 614fc09a4e..e50b322779 100644 --- a/pack-bitmap.c +++ b/pack-bitmap.c @@ -2045,7 +2045,7 @@ void reuse_partial_packfile_from_bitmap(struct bitmap_index *bitmap_git, reuse_partial_packfile_from_bitmap_1(bitmap_git, packs, reuse); - if (!bitmap_popcount(reuse)) { + if (bitmap_is_empty(reuse)) { free(packs); bitmap_free(reuse); return; --- >8 --- Thanks, Taylor