Re: [PATCH] branch: avoid slow strvec Coccinelle matching
- From
Junio C Hamano <gitster@pobox.com>
- Date
- Jul 24, 2026, 15:27 UTC
- Message-ID
- <xmqq33x89zn9.fsf@gitster.g>
- In-Reply-To
- <20260724091152.27794-2-tnyman@openai.com>
tnyman@openai.com writes:
Show 12 quoted lines
> From: Ted Nyman <tnyman@openai.com> > > The --delete-merged implementation declares a loop index at function > scope and reuses it to walk its strvec of upstreams and its list of > candidate branches. Coccinelle 1.1.1 spends hours matching this against > the separate_loop_index rule in tools/coccinelle/strvec.cocci, causing > the static-analysis job on 'seen' to reach its six-hour timeout. > ... > The CI failure reproduces locally with Coccinelle 1.1.1: applying > strvec.cocci to the original builtin/branch.c still times out with > "spatch --timeout 120". With this change, the same check completes in > 0.06 seconds.
Impressive. Nicely analyzed.
Even though this is very much like bending the code only to appease the checker, the resulting code is arguably better in this particular case, so I do not feel as bad as I have on other occasions when we had to work around deficiencies in our tools [*].
I see Harald already took this in the latest update. Thanks for working well together.
[*]
* Here, I do not blame Coccinelle alone. The performance bug is caused by a combination of Coccinelle and the 'strvec' check that makes it so inefficient. I wonder if there are ways to make the checks in 'strvec.cocci' more efficient?
Show 25 quoted lines
> diff --git a/builtin/branch.c b/builtin/branch.c
> index 42f2221547..2415a275ea 100644
> --- a/builtin/branch.c
> +++ b/builtin/branch.c
> @@ -797,10 +797,9 @@ static int delete_merged_branches(const struct strvec *upstreams,
> struct strbuf key = STRBUF_INIT;
> struct hashmap_iter iter;
> struct strmap_entry *entry;
> - size_t i;
> int ret = 0;
>
> - for (i = 0; i < upstreams->nr; i++)
> + for (size_t i = 0; i < upstreams->nr; i++)
> if (ref_filter_forked_add(&filter, upstreams->v[i]) < 0)
> die(_("'%s' is not a valid branch or pattern"),
> upstreams->v[i]);
> @@ -809,7 +808,7 @@ static int delete_merged_branches(const struct strvec *upstreams,
> filter.name_patterns = argv;
> filter_refs(&candidates, &filter, filter.kind);
>
> - for (i = 0; i < (size_t)candidates.nr; i++) {
> + for (size_t i = 0; i < (size_t)candidates.nr; i++) {
> const char *branch_refname = candidates.items[i]->refname;
> const char *branch_name;
> struct branch *branch;