-
Notifications
You must be signed in to change notification settings - Fork 30k
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
lib,src: improve writev() performance for Buffers #13187
Conversation
while (entry) { | ||
buffer[count] = entry; | ||
if (!entry.isBuf) |
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'd probably do allBuffers = allBuffers && entry.isBuf
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 tried something similar (continuing the rest of the loop without any conditional) and did not see any difference in performance.
src/stream_base.cc
Outdated
@@ -100,94 +100,118 @@ int StreamBase::Writev(const FunctionCallbackInfo<Value>& args) { | |||
|
|||
Local<Object> req_wrap_obj = args[0].As<Object>(); | |||
Local<Array> chunks = args[1].As<Array>(); | |||
bool all_buffers = args[2]->BooleanValue(); |
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.
Can you use the overload that returns a Maybe<bool>
, or alternatively use IsTrue()
instead?
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.
Changed.
if (all_buffers) | ||
count = chunks->Length(); | ||
else | ||
count = chunks->Length() >> 1; |
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.
nit: I’d really just write / 2
, it’s clearer and the resulting code will be the same
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.
That's copied from before these changes. It's also similar to what was already being used in js.
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.
Yeah, but in JS that has a different meaning. ¯\_(ツ)_/¯ If you want to keep it it’s fine.
src/stream_base.cc
Outdated
wrap = GetAsyncWrap(); | ||
// NOTE: All tests show that GetAsyncWrap() never returns nullptr here. If it | ||
// can then replace the CHECK_NE() with if (wrap != nullptr). | ||
CHECK_NE(wrap, nullptr); |
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.
Heads up, this is going to conflict with #13174 which removes the comment (because GetAsyncWrap()
does actually never return a null pointer), so feel free to remove it here as well
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'll just wait until that lands first and I'll rebase.
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.
@mscdex Landed, you can rebase now
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.
Done.
size_t offset = 0; | ||
for (size_t i = 0; i < count; i++) { | ||
Local<Value> chunk = chunks->Get(i * 2); | ||
if (Buffer::HasInstance(chunk)) |
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.
nit: chunk->IsUint8Array()
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.
This was also copied from before these changes. I think changing it to check for a more general type is outside the scope of this PR.
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 think changing it to check for a more general type is outside the scope of this PR.
It’s literally the same thing, just inlined. :)
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.
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.
Oh, right, we made that switch. Idc, you can also keep Buffer::HasInstance
.
c5814a0
to
fd84f30
Compare
PR-URL: nodejs#13187 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
PR-URL: #13187 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
Should we consider this for LTS? if so it needs to bake for a bit. Please change labels as appropriate |
It's pretty common to write only Buffers to a socket, so we can optimize for that case in a couple of ways whenever we know we have all Buffers queued up for
writev()
:WriteWrap
instance first. This optimization is one that is already being done whenwrite()
ing a single Buffer (or a single string for that matter) to a socket.Benchmark results:
CI: https://ci.nodejs.org/job/node-test-pull-request/8271/
CI for FIPS (since it failed initially): https://ci.nodejs.org/job/node-test-commit-linux-fips/8624/
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)