mirror of
https://github.com/nlohmann/json.git
synced 2026-10-31 09:55:42 +00:00
The digits after the decimal point were skipped by skip_digits(), 16 compare-and-branch steps in a row: about 3.5 instructions per digit, and an exit branch that is mispredicted when the lengths of the fractions vary. On x86 with SSE2, the fraction is now skipped by skip_fraction_digits(): 16 bytes are compared at once and the end of the run is taken from the bit mask, which is about a third of the instructions for a fraction of 12 digits. The last bytes of the input are skipped one at a time as before. Where there is no SSE2 (AArch64, other targets, JSON_NO_SIMD) skip_fraction_digits() is skip_digits(): nothing changes there. Integer digits keep skip_digits(), whose exit is predictable. GCC unrolls the loop over the last bytes in every inlined copy of the new function, which made the parse loop 4 KiB larger and parse() of documents with hardly any fractions about 4 % slower. For GCC that loop is therefore out of line (skip_digits_tail()); Clang is faster with it inline. json_document::parse(), A/B in one binary, 6 code layouts, x86-64 Haswell, time after / before (GCC 16.2 / Clang 23): - numbers.json (10,001 floats): 0.715 / 0.680 - canada.json: 0.778 / 0.790 - mesh.json: 0.908 / 0.883 - marine_ik.json: 0.937 / 0.926 - mesh.pretty.json: 0.923 / 0.960 Files with few or no fractions and files with fractions of a fixed length (20,000 prices with two decimals, 60,000 coordinates with six): between 0.98 and 1.014 on both compilers, except citm_catalog.json with GCC (1.05: the instruction count is +0.3 %, and that row varies by +-7 % between builds of unrelated variants on this machine). New test: fractions of every length from 0 to 40 digits followed by every kind of byte that ends a number or lies next to the digits in ASCII, in several positions, and cut in every place near the end of the text, against json::parse() (the length of the number is part of what is compared), for all option combinations and with and without a terminating NUL. Checked on x86-64 with GCC 16.2, Clang 23 and Apple clang under Rosetta, and with a deliberate off-by-one at the 16th byte. Signed-off-by: Niels Lohmann <mail@nlohmann.me>