perf(storage): Parse JSON from a slice instead of a reader - #898
Merged
Conversation
conversation grep hits addressable and scriptable
conversation grep hits addressable and scriptableconversation grep hits addressable
Every JSON read went through `serde_json::from_reader` over a `BufReader`. Its `IoRead` advances one byte at a time, which costs the parser both its `memchr` scans and its zero-copy string borrows — the crate's own docs note that reading the file into memory and calling `from_slice` is usually faster. Reading whole and parsing the slice cut `jp conversation grep --scope chat` from 2.5s to 1.8s on a 600-conversation workspace, with JSON parsing dropping from roughly 42% of working samples to under 3%. Three call sites carried the slow path: `load_json`, which loads conversation metadata and event streams; `load_count_and_timestamp_events`, which skims an event file for its count and last timestamp; and `get_expiring_timestamp`, which reads just `expires_at` out of a metadata file. `jp_storage::value::read_json` shared the pattern and moves too, though nothing hot calls it. The tradeoff is peak memory: a file is now fully resident while it parses, where the reader streamed it. Conversation event files are the largest thing this reads and they are already deserialized into memory in full, so the extra transient allocation is bounded by a file that was going to be resident anyway. Signed-off-by: Jean Mertz <git@jeanmertz.com>
conversation grep hits addressable
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.
Every JSON read went through
serde_json::from_readerover aBufReader. ItsIoReadadvances one byte at a time, which costs theparser both its
memchrscans and its zero-copy string borrows — thecrate's own docs note that reading the file into memory and calling
from_sliceis usually faster. Reading whole and parsing the slice cutjp conversation grep --scope chatfrom 2.5s to 1.8s on a 600-turnworkspace, with JSON parsing dropping from roughly 42% of working
samples to under 3%.
Three call sites carried the slow path:
load_json, which loadsconversation metadata and event streams;
load_count_and_timestamp_events,which skims an event file for its count and last timestamp; and
get_expiring_timestamp, which reads justexpires_atout of a metadatafile.
jp_storage::value::read_jsonshared the pattern and moves too,though nothing hot calls it.
The tradeoff is peak memory: a file is now fully resident while it parses,
where the reader streamed it. Conversation event files are the largest
thing this reads and they are already deserialized into memory in full,
so the extra transient allocation is bounded by a file that was going to
be resident anyway.