Skip to content

Reserve vector capacity when array lengths are known - #739

Merged
liuzicheng1987 merged 2 commits into
getml:mainfrom
Altren:perf/reserve-array-capacity
Oct 16, 2026
Merged

liuzicheng1987 merged 2 commits into
getml:mainfrom
Altren:perf/reserve-array-capacity

Conversation

@Altren

@Altren Altren commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Array deserialization currently grows vectors incrementally even when the reader knows the number of elements. Pass that count to an optional shared reserve hook before parsing. Reservation failures become parse errors; fixed-capacity and associative containers retain their insertion behavior.

This applies to Avro, Boost.Serialization, Cap'n Proto, CBOR, Cereal, FlexBuffers, JSON, MessagePack, TOML, UBJSON, YAML, YAS, and Generic. BSON and XML do not expose a direct element count, so their readers are unchanged and remain in the benchmark as controls.

The vectors_read benchmark covers all serialized formats. It compares a single vector of 1,000 or 1,000,000 floats with 10,000 vectors of 64 floats. Setup, schema creation, and full round-trip validation are outside the timed loop. Serialized byte counts are reported.

Validation:

  • The relocation regression test fails on the original parser: 65 values
    cause 127 extra moves. These reallocations disappear with the change.
  • Serialized sizes are identical before and after.
  • Release AppleClang 21 on arm64 macOS; median of three alternating runs.

Performance for 10,000 vectors of 64 floats (CPU time; lower is better):

Format Before (ms) After (ms) Speedup Serialized bytes
Avro 12.6540 11.7457 1.08x 2,590,004
Boost.Serialization 5.9483 4.8930 1.22x 2,720,016
BSON (control) 6.2009 6.2808 0.99x 7,818,909
Cap’n Proto 7.9250 6.8062 1.16x 2,302,326
CBOR 16.2797 15.1113 1.08x 3,310,013
Cereal 6.2484 5.1808 1.21x 2,640,009
FlexBuffers 4.6498 3.5928 1.29x 3,489,272
JSON 6.6953 5.8021 1.15x 5,560,123
MessagePack 6.4588 5.7715 1.12x 3,310,012
TOML 199.8160 201.6540 0.99x 8,880,108
UBJSON 13.5427 12.5567 1.08x 3,360,018
XML (control) 39.2880 39.4100 1.00x 24,120,164
YAML 839.2200 853.7410 0.98x 13,070,118
YAS 4.3343 3.3883 1.28x 2,640,015

The largest measured gains are in FlexBuffers (1.29x), YAS (1.28x),
Boost.Serialization (1.22x), and Cereal (1.21x). Single million-element
vectors show little change (0.98–1.03x across formats); TOML and YAML do
not show a gain in these measurements. Small differences may be noise.
Serialized sizes are unchanged for every workload.

The benchmark is included in reflect-cpp-all-format-benchmarks and runs in
the Linux, macOS, and Windows CI benchmark summaries. Timing results are
informational rather than pass/fail thresholds. The move-count regression
tests deterministically check that vector growth does not add relocations.

Run:
./build/benchmarks/all/reflect-cpp-all-format-benchmarks --benchmark_filter=vectors_read

Pass array lengths through an optional reserve hook before parsing elements.
Reserve storage for growable sequence containers and return reservation
failures as parse errors. Fixed-capacity and associative containers keep
their existing insertion behavior.

Enable the hint in 12 format readers and Generic. Add per-reader move-count
regression coverage and all-format benchmarks for large and many short
vectors, including serialized size counters and CI summary entries.

Validated 933 tests and 42 benchmark cases across all 14 formats in the
all-format suite. Serialized sizes match the baseline. One existing UBJSON
test needed a local -Wno-error=deprecated-declarations workaround with the
Apple SDK; that build-only workaround is not part of this change.
@Altren

Altren commented Oct 14, 2026

Copy link
Copy Markdown
Contributor Author

CI failure is not related to my changes (some vcpkg issue) linux / (headers-C++20-gcc-14) (pull_request)
But I don't have rights to restart it

@liuzicheng1987

Copy link
Copy Markdown
Collaborator

@Altren no problem

@liuzicheng1987

Copy link
Copy Markdown
Collaborator

@Altren thanks for the contribution.

@liuzicheng1987
liuzicheng1987 merged commit 10580aa into getml:main Oct 16, 2026
176 checks passed
@Altren
Altren deleted the perf/reserve-array-capacity branch October 17, 2026 08:50
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.

2 participants