Skip to content

Add opt-in slice presize (//lightning:presize directive + ,presize tag)#7

Open
JohanLindvall wants to merge 4 commits into
mainfrom
presize
Open

Add opt-in slice presize (//lightning:presize directive + ,presize tag)#7
JohanLindvall wants to merge 4 commits into
mainfrom
presize

Conversation

@JohanLindvall

Copy link
Copy Markdown
Owner

What

Adds an opt-in presize for slices of leaf-collection structs: preallocate a slice to its counted element length (one make) instead of letting it grow by append-doubling. Enabled two ways:

  • //lightning:presize — type directive, applies to every eligible slice the root reaches.
  • ,presize — json-tag option, per-field; propagates through slices/maps/pointers and stops at struct boundaries, exactly like nocopy/lax.
//lightning:presize
type Doc struct { ... }          // whole-type

type Doc struct {                // or surgically, per field
    Areas []struct{...} `json:"areas,presize"`
}

Why off by default

It's a space-for-time trade. Measured with ,presize on citm's areas field:

metric vs base
allocs/op −54%
B/op −46%
time +5.6…7.6%

The CountArrayElements scan doubles the per-element walk, which costs more wall-time than the reallocations it saves on tiny (~30-byte) elements — so on the time-focused microbenchmarks it's a small loss. It's a win on time too when arrays are large (marine_ik bones[].pos: −3.8% time, −31% B/op). The split is array/element-size dependent and not statically decidable, so it's an explicit opt-in rather than a cost heuristic — aimed at long-running services that care about GC pressure.

Safety

structSkipIsCheap gains a relaxed arg (gated by isLeafType) that admits structs whose only non-flat fields are 1-D collections of scalars/strings/any (citm areas[].blockIds is a []any that's always []). It still rejects collection-of-collection and collection-of-struct, so the multi-dimensional coordinate arrays slicePresize deliberately skips (the documented +155% disaster on canada/large-json) are never presized regardless of the directive. The flag threads through field/valueDecoder/sliceDecoder/arrayDecoder/mapDecoder with a Presize suffix/memo-key bit so tagged and untagged slices of the same type get distinct decoders.

Tests

  • TestPresizeDirective — directive presizes leaf-collection slices, leaves multi-dim arrays correct, handles empty/non-empty/null.
  • TestPresizeTag — tagged vs untagged slices decode identically.
  • Full suite green; generator runs clean over the whole bench corpus; gofmt clean.

CLAUDE.md updated (directive list, slicePresize opt-in entry with numbers + rationale, cross-ref from the "tried and rejected" entry).

🤖 Generated with Claude Code

JohanLindvall and others added 2 commits June 24, 2026 14:15
Presize a slice whose struct element holds only flat scalars and
one-dimensional leaf collections (scalars/strings/any) to its counted
length, replacing append-doubling reallocations with a single make.
This is off by default and opt-in via either a //lightning:presize type
directive (whole root) or a ,presize json-tag option (per field,
propagating through slices/maps/pointers and stopping at struct
boundaries, like nocopy/lax).

structSkipIsCheap gains a relaxed arg (gated by isLeafType) that admits
leaf-collection structs while still rejecting collection-of-collection
and collection-of-struct, so the multi-dimensional coordinate arrays
slicePresize deliberately skips are never presized regardless of the
directive. The presize flag threads through
field/valueDecoder/sliceDecoder/arrayDecoder/mapDecoder with a Presize
suffix/memo-key bit so tagged and untagged slices of the same type get
distinct decoders.

Measured (citm areas tagged): allocs -54%, B/op -46%, time +5.6..7.6% —
the count scan over tiny elements costs more wall-time than the reallocs
it saves, hence opt-in for callers that value the allocation cut (e.g.
GC pressure in a long-running service). marine_ik bones is the case
where it wins on time too (-3.8%, -31% B/op); the split is
array/element-size dependent and not statically decidable.

Covered by conformance TestPresizeDirective and TestPresizeTag.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Tag the seatCategories[].areas field with ,presize. Its element is a
struct of a scalar (areaId) plus a 1-D leaf collection (blockIds []any,
always empty in the corpus), so presizing it to the counted length
replaces the append-doubling reallocations (decodeAreas was ~19% of the
decode in growslice) with a single make: allocs -54%, B/op -46%, at
+5.6..7.6% decode time.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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