Skip to content

perf(arrow/array): append fixed-width nulls in bulk - #1173

Open
fallintoplace wants to merge 4 commits into
apache:mainfrom
fallintoplace:perf/arrow-fixed-width-append-nulls
Open

perf(arrow/array): append fixed-width nulls in bulk#1173
fallintoplace wants to merge 4 commits into
apache:mainfrom
fallintoplace:perf/arrow-fixed-width-append-nulls

Conversation

@fallintoplace

Copy link
Copy Markdown
Contributor

Rationale for this change

Fixed-width builders currently implement AppendNulls by calling AppendNull for every value. Large batches repeatedly reserve capacity, update the validity bitmap, and update builder counters.

What changes are included in this PR?

  • Reserve capacity once for a null batch.
  • Clear the validity range in bulk.
  • Update the length and null count once.
  • Advance fixed-size binary value storage once.
  • Keep the existing scalar path when appending one null.
  • Update both the numeric builder template and generated source.
  • Add shared correctness tests and benchmarks for representative fixed-width builders.

This only changes AppendNulls. Empty-value appends are separate because their value bytes must also be zeroed.

Apple M1 Pro results for 65,536 nulls with -cpu=1:

Builder Before After Speedup Allocs
Int32 252 us 68.2 us 3.70x 23 to 5
Int64 366 us 169 us 2.17x 23 to 5
Decimal128 574 us 259 us 2.22x 25 to 7
Timestamp 424 us 176 us 2.41x 24 to 6
Boolean 178 us 6.92 us 25.7x 19 to 5
FixedSizeBinary(16) 606 us 327 us 1.85x 28 to 7

Are these changes tested?

Yes.

  • go test ./arrow/...
  • go test -race ./arrow/array
  • go vet -composites=false ./arrow/array
  • Regenerated the numeric builders and verified there is no diff.
  • Cross-compiled the array tests for linux/amd64 and linux/s390x.

Are there any user-facing changes?

No.

@fallintoplace
fallintoplace force-pushed the perf/arrow-fixed-width-append-nulls branch from 95fa3a5 to e52e43e Compare August 11, 2026 21:27
@fallintoplace
fallintoplace marked this pull request as ready for review August 12, 2026 18:41
@fallintoplace
fallintoplace marked this pull request as draft August 12, 2026 18:53
@fallintoplace
fallintoplace marked this pull request as ready for review August 12, 2026 20:51
zeroshade pushed a commit that referenced this pull request Aug 14, 2026
…#1183)

## What does this PR do?

- reserves fixed-size list parent slots once in `AppendNulls` and
`AppendEmptyValues`
- updates the parent validity bitmap in bulk
- appends all child null or empty values with one bulk builder call

The child append count is `listSize * n`, so the parent and child
lengths stay in sync.

## Why?

Both methods currently loop over every parent value. Each parent append
also loops over every child value.

This removes the parent loop and lets child builders use their bulk
append paths. The change is independent, but it also composes with #1173
and #1180.

## Benchmarks

Apple M1 Pro, 65,536 `FixedSizeList<Int32>` rows, `GOMAXPROCS=1`.

Standalone on `main`:

| list width | nulls before | nulls after | change | empty before |
empty after | change |
| ---: | ---: | ---: | ---: | ---: | ---: | ---: |
| 4 | 1.10 ms | 0.86 ms | -22% | 1.55 ms | 1.07 ms | -31% |
| 16 | 3.76 ms | 2.74 ms | -27% | 5.43 ms | 3.90 ms | -28% |
| 64 | 13.03 ms | 11.07 ms | -15% | 19.35 ms | 14.86 ms | -23% |

With #1173 and #1180 applied underneath:

| list width | nulls before | nulls after | change | empty before |
empty after | change |
| ---: | ---: | ---: | ---: | ---: | ---: | ---: |
| 4 | 1.56 ms | 0.18 ms | -88% | 2.01 ms | 0.20 ms | -90% |
| 16 | 4.69 ms | 0.33 ms | -93% | 6.89 ms | 0.42 ms | -94% |
| 64 | 16.27 ms | 0.74 ms | -95% | 22.18 ms | 0.92 ms | -96% |

```text
GOMAXPROCS=1 go test ./arrow/array -run '^$' -bench '^BenchmarkFixedSizeListBuilderBulkAppend$/(nulls|empty)/rows=65536/width=(4|16|64)$' -benchmem -benchtime=300ms -count=5
```

## Tests

- added coverage for unaligned parent validity bits
- verifies parent validity and null counts
- verifies child length, null slots, and zero-valued empty slots
- ran `go test ./arrow/...`
- ran `go test -race ./arrow/array`
- ran `go vet ./arrow/array`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant