-
Notifications
You must be signed in to change notification settings - Fork 254
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(NODE-5909): optimize writing basic latin strings #645
Conversation
a5300ad
to
2e612cf
Compare
The test case was repeating BSON.serialize({ _id: string }); These benchmarks were run without a string length limit Node.js v20.11.0
OS: linux
CPUs: 8
Arch: x64
RAM: 33.105743872 GB See basic latin benchmarks!testing string of length: 0
do_nothing x 850,495,953 ops/sec ±0.07% (196 runs sampled)
bson_serialize_current x 1,440,612 ops/sec ±0.86% (190 runs sampled)
bson_serialize_latin_writing x 2,465,289 ops/sec ±0.80% (194 runs sampled)
Fastest to slowest is do_nothing, bson_serialize_latin_writing, bson_serialize_current
testing string of length: 5
do_nothing x 851,197,943 ops/sec ±0.07% (196 runs sampled)
bson_serialize_current x 1,409,583 ops/sec ±0.34% (192 runs sampled)
bson_serialize_latin_writing x 2,256,285 ops/sec ±0.88% (193 runs sampled)
Fastest to slowest is do_nothing, bson_serialize_latin_writing, bson_serialize_current
testing string of length: 10
do_nothing x 851,116,772 ops/sec ±0.08% (196 runs sampled)
bson_serialize_current x 1,386,497 ops/sec ±0.33% (191 runs sampled)
bson_serialize_latin_writing x 2,174,389 ops/sec ±0.96% (192 runs sampled)
Fastest to slowest is do_nothing, bson_serialize_latin_writing, bson_serialize_current
testing string of length: 15
do_nothing x 566,973,633 ops/sec ±17.59% (134 runs sampled)
bson_serialize_current x 1,362,566 ops/sec ±0.39% (191 runs sampled)
bson_serialize_latin_writing x 2,070,277 ops/sec ±0.87% (192 runs sampled)
Fastest to slowest is do_nothing, bson_serialize_latin_writing, bson_serialize_current
testing string of length: 25
do_nothing x 150,902,887 ops/sec ±8.73% (115 runs sampled)
bson_serialize_current x 1,374,990 ops/sec ±0.36% (191 runs sampled)
bson_serialize_latin_writing x 1,921,850 ops/sec ±0.82% (192 runs sampled)
Fastest to slowest is do_nothing, bson_serialize_latin_writing, bson_serialize_current
testing string of length: 50
do_nothing x 133,791,776 ops/sec ±2.94% (177 runs sampled)
bson_serialize_current x 771,222 ops/sec ±0.96% (177 runs sampled)
bson_serialize_latin_writing x 804,194 ops/sec ±1.11% (177 runs sampled)
Fastest to slowest is do_nothing, bson_serialize_latin_writing, bson_serialize_current
testing string of length: 500
do_nothing x 129,510,424 ops/sec ±3.59% (175 runs sampled)
bson_serialize_current x 488,674 ops/sec ±1.24% (156 runs sampled)
bson_serialize_latin_writing x 334,235 ops/sec ±1.23% (181 runs sampled)
Fastest to slowest is do_nothing, bson_serialize_current, bson_serialize_latin_writing
testing string of length: 1000
do_nothing x 138,587,441 ops/sec ±3.02% (123 runs sampled)
bson_serialize_current x 411,147 ops/sec ±1.16% (164 runs sampled)
bson_serialize_latin_writing x 204,873 ops/sec ±1.62% (184 runs sampled)
Fastest to slowest is do_nothing, bson_serialize_current, bson_serialize_latin_writing Ran the same tests again sticking a See advanced latin benchmarks!... omitted smaller cases ... demonstrated no difference because strings were so small
testing string of length: 501
do_nothing x 134,189,343 ops/sec ±3.65% (116 runs sampled)
bson_serialize_current x 471,620 ops/sec ±1.18% (173 runs sampled)
bson_serialize_latin_writing x 278,600 ops/sec ±0.87% (185 runs sampled)
Fastest to slowest is do_nothing, bson_serialize_current, bson_serialize_latin_writing
testing string of length: 1001
do_nothing x 139,626,049 ops/sec ±3.39% (124 runs sampled)
bson_serialize_current x 414,861 ops/sec ±1.00% (167 runs sampled)
bson_serialize_latin_writing x 167,419 ops/sec ±1.27% (185 runs sampled)
Fastest to slowest is do_nothing, bson_serialize_current, bson_serialize_latin_writing Between these two benchmarks results, I decided to take this improvement the same route as the parsing one and focus on small strings only. I had considered that we could stay in the charCodeAt code all the way until we encounter a non basic latin character, and slice the string at that index and let Node.js do the rest. However, the 500 and 1000 character case in the first set of tests show it does not pay to only use charCodeAt, for "large" strings (500 can hardly be called "large"). So again we're mainly targeting BSON strings getting a boost. |
2e612cf
to
1214643
Compare
Description
What is changing?
This is the inverse opimization made in: #642
Should have thought of it sooner :)
Is there new documentation needed for these changes?
No
What is the motivation for this change?
When strings are short and are only basic latin, it is faster to iterate length of the string and call charCodeAt to obtain the UTF8 byte value.
Release Highlight
BSON short basic latin string writing performance improved!
The BSON library's string encoding logic now attempts to optimize for basic latin (ASCII) characters. This will apply to both BSON keys and BSON values that are or contain strings. If strings are less than 6 bytes we observed approximately 100% increase in speed while around 24 bytes the performance was about 33% better. For any non-basic latin bytes or at 25 bytes or greater the BSON library will continue to use Node.js' Buffer.toString API.
The intent is to generally target the serialization of BSON keys which are often short and only use basic latin.
Double check the following
npm run check:lint
scripttype(NODE-xxxx)[!]: description
feat(NODE-1234)!: rewriting everything in coffeescript