perf(serialise): stream JSON directly and compile format strings#7
Merged
Conversation
Graph serialisation was the dominant wall-clock cost (~19.7s vs ~2.5s
generation on a 1.8M-node graph). Three changes, output byte-shape identical:
- Replace the nlohmann::json DOM construction + .dump() with direct streaming
into a 1 MiB reused buffer flushed to the file, so the whole multi-GB string
is never held in memory. graph_to_json now parses graph_to_string's output,
keeping one serialisation implementation (the DOM path only ran in tests).
- Use FMT_COMPILE for the per-cell board formatting (Table::to_string) and the
per-node/per-edge JSON records. fmt was re-parsing '{:^5}' etc. at runtime
for every cell of every node; compiling the format strings removes the
parse_format_string / on_format_specs overhead (the single largest cost).
- Bulk-append runs of non-escaped characters in the JSON string escaper
instead of one char at a time.
Write time on the 1.8M-node graph: 19.7s -> 7.9s (~2.5x). All 230 test
assertions pass (test_table asserts exact to_string output; test_serialise
validates the parsed structure).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Graph JSON serialisation was the dominant wall-clock cost — ~19.7s vs ~2.5s of search generation on a 1.83M-node graph. This isolates three serialisation optimisations, with byte-shape-identical output (the web frontend is untouched).
Changes
nlohmann::jsonDOM then.dump()-ing it. Records are written into a 1 MiB reused buffer flushed to the file, so the multi-GB string is never fully held in memory.graph_to_jsonnow parsesgraph_to_string's output, keeping a single serialisation implementation (the DOM path only ran in tests).FMT_COMPILEfor the per-cell board formatting (Table::to_string) and per-node/per-edge records. fmt was re-parsing{:^5}etc. at runtime for every cell of every node; compiling the format strings removes theparse_format_string/on_format_specsoverhead (the single largest remaining cost).Results
Write time on the 1.83M-node graph (
--max-depth 30): 19.7s → 7.9s (~2.5×), memory now bounded.Testing
All 230 assertions pass —
test_table.cppasserts exactto_string()output andtest_serialise.cppvalidates the parsed structure. Output field shapes verified identical to the previous format (the"size":["..."]array quirk, raw UTF-8 suit glyphs, escaped newlines,label/forceLabelonly on start/winning nodes).