Skip to content

perf(queries): cache bind pointer fields per struct type - #1480

Open
nohhyun wants to merge 1 commit into
aarondl:masterfrom
nohhyun:rubrik-ptr-slice-bind
Open

nohhyun wants to merge 1 commit into
aarondl:masterfrom
nohhyun:rubrik-ptr-slice-bind

Conversation

@nohhyun

@nohhyun nohhyun commented Sep 15, 2026

Copy link
Copy Markdown

bind() allocated every []*Struct element through makeStructPtr(), which walked each field of the struct type and parsed its boil tag looking for the "bind" pointer fields that need allocating. The struct type is fixed for the lifetime of a bind, so this recomputed the same answer on every row: a 1M-row query over a 20-column model ran 20M redundant tag parses.

The per-type mappingCache already caches column mappings, so the field scan moves there as bindPtrFields, built once in newMappingCache and consumed by the new newStructPtr method. It is fixed at construction time, so it is read without holding the cache mutex.

Binding 1000 rows, benchstat over 6 runs:

BindSmallPtrSlice     312.3µ -> 176.5µ   -43.50%
BindWidePtrSlice     1344.3µ -> 687.8µ   -48.83%

The []Struct paths and the allocation counts are unchanged, since the work removed was pure CPU.

Adds TestBind_InnerJoinPtrFields, which covers the allocation of ",bind" pointer fields. No existing test bound to a struct with one, despite it being the documented example on Bind.

bind() allocated every []*Struct element through makeStructPtr(), which
walked each field of the struct type and parsed its boil tag looking for
the ",bind" pointer fields that need allocating. The struct type is
fixed for the lifetime of a bind, so this recomputed the same answer on
every row: a 1M-row query over a 20-column model ran 20M redundant tag
parses.

The per-type mappingCache already caches column mappings, so the field
scan moves there as bindPtrFields, built once in newMappingCache and
consumed by the new newStructPtr method. It is fixed at construction
time, so it is read without holding the cache mutex.

Binding 1000 rows, benchstat over 6 runs:

    BindSmallPtrSlice     312.3µ -> 176.5µ   -43.50%
    BindWidePtrSlice     1344.3µ -> 687.8µ   -48.83%

The []Struct paths and the allocation counts are unchanged, since the
work removed was pure CPU.

Adds TestBind_InnerJoinPtrFields, which covers the allocation of ",bind"
pointer fields. No existing test bound to a struct with one, despite it
being the documented example on Bind.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@nohhyun

nohhyun commented Sep 15, 2026

Copy link
Copy Markdown
Author

It is a minor performance improvement but I believe the improvement is monotonic.
Please let me know.

I also wrote a small benchmark test - which I could add if folks thinks that is better.

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