[PATCH] Add pg_lfind8_nonzero()

Started by cca55078 months ago5 messageshackers
Beta feature

Hackorum builds and tests every patch posted to the lists, not only commitfest submissions. This is Hackorum's own CI rather than the PostgreSQL project's, and it is still under testing - please report anything that looks wrong.

appliessuccessCI history

You can run a PostgreSQL built from this patch straight from Docker, with no checkout and no build:

docker run --rm -p 5432:5432 ghcr.io/hackorum-dev/postgres-patch:t52891
psql -h localhost -U postgres

Built from patchset v1 (message #1), August 25, 2026 at 02:08 AM.

Every patchset is also pushed to a branch of our PostgreSQL fork, so you can check out the same tree CI built. Without a PostgreSQL checkout:

git clone --branch t52891_1 https://github.com/hackorum-dev/postgres.git

In a checkout you already have, add the fork once:

git remote add hackorum https://github.com/hackorum-dev/postgres.git

then, for this patchset and every later one:

git fetch hackorum t52891_1 && git checkout t52891_1

Patchset v1 (message #1) is on t52891_1

Jump to latest
#1cca5507
cca5507@qq.com

Hi hackers,

I'd like to add pg_lfind8_nonzero() to optimize some code like this:

```
for (i = 0; i < numberOfAttributes; i++)
{
if (isnull[i])
{
hasnull = true;
break;
}
}
```

With pg_lfind8_nonzero(), we can write the code like this:

```
if (likely(numberOfAttributes > 0))
hasnull = pg_lfind8_nonzero((uint8 *) isnull, numberOfAttributes);
```

The pg_lfind8_nonzero() is faster because we can handle 8 bool values at a time.

v1-0001 add the pg_lfind8_nonzero().

v1-0002 use the pg_lfind8_nonzero() in some places.

v1-0003 add a extension "test_patch" only for testing, the test like this:

```
for (i = 0; i < 1000; i++)
{
for (int j = 0; j < natts; j++)
{
if (isnull[j])
{
hasnull = true;
break;
}
}
}
=======================
for (i = 0; i < 1000; i++)
{
if (likely(natts > 0))
hasnull = pg_lfind8_nonzero((uint8 *) isnull, natts);
}
```

create extension test_patch;
# 4 is the natts
select test_head(4);
select test_patch(4);

Test result:
natts: 4 head: 1984ns patch: 2094ns
natts: 8 head: 3196ns patch: 641ns
natts: 16 head: 4589ns patch: 752ns
natts: 32 head: 8036ns patch: 1152ns
natts: 64 head: 19367ns patch: 2455ns
natts: 128 head: 33445ns patch: 4018ns

Looking forward to your comments!

--
Regards,
ChangAo Chen

Attachments:

t52891_1
v1-0001-Add-pg_lfind8_nonzero.patchapplication/octet-stream; charset=utf-8; name=v1-0001-Add-pg_lfind8_nonzero.patchDownload+68-1
v1-0002-Use-pg_lfind8_nonzero.patchapplication/octet-stream; charset=utf-8; name=v1-0002-Use-pg_lfind8_nonzero.patchDownload+11-35
v1-0003-Test-pg_lfind8_nonzero.patch.tmpapplication/octet-stream; charset=utf-8; name=v1-0003-Test-pg_lfind8_nonzero.patch.tmpDownload+102-1
#2Andres Freund
andres@anarazel.de
In reply to: cca5507 (#1)
Re: [PATCH] Add pg_lfind8_nonzero()

Hi,

On 2025-12-14 21:33:00 +0800, cca5507 wrote:

Hi hackers,

I'd like to add pg_lfind8_nonzero() to optimize some code like this:

```
for (i = 0; i < numberOfAttributes; i++)
{
if (isnull[i])
{
hasnull = true;
break;
}
}
```

Is code like this ever actually relevant for performance? In cases where the
compiler can't also optimize the code? Unless it is a legitimate bottleneck,
adding more complicated code to optimize the case doesn't make sense.

create extension test_patch;
# 4 is the natts
select test_head(4);
select test_patch(4);

Test result:
natts: 4 head: 1984ns patch: 2094ns
natts: 8 head: 3196ns patch: 641ns
natts: 16 head: 4589ns patch: 752ns
natts: 32 head: 8036ns patch: 1152ns
natts: 64 head: 19367ns patch: 2455ns
natts: 128 head: 33445ns patch: 4018ns

Looking forward to your comments!

The benchmark really should show performance benefits in at least somewhat
realistic cases (i.e. real users of the functions, even if the workload is a
bit more extreme than it'd be most of the time).

Greetings,

Andres

#3cca5507
cca5507@qq.com
In reply to: Andres Freund (#2)
Re: [PATCH] Add pg_lfind8_nonzero()

Hi,

Thank you for your reply!

Is code like this ever actually relevant for performance? In cases where the
compiler can't also optimize the code? Unless it is a legitimate bottleneck,
adding more complicated code to optimize the case doesn't make sense.

I just think the patch isn't that complicated.

The benchmark really should show performance benefits in at least somewhat
realistic cases (i.e. real users of the functions, even if the workload is a
bit more extreme than it'd be most of the time).

Yeah, this makes sense to me. Maybe I need to think more on it.

--
Regards,
ChangAo Chen

#4Peter Eisentraut
peter_e@gmx.net
In reply to: cca5507 (#1)
Re: [PATCH] Add pg_lfind8_nonzero()

On 14.12.25 14:33, cca5507 wrote:

With pg_lfind8_nonzero(), we can write the code like this:

```
if (likely(numberOfAttributes > 0))
hasnull = pg_lfind8_nonzero((uint8 *) isnull, numberOfAttributes);
```

The pg_lfind8_nonzero() is faster because we can handle 8 bool values at a time.

Maybe you could try popcount for this?

hasnull = (pg_popcount((char *) isnull, numberOfAttributes) > 0);

#5cca5507
cca5507@qq.com
In reply to: Peter Eisentraut (#4)
Re: [PATCH] Add pg_lfind8_nonzero()

Hi,

Maybe you could try popcount for this?

     hasnull = (pg_popcount((char *) isnull, numberOfAttributes) > 0);

It seems that pg_popcount() cannot early return when we find a nonzero value, so I don't
think it's a good choice for this case.

--
Regards,
ChangAo Chen