| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
scanstring_unicode scans each JSON string one character at a time for the closing quote, a backslash, or a control character. For the one-byte (ASCII/Latin-1) representation, skip eight bytes at a time with a word-at-a-time test using the same masks Objects/unicodeobject.c applies for ASCII scanning; the existing per-character loop then pins the exact byte and performs every decode decision. Two-byte and four-byte strings keep the current loop. Output is byte-identical, verified against test_json, a 347-input differential corpus, and all 340 nst/JSONTestSuite files. Long ASCII string values decode up to 6.3x faster; short keys, numbers, and non-Latin-1 strings are unaffected.
Cover long runs that cross the scan windows with a terminator, backslash escape and \uXXXX escape at every offset in 1-byte and wider strings, plus strict and non-strict control-character handling at the window boundaries.
|
Added test_long_string_scan_paths to test_json/test_decode.py (runs under both the Python and C decoders): a terminator, backslash escape, and \uXXXX escape at every offset across the scan windows in 1-byte and wider strings, plus strict and non-strict control-character handling at the window boundaries. |
Sorry, something went wrong.
|
This PR is stale because it has been open for 90 days with no activity. |
Sorry, something went wrong.
|
@picnixz any appetite to get this merged or should we close it? Thanks! |
Sorry, something went wrong.
|
Sorry, something went wrong.
|
The CI was green back in June and no merge conflicts, I can fix it, but if there's no appetite in accepting it perhaps better to close it than spend more time on it, thanks! |
Sorry, something went wrong.
|
Right now I am working on new JSON parser which may replace the current one. So, such micro-optimizations are premature. I hope to finish my work in few days. |
Sorry, something went wrong.
|
FWIW, I was also interested in JSON performance and found that accepting UTF-8 for input as bytes in addition to Unicode when decoding, and using BytesWriter to produce UTF-8 output when encoding, could improve the overall performance of reading and writing non-ASCII JSON by around 25%. |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
JSON documents whose payload is long text (log lines, description and content fields, base64 or embedded-document values) spend most of their decode time finding the end of each string. This speeds that up by scanning eight bytes at a time instead of one, with no SIMD intrinsics and no CPU detection, and it is byte-identical to the current decoder.
What we do now (scalar, one code point at a time)
The current scanstring_unicode inner loop:
For a 64-character string with no escapes that is 64 iterations, each doing one read, up to three comparisons, and a loop branch: about 64 × 4 operations just to find the closing ". The CPU walks the string one byte at a time while its 64-bit registers sit mostly idle.
What SWAR does (8 bytes at a time, in one register)
SWAR is "SIMD within a register": load 8 bytes into a single uint64_t and test all 8 lanes at once with ordinary integer ops.
Two tricks make this work:
One loop iteration answers "do any of these 8 bytes need attention?" in about 6 integer ops. If not, it advances 8 bytes, so the 64-character string takes 8 iterations instead of 64.
The key design point: SWAR only skips, it never decides
When the mask is nonzero, meaning a ", \\, or control char sits somewhere in the 8-byte window, the loop breaks and the original scalar loop re-scans those 8 bytes to find the exact position and do the actual work: terminate the string, handle the escape, or raise the error at the right index. Every decode decision stays on the proven scalar path. SWAR is purely a fast-forward over the runs of ordinary characters that make up the bulk of most strings.
Worked example
Chunk hello wo (8 ordinary ASCII bytes):
Chunk lo","wor (a " at offset 2):
Why it is a win, and its limits
Mental model: today we ask "is this byte special?" once per byte; SWAR asks "is any of these eight bytes special?" once per eight, and drops to per-byte only when the answer is yes.
When and how this changes performance
json.loads, current decoder versus this change:
The standard pyperformance bm_json_loads document is short-string and dict dominated and shows no change. The benefit lands on documents whose strings are long.
Correctness
Output is byte-identical to the current decoder, error positions included. Verified three ways: the full test_json suite; a 347-input differential corpus (real-world JSON, plus a quote, backslash, raw control character, escape, and \uXXXX placed at every offset across the eight-byte window in all three string representations, plus surrogate pairs, lone surrogates, embedded nulls, and truncated escapes); and all 340 files of nst/JSONTestSuite (318 parsing and 22 transform, including the must-reject and implementation-defined cases). Every value and every raised error position matched the current implementation.
BenchmarkReferences for the bit tricks: Sean Anderson, Bit Twiddling Hacks (zero byte, byte equal to n, byte less than n); Henry S. Warren Jr., Hacker's Delight, 2nd ed., chapter 6.
It is not the SIMD parsing backend from #142915: it adds no intrinsics, no CPU detection, and no build configuration, and it does not depend on #125022.
Resolves #150871.