Skip to content

Avoid copying Cereal input buffers before deserialization - #757

Merged
liuzicheng1987 merged 2 commits into
munich-data-engineering:mainfrom
Altren:perf/nonowning-input-stream
Oct 25, 2026
Merged

liuzicheng1987 merged 2 commits into
munich-data-engineering:mainfrom
Altren:perf/nonowning-input-stream

Conversation

@Altren

@Altren Altren commented Oct 24, 2026

Copy link
Copy Markdown
Contributor

Cereal's read(bytes) copies the entire input into a string-backed stream before decoding it. Replace that stream with a non-owning input buffer, removing the extra allocation and copy for byte-buffer reads and for load() calls that use them. The public APIs, binary representation, and bulk file loading remain unchanged.

The shared internal buffer exposes only an input area, handles empty/null buffers without null-pointer arithmetic, and bounds block reads to the supplied extent. Boost.Serialization reuses it in place of its existing non-owning MemBuf; Boost already avoided the owning input copy.

Read time

Compared upstream main 26c66bfa (including #753) with this change on macOS arm64timings.

Input Bytes No-LTO speedup LTO speedup
Cereal: 4,194,304 uint64 values 33,554,441 1.83× 1.83×
Cereal: 100,000 Record16 6,400,009 — 1.14×
Cereal: Dataset 36,008,009 1.03× 1.29×
Boost: 4,194,304 uint64 values (control) 33,554,440 — —

A dash denotes a time difference below 3%. Record16 has sixteen float fields. Dataset contains 500 groups, each with 3,000 two-double points and 3,000 uint64 IDs. Numeric vectors already use bulk arithmetic I/O in both versions.

Peak memory

Input Main peak, MiB New peak, MiB Reduction, MiB
Cereal: 4,194,304 uint64 values 97.67 65.62 32.05
Cereal: 100,000 Record16 20.02 13.88 6.14
Cereal: Dataset 106.45 72.09 34.36
Boost: 4,194,304 uint64 values (control) 65.64 65.64 0.00

Peak resident memory from three fresh processes per case/configuration, measured with macOS getrusage; table shows the no-LTO medians. This includes the encoded input, decoded output, and process/runtime overhead. Fixtures are generated in a separate process, and no timed benchmark runs first. These are whole-process peaks, not exact allocation counts; LTO measurements are retained in the local report.

@liuzicheng1987

Copy link
Copy Markdown
Collaborator

@Altren thanks

@liuzicheng1987
liuzicheng1987 merged commit 6719a9c into munich-data-engineering:main Oct 25, 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