Skip to content

perf(array): pre-size Ap and Flatten results#190

Draft
nishantmehta wants to merge 1 commit into
IBM:mainfrom
nishantmehta:pr/array-presize
Draft

perf(array): pre-size Ap and Flatten results#190
nishantmehta wants to merge 1 commit into
IBM:mainfrom
nishantmehta:pr/array-presize

Conversation

@nishantmehta

Copy link
Copy Markdown
Contributor

Problem

array.Ap and array.Flatten both route through MonadChain, which grows the
result from nil; Ap additionally allocates an intermediate slice per function
(via MonadMap).

Change

Both output lengths are known up front — len(fab)*len(fa) for the applicative
cartesian product, and the sum of the inner slice lengths for flatten — so the
result is built in a single pre-sized allocation. Element order and values are
unchanged (the change is in array/generic, which the public array.Ap /
array.Flatten delegate to).

Result

Benchmarks (added), -benchmem -count=6:

benchmark allocs/op B/op ns/op
Ap before 6 800 155
Ap after 1 240 66
Flatten before 3 216 51
Flatten after 1 128 24

−83% / −67% allocations respectively.

Testing

go test -race ./array/... passes (existing tests cover element order/values).
BenchmarkAp and BenchmarkFlatten were added to demonstrate and guard the win.

array.Ap and array.Flatten both routed through MonadChain, which grows the
result from nil and (for Ap) allocates an intermediate slice per function.
Their output lengths are known up front -- len(fab)*len(fa) for the
applicative cartesian product and the sum of inner lengths for flatten -- so
build the result in a single pre-sized allocation.

Benchmarks (added):

  BenchmarkAp        6 -> 1 allocs/op (-83%), 155 -> 66 ns/op
  BenchmarkFlatten   3 -> 1 allocs/op (-67%),  51 -> 24 ns/op

Signed-off-by: Nishant Mehta <nishantmehta.n@gmail.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