git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH v2 3/3] connected: implement connectivity check using bitmaps

From
Taylor Blau <me@ttaylorr.com>
Date
Jul 2, 2021, 17:44 UTC
Message-ID
<YN9QbEaWgP09PfeD@nand.local>
In-Reply-To
<YNwE3wES3iv+Xynp@coredump.intra.peff.net>
On Wed, Jun 30, 2021 at 01:45:03AM -0400, Jeff King wrote:
> That implies to me that yes, it really is saving time, especially in the
> cold-cache case. But if you have to do any actual fill-in traversal, the
> benefits get totally lost in the noise. _Especially_ in the cold-cache
> case, because then we're faulting in the actual object data, etc.

That's definitely true. I would say that any patches in this direction would have the general sense of "this helps in some cases where we don't have to do much traversal by eliminating an unnecessarily eager part of loading bitmaps, and does not make anything worse when the bitmap coverage is incomplete (and requires traversing)."

I would add that these effects change with the size of the bitmap. Let's just consider the "count the number of objects in a bitmapped commit". On my local copy of the kernel, I see a relatively modest improvement:

    $ tip=2ab38c17aac10bf55ab3efde4c4db3893d8691d2
    $ hyperfine \
      'GIT_READ_COMMIT_TABLE=0 git.compile rev-list --count --objects --use-bitmap-index $tip' \
      'GIT_READ_COMMIT_TABLE=1 git.compile rev-list --count --objects --use-bitmap-index $tip' \
      --warmup=3
    Benchmark #1: GIT_READ_COMMIT_TABLE=0 git.compile rev-list --count --objects --use-bitmap-index $tip
      Time (mean ± σ):      21.5 ms ±   5.6 ms    [User: 8.7 ms, System: 12.7 ms]
      Range (min … max):    12.4 ms …  34.2 ms    170 runs
    Benchmark #2: GIT_READ_COMMIT_TABLE=1 git.compile rev-list --count --objects --use-bitmap-index $tip
      Time (mean ± σ):      10.6 ms ±   1.6 ms    [User: 7.1 ms, System: 3.5 ms]
      Range (min … max):     4.5 ms …  11.9 ms    258 runs

but on my copy of the kernel's fork network repo (that containing all of torvalds/linux's objects, as well as all of its fork's objects, too), the magnitude of the effect is much bigger:

    Benchmark #1: GIT_READ_COMMIT_TABLE=0 git.compile rev-list --count --objects --use-bitmap-index $tip
      Time (mean ± σ):     332.3 ms ±  12.6 ms    [User: 210.4 ms, System: 121.8 ms]
      Range (min … max):   322.7 ms … 362.4 ms    10 runs
    Benchmark #2: GIT_READ_COMMIT_TABLE=1 git.compile rev-list --count --objects --use-bitmap-index $tip
      Time (mean ± σ):     260.0 ms ±   9.3 ms    [User: 191.0 ms, System: 69.0 ms]
      Range (min … max):   250.4 ms … 272.8 ms    11 runs

That's a more modest 1.28x improvement (versus 2.03x in just linux.git), but the overall magnitude is much bigger.

This is basically an effect of the bitmaps themselves. In the latter example, there are more bitmaps (around 1.6k of them, versus just over 500 in my copy of just the kernel), and each of them are much wider (because there are far more objects, 40.2M versus just 7.8M). So there is more work to do, and the page cache is less efficient for us because we can't fit as much of the .bitmap file in the page cache at once.

Show 5 quoted lines
> By the way, one other thing I noticed is that having a fully-build
> commit-graph also made a big difference (much bigger than this patch),
> especially for the non-bitmapped commit. Which makes sense, since it is
> saving us from loading commit objects from disk during fill-in
> traversal.

Likewise having an reverse index helps a lot, too. That radix sort scales linearly with the number of objects in the bitmapped pack (plus you're paying the cost to allocate more heap, etc).

This clouded up some of my timings in p5310, which made me think that it would be a good idea to `git config pack.writeReverseIndex true` in the setup for those tests, but an even better direction would be to change the default of pack.writeReverseIndex to true everywhere.

Show 9 quoted lines
> So I dunno. There's absolutely savings for some cases, but I suspect in
> practice it's not going to really be noticeable. Part of me says "well,
> if it ever provides a benefit and there isn't a downside, why not?". So
> just devil's advocating on downsides for a moment:
>
>   - there's some extra complexity in the file format and code to read
>     and write these (and still fall back to the old system when they're
>     absent). I don't think it's a deal-breaker, as it's really not that
>     complicated a feature.

I agree with both of these. The complexity is manageable, I think, especially since I dropped support for the extended offset table (having a bitmap file that is >2GiB seems extremely unlikely to me, and it's possible to add support for it in the future) and fanout table (there are usually less than <1k commits with bitmaps, so a 256-entry fanout table doesn't seem to help much in benchmarking).

So what's left of the format is really just:
  - a table of object id's
  - a table of (uint32_t, uint32_t) tuples describing the (short) offset
    of the bitmap, and an index position of the xor'd bitmap (if one
    exists).
Show 9 quoted lines
>   - we're using extra bytes on disk (and the associated cold block cache
>     effects there). It's not very many bytes, though (I guess 20 for the
>     hash, plus a few offset integers; if we wanted to really
>     penny-pinch, we could probably store 32-bit pointers to the hashes
>     in the associated .idx file, at the cost of an extra level of
>     indirection while binary searching). But that is only for a few
>     hundred commits that are bitmapped, not all of them. And it's
>     balanced by not needing to allocate a similar in-memory lookup table
>     in each command. So it's probably a net win.
Worth benchmarking, at least.

I'll be offline for the next ~week and a half for my wedding, but I'll post some patches to the list shortly after I get back.

Thanks, Taylor

Previous: Jeff KingNext: Jeff King
Message 19 of 64 in “Speed up connectivity checks via bitmaps”
  1. 0/3 Speed up connectivity checks via bitmapsPatrick Steinhardt, Jun 28, 2021
  2. 1/3 p5400: add perf tests for git-receive-pack(1)Patrick Steinhardt, Jun 28, 2021
  3. Ævar Arnfjörð BjarmasonJun 28, 2021
  4. Patrick SteinhardtJun 29, 2021
  5. Ævar Arnfjörð BjarmasonJun 29, 2021
  6. 2/3 receive-pack: skip connectivity checks on delete-only commandsPatrick Steinhardt, Jun 28, 2021
  7. Ævar Arnfjörð BjarmasonJun 28, 2021
  8. Ævar Arnfjörð BjarmasonJun 28, 2021
  9. Patrick SteinhardtJun 29, 2021
  10. Jeff KingJun 30, 2021
  11. Jeff KingJun 30, 2021
  12. Patrick SteinhardtJun 30, 2021
  13. 3/3 connected: implement connectivity check using bitmapsPatrick Steinhardt, Jun 28, 2021
  14. Taylor BlauJun 28, 2021
  15. Taylor BlauJun 29, 2021
  16. Jeff KingJun 30, 2021
  17. Taylor BlauJun 30, 2021
  18. Jeff KingJun 30, 2021
  19. Taylor BlauJul 2, 2021
  20. Jeff KingJul 2, 2021
  21. Jeff KingJun 30, 2021
  22. Patrick SteinhardtJul 20, 2021
  23. 0/4 Speed up connectivity checksPatrick Steinhardt, Aug 2, 2021
  24. 1/4 connected: do not sort input revisionsPatrick Steinhardt, Aug 2, 2021
  25. Ævar Arnfjörð BjarmasonAug 2, 2021
  26. Patrick SteinhardtAug 3, 2021
  27. Ævar Arnfjörð BjarmasonAug 4, 2021
  28. Junio C HamanoAug 2, 2021
  29. Patrick SteinhardtAug 3, 2021
  30. Junio C HamanoAug 3, 2021
  31. 2/4 revision: stop retrieving reference twicePatrick Steinhardt, Aug 2, 2021
  32. Ævar Arnfjörð BjarmasonAug 2, 2021
  33. 3/4 revision: avoid loading object headers multiple timesPatrick Steinhardt, Aug 2, 2021
  34. Ævar Arnfjörð BjarmasonAug 2, 2021
  35. Patrick SteinhardtAug 5, 2021
  36. Junio C HamanoAug 2, 2021
  37. Patrick SteinhardtAug 3, 2021
  38. Patrick SteinhardtAug 6, 2021
  39. 4/4 revision: avoid hitting packfiles when commits are in commit-graphPatrick Steinhardt, Aug 2, 2021
  40. Junio C HamanoAug 2, 2021
  41. Patrick SteinhardtAug 3, 2021
  42. Junio C HamanoAug 3, 2021
  43. Patrick SteinhardtAug 5, 2021
  44. Junio C HamanoAug 5, 2021
  45. Ævar Arnfjörð BjarmasonAug 4, 2021
  46. 0/6 Speed up connectivity checksPatrick Steinhardt, Aug 5, 2021
  47. 1/6 revision: separate walk and unsorted flagsPatrick Steinhardt, Aug 5, 2021
  48. Junio C HamanoAug 5, 2021
  49. 2/6 connected: do not sort input revisionsPatrick Steinhardt, Aug 5, 2021
  50. Junio C HamanoAug 5, 2021
  51. Patrick SteinhardtAug 6, 2021
  52. Junio C HamanoAug 6, 2021
  53. 3/6 revision: stop retrieving reference twicePatrick Steinhardt, Aug 5, 2021
  54. 4/6 revision: avoid loading object headers multiple timesPatrick Steinhardt, Aug 5, 2021
  55. 5/6 commit-graph: split out function to search commit positionPatrick Steinhardt, Aug 5, 2021
  56. 6/6 revision: avoid hitting packfiles when commits are in commit-graphPatrick Steinhardt, Aug 5, 2021
  57. 0/5 Speed up connectivity checksPatrick Steinhardt, Aug 9, 2021
  58. Patrick SteinhardtAug 9, 2021
  59. 0/5 Speed up connectivity checksPatrick Steinhardt, Aug 9, 2021
  60. 1/5 revision: separate walk and unsorted flagsPatrick Steinhardt, Aug 9, 2021
  61. 2/5 connected: do not sort input revisionsPatrick Steinhardt, Aug 9, 2021
  62. 3/5 revision: stop retrieving reference twicePatrick Steinhardt, Aug 9, 2021
  63. 4/5 commit-graph: split out function to search commit positionPatrick Steinhardt, Aug 9, 2021
  64. 5/5 revision: avoid hitting packfiles when commits are in commit-graphPatrick Steinhardt, Aug 9, 2021

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.