Repository navigation
Speed up Ox.sax_parse by not rescanning the String on each refill - #472
Merged
Merged
Conversation
Watson1978
marked this pull request as ready for review
September 3, 2026 10:39
Watson1978
force-pushed
the
fix-sax-string-refill-scan
branch
from
September 3, 2026 10:41
9744c61 to
c989fa7
Compare
read_from_str() measured what was left of the input with strlen() every
time it filled the 4KB buffer, so a String or StringIO document was
walked once per 4KB and sax_parse was quadratic in its length. A File
goes through read_from_fd() and is unaffected.
Carry the remaining length in the buffer, taken once when the reader is
set up. That strlen() keeps the old rule that the document ends at the
first NUL, which RSTRING_LEN() would not.
Best of three, a no-op Ox::Sax handler:
50.3 MB String 8.5443 s -> 0.1849 s
12.4 MB String 0.4064 s -> 0.0456 s
3.1 MB String 0.0192 s -> 0.0111 s
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Watson1978
force-pushed
the
fix-sax-string-refill-scan
branch
from
September 3, 2026 10:42
c989fa7 to
b166953
Compare
ohler55
approved these changes
Sep 3, 2026
Owner
|
Thank you |
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.
read_from_str()measured what was left of the input withstrlen()every time it filled the 4KB buffer, so a String or StringIO document was walked once per 4KB andOx.sax_parsewas quadratic in its length. A 50 MB document took 8.5 s where the same document read from a File took 0.20 s. The remaining length is now carried in the buffer and taken once when the reader is set up, so the refill is amemcpyand nothing else. That onestrlen()also keeps the rule the old code had, that the document ends at the first NUL, whichRSTRING_LEN()would not.Events are unchanged over a 3180 case corpus that puts every length either side of the 4092, 8184 and 12276 byte refill boundaries in text, in a name, in an attribute value, in a comment, in a CDATA section and in an instruction, read as a String, a StringIO, a StringIO with a non-zero pos and a pipe. The same corpus is clean under AddressSanitizer.
Ruby 4.0.6, gcc 16
-O3, best of three per row after a warm-up. Reading a File is untouched and is shown as the reference, which is also why the 0.2 MB row is the noise floor rather than a change.Benchmark script
🤖 Generated with Claude Code