Skip to content

Inline frequently used parsing functions - #742

Merged
liuzicheng1987 merged 2 commits into
getml:mainfrom
Altren:perf/inline-parsing-hot-paths
Oct 16, 2026
Merged

liuzicheng1987 merged 2 commits into
getml:mainfrom
Altren:perf/inline-parsing-hot-paths

Conversation

@Altren

@Altren Altren commented Oct 15, 2026

Copy link
Copy Markdown
Contributor

Reading arrays of structs can leave a chain of small parser calls out of line in optimized builds without LTO. Add explicit inlining hints to eleven frequently used parsing declarations so the compiler can optimize field assignment, result handling, and object construction together.

LTO can eliminate much of the same parser-call overhead automatically. Separate Cereal measurements with #738–#741 applied reduced read time from 35.51 ms to 14.84 ms by enabling LTO alone, without this patch. Those measurements used a different dataset from the table below. This PR targets builds without LTO.

The change covers shared struct/vector parsing, field assignment, missing-field handling, the C++20 rvalue Result::transform overload, and two Cereal reader methods. RFL_ALWAYS_INLINE selects __forceinline for MSVC, inline __attribute__((always_inline)) for GCC/Clang, and ordinary inline otherwise. Parsing logic, validation, error aggregation, cleanup, and the wire format are unchanged.

Benchmarks

Add six parser_inlining read cases to reflect-cpp-all-format-benchmarks and the Linux/macOS/Windows benchmark summaries. Each case reads a vector of 100,000 records with either two or sixteen float fields using ordinary APIs. Input generation, serialization, and equality checks happen outside timing; result destruction is included.

AppleClang 21, macOS arm64, Release -O3 -DNDEBUG, no LTO. Values are median CPU times from six alternating-order runs, with 0.1 s warmup and a 0.2 s measurement target per case. Both variants use ed67735; the after variant adds only this PR. None of #739–#741 is included in these measurements.

Format Fields per record Before read After read Speedup Serialized bytes
Cereal 2 2.808 ms 1.622 ms 1.73× 800,009
Cereal 16 41.892 ms 13.096 ms 3.20× 6,400,009
JSON 2 3.902 ms 2.689 ms 1.45× 3,683,353
JSON 16 49.787 ms 19.141 ms 2.60× 23,083,353
MessagePack 2 3.593 ms 2.643 ms 1.36× 2,500,014
MessagePack 16 56.701 ms 25.249 ms 2.25× 20,100,014

All six fixtures have byte-identical before/after output, and the patched reader successfully decodes the baseline fixtures. These are local microbenchmarks; gains depend on the compiler and input structure.

Compile time and code size

Compile each format's benchmark translation unit (both record widths) independently, without PCH or linking. Median CPU time from three alternating runs after a warmup:

Translation unit Before After Compile-time change Object __TEXT change
Cereal 1.390 s 1.371 s -1.4% -16.2%
JSON 1.468 s 1.536 s +4.6% -17.3%
MessagePack 1.338 s 1.304 s -2.5% -16.1%

These measurements cover three translation units, not a full build. Small timing differences can be noise; larger schemas and other compilers may behave differently. Object __TEXT includes code and read-only data, not the final executable size.

Validation

  • A separate -O0 -g -Wall -Werror smoke test passes for recursive types, multiple validation errors, and truncated input.

Run the new benchmarks with:

./build/benchmarks/all/reflect-cpp-all-format-benchmarks \
  --benchmark_filter=parser_inlining \
  --benchmark_min_warmup_time=0.1 \
  --benchmark_min_time=0.2s \
  --benchmark_repetitions=6

I got to the point where I made most clean optimizations for reflectcpp+Cereal vs raw Cereal speedup. I need to do few more tests, but currently it still reads 2.1x slower and writes 1.2x slower.
Later I will be able to share more complex data structure with benchmarks.

@liuzicheng1987

Copy link
Copy Markdown
Collaborator

Thanks for the contribution! This is excellent!

@liuzicheng1987
liuzicheng1987 merged commit 10fb6bb into getml:main Oct 16, 2026
176 checks passed
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