-
-
Notifications
You must be signed in to change notification settings - Fork 33.8k
buffer: improve fill & normalizeEncoding performance #18790
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
Conversation
b2f5427 to
f082114
Compare
jasnell
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with a good CITGM run.
doc/api/buffer.md
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ERR_INDEX_OUT_OF_RANGE?
benjamingr
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work!
I think it would be interesting to add fill with larger values to the benchmark.
Actual changes LGTM
lib/internal/util.js
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm surprised this improves performance noticeably.
|
@benjamingr the performance gain for Buffer#fill goes down the bigger the buffer is. The break even point should be at about 25kb. Above that the filling will be the main time consumer. |
|
@BridgeAR right, but since we're adding a benchmark that will run when this code changes for a while, I think there is value in adding a larger buffer for the test case - I suspect allocating large'ish buffers is a pretty common use case. Even if there won't be a big difference here. |
|
doc/api/buffer.md
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OF_OUT -> OUT_OF :)
mcollina
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
1) This improves the performance for Buffer#fill by using shortcuts. 2) It also ports throwing errors to JS. That way they contain the proper error code. 3) Using negative `end` values will from now on result in an error instead of just doing nothing. 4) Passing in `null` as encoding is from now on accepted as 'utf8'.
This focuses on the common case by making sure they are prioritized. It also changes some typeof checks to test for undefined since that is faster and it adds a benchmark.
Due to a consolidation the isEncoding function got less strict in version 5.x.x. This commit makes sure we do not return `true` for empty strings.
332ac6e to
c5aa244
Compare
|
Rebased due to conflicts. |
|
Landed in d3af120...452eed9 |
1) This improves the performance for Buffer#fill by using shortcuts. 2) It also ports throwing errors to JS. That way they contain the proper error code. 3) Using negative `end` values will from now on result in an error instead of just doing nothing. 4) Passing in `null` as encoding is from now on accepted as 'utf8'. PR-URL: nodejs#18790 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Matteo Collina <[email protected]>
PR-URL: nodejs#18790 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Matteo Collina <[email protected]>
PR-URL: nodejs#18790 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Matteo Collina <[email protected]>
This focuses on the common case by making sure they are prioritized. It also changes some typeof checks to test for undefined since that is faster and it adds a benchmark. PR-URL: nodejs#18790 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Matteo Collina <[email protected]>
Due to code consolidation in nodejs#7207 the isEncoding function got less strict. This commit makes sure isEncoding returns false for empty strings as before the consolidation. PR-URL: nodejs#18790 Refs: nodejs#7207 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Matteo Collina <[email protected]>
1) This improves the performance for Buffer#fill by using shortcuts. 2) It also ports throwing errors to JS. That way they contain the proper error code. 3) Using negative `end` values will from now on result in an error instead of just doing nothing. 4) Passing in `null` as encoding is from now on accepted as 'utf8'. PR-URL: nodejs#18790 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Matteo Collina <[email protected]>
PR-URL: nodejs#18790 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Matteo Collina <[email protected]>
PR-URL: nodejs#18790 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Matteo Collina <[email protected]>
This focuses on the common case by making sure they are prioritized. It also changes some typeof checks to test for undefined since that is faster and it adds a benchmark. PR-URL: nodejs#18790 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Matteo Collina <[email protected]>
Due to code consolidation in nodejs#7207 the isEncoding function got less strict. This commit makes sure isEncoding returns false for empty strings as before the consolidation. PR-URL: nodejs#18790 Refs: nodejs#7207 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Matteo Collina <[email protected]>
|
@nodejs/security thoughts on preventing such changes in the future? My opinion is that a testcase should have been introduced at the same time when the comment was. Or, perhaps, even instead of the comment. Upd: filed #22492. |
This improves the performance of
Buffer#filland ofnormalizeEncoding. The latter focuses on the common cases as can be seen in the benchmarks.I made the
Buffer.isEncoding()implementation stricter again after it was loosened in #7207. It will not return true for an empty string anymore.normalizeEncodingis now also stricter and it returnsundefinedforfalse,NaNand0.undefined,nulland''are still "valid"utf8encodings.The
Buffer#fillimplementation will now also throw an OOB error in caseendis a negative value. This makes it consistent withstartand it helps to identify issues since before it would just been ignored instead.Buffer#fillwill throw the errors in JS from now on in case the OOB is detected in c++ and those errors contain the proper error code from now on.Buffer#fillwill from now on also acceptnullas validutf8encoding in case a string is provided. That was not the case before but we do accept it in other places and that makes it more consistent.Buffer#fill performance
confidence improvement accuracy (*) (**) (***) buffers/buffer-fill.js n=20000 size=10 type='fill("")' *** 16.25 % ±5.16% ±6.89% ±9.01% buffers/buffer-fill.js n=20000 size=10 type='fill("t", "utf8")' *** 17.49 % ±3.59% ±4.78% ±6.23% buffers/buffer-fill.js n=20000 size=10 type='fill("t", 0, "utf8")' *** 14.82 % ±4.17% ±5.55% ±7.23% buffers/buffer-fill.js n=20000 size=10 type='fill("t", 0)' *** 21.59 % ±4.88% ±6.50% ±8.47% buffers/buffer-fill.js n=20000 size=10 type='fill("t")' *** 23.16 % ±3.88% ±5.17% ±6.73% buffers/buffer-fill.js n=20000 size=10 type='fill("test")' *** 12.85 % ±3.91% ±5.24% ±6.91% buffers/buffer-fill.js n=20000 size=10 type='fill(0)' *** 22.39 % ±2.48% ±3.30% ±4.30% buffers/buffer-fill.js n=20000 size=10 type='fill(100)' *** 24.41 % ±4.52% ±6.02% ±7.85% buffers/buffer-fill.js n=20000 size=10 type='fill(400)' *** 22.00 % ±2.27% ±3.03% ±3.95% buffers/buffer-fill.js n=20000 size=10 type='fill(Buffer.alloc(1), 0)' *** 8.60 % ±3.85% ±5.17% ±6.84% buffers/buffer-fill.js n=20000 size=5000 type='fill("")' *** 22.84 % ±6.16% ±8.20% ±10.68% buffers/buffer-fill.js n=20000 size=5000 type='fill("t", "utf8")' *** 8.74 % ±4.89% ±6.57% ±8.67% buffers/buffer-fill.js n=20000 size=5000 type='fill("t", 0, "utf8")' *** 10.69 % ±4.94% ±6.60% ±8.63% buffers/buffer-fill.js n=20000 size=5000 type='fill("t", 0)' *** 14.17 % ±4.13% ±5.51% ±7.20% buffers/buffer-fill.js n=20000 size=5000 type='fill("t")' *** 21.25 % ±3.83% ±5.10% ±6.65% buffers/buffer-fill.js n=20000 size=5000 type='fill("test")' *** 16.50 % ±2.03% ±2.70% ±3.52% buffers/buffer-fill.js n=20000 size=5000 type='fill(0)' *** 29.73 % ±4.40% ±5.89% ±7.72% buffers/buffer-fill.js n=20000 size=5000 type='fill(100)' *** 15.48 % ±2.54% ±3.38% ±4.40% buffers/buffer-fill.js n=20000 size=5000 type='fill(400)' *** 16.19 % ±2.62% ±3.49% ±4.55% buffers/buffer-fill.js n=20000 size=5000 type='fill(Buffer.alloc(1), 0)' ** 4.36 % ±2.79% ±3.74% ±4.90%Normalize encoding performance
Checklist
make -j4 test(UNIX), orvcbuild test(Windows) passesAffected core subsystem(s)
buffer