Performance regression in "update" hooks
From: Patrick Steinhardt <hidden>
Date: 2026-03-02 07:17:52
Hi,
Bencher has alerted me that there's been two performance regressions in
git-receive-pack(1) [1] and git-fetch(1) [2].
The first one is quite easy to reproduce with the benchmarks at [3] and
bisects to fc148b146a (receive-pack: convert update hooks to new API,
2026-01-28):
$ cd receive-refs
$ ./run --revisions /path/to/your/git/repo \
fc148b146ad41be71a7852c4867f0773cbfe1ff9~,fc148b146ad41be71a7852c4867f0773cbfe1ff9 \
--parameter-list refformat reftable \
--parameter-list refcount 10000
Benchmark 1: receive: many refs (refformat = reftable, refcount = 10000, revision = fc148b146ad41be71a7852c4867f0773cbfe1ff9~)
Time (mean ± σ): 182.0 ms ± 2.7 ms [User: 91.5 ms, System: 89.3 ms]
Range (min … max): 175.8 ms … 185.0 ms 15 runs
Benchmark 2: receive: many refs (refformat = reftable, refcount = 10000, revision = fc148b146ad41be71a7852c4867f0773cbfe1ff9)
Time (mean ± σ): 484.6 ms ± 27.6 ms [User: 176.2 ms, System: 376.1 ms]
Range (min … max): 406.2 ms … 495.1 ms 10 runs
Summary
receive: many refs (refformat = reftable, refcount = 10000, revision = fc148b146ad41be71a7852c4867f0773cbfe1ff9~) ran
2.66 ± 0.16 times faster than receive: many refs (refformat = reftable, refcount = 10000, revision = fc148b146ad41be71a7852c4867f0773cbfe1ff9)
I've Cc'd Adrian.
The other performance regression seems to be present in both
git-receive-pack(1) and git-fetch(1) and happens between e6e9f13364
(Sync with 'master', 2026-02-25) and ebd1da8b75 (Merge branch
'cx/fetch-display-ubfix' into next, 2026-02-26). It took me a while to
reproduce as my local Git configuration was hiding the regression, but I
have been able to bisect this to 452b12c2e0 (builtin/maintenance: use
"geometric" strategy by default, 2026-02-24).
The problem here is rather simple though. The benchmark fetches 10,000
refs into the repository, and before the commit we didn't do anything
about them. But after the commit we now have per-data-structure tasks,
and the result is that we thus end up packing refs. That's also why the
regression isn't present in the reftable backend, as it wouldn't need
any optimization.
So I'd consider this to be a bug in the benchmarking infrastructure
itself that I'll fix by disabling auto-maintenance.
Thanks!
Patrick
[1]: https://bencher.dev/perf/git?lower_value=false&upper_value=false&lower_boundary=false&upper_boundary=false&x_axis=date_time&branches=595859eb-071c-48e9-97cf-195e0a3d6ed1&testbeds=02dcb8ad-6873-494c-aabc-9a6237601308&benchmarks=e3553193-aefc-40a4-8816-9c1bdc1838a4%2Ccd00a2a1-0fd1-416a-9812-cfd3e9b4fdb8&measures=63dafffb-98c4-4c27-ba43-7112cae627fc&start_time=1765177145759&end_time=1772434745759&tab=plots&plot=6887f804-2bbc-4219-8211-55b6440fd5c0&plots_search=6887f804-2bbc-4219-8211-55b6440fd5c0&key=true&reports_per_page=4&branches_per_page=8&testbeds_per_page=8&benchmarks_per_page=8&plots_per_page=8&reports_page=1&branches_page=1&testbeds_page=1&benchmarks_page=1&plots_page=1
[2]: https://bencher.dev/perf/git?lower_value=false&upper_value=false&lower_boundary=false&upper_boundary=false&x_axis=date_time&branches=595859eb-071c-48e9-97cf-195e0a3d6ed1&testbeds=02dcb8ad-6873-494c-aabc-9a6237601308&benchmarks=196480c8-64d1-4768-a3e2-ac3c5f75a26e%2Cb422ed57-2b09-474b-a85f-2d71ba7ca46b&measures=63dafffb-98c4-4c27-ba43-7112cae627fc&start_time=1765177141331&end_time=1772434741331&tab=plots&plot=4134acc8-9194-454c-9d71-f41b44ab969d&plots_search=4134acc8-9194-454c-9d71-f41b44ab969d&key=true&reports_per_page=4&branches_per_page=8&testbeds_per_page=8&benchmarks_per_page=8&plots_per_page=8&reports_page=1&branches_page=1&testbeds_page=1&benchmarks_page=1&plots_page=1
[3]: https://gitlab.com/gitlab-org/data-access/git/benchmarks