-
Notifications
You must be signed in to change notification settings - Fork 29.8k
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: remove queue implementation from JSStreamWrap #17918
Conversation
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.
lib/internal/wrap_js_stream.js
Outdated
this[kCurrentWriteRequest] = null; | ||
this[kCurrentShutdownRequest] = null; | ||
|
||
// Start reading |
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.
Dot at end. Also, somewhat superfluous 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.
I don’t think it’s superfluous – I could imagine there’s quite a few who wouldn’t know why you’d ever want to call .read(0)
.
lib/internal/wrap_js_stream.js
Outdated
|
||
this.stream.cork(); | ||
for (var n = 0; n < bufs.length; n++) | ||
this.stream.write(bufs[n], done); | ||
for (var i = 0; i < bufs.length; i++) |
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.
If you're making stylistic changes anyway: let i = ...
(or for (const buf of bufs)
)
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.
We are not allowed to use let
in loops, the linter yells about that. :(
for (const buf of bufs)
seems to work though!
|
||
var pending = bufs.length; | ||
const handle = this._handle; |
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.
Unused?
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.
The linter would complain about that. :)
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 not seeing it, though. Same for the const handle = ...
on line 112.
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.
It’s passed to the self.finishWrite()
call down on line 162
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, indeed. Unfortunate fold in the diff.
lib/internal/wrap_js_stream.js
Outdated
handle.onwrite = (req, bufs) => this.doWrite(req, bufs); | ||
// Inside of the following functions, `this` refers to the handle | ||
// and `this.owner` refers to this JSStreamWrap instance. | ||
handle.isClosing = function() { return this.owner.isClosing(); }; |
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.
would be slightly better to avoid the closures entirely and just make these top level functions.
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.
@jasnell done!
|
||
var pending = bufs.length; | ||
const handle = this._handle; | ||
const self = this; |
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.
Is it still needed ?
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.
@billouboq it’s used inside the done()
function below :)
lib/internal/wrap_js_stream.js
Outdated
|
||
this.stream.cork(); | ||
for (var n = 0; n < bufs.length; n++) | ||
this.stream.write(bufs[n], done); | ||
for (const buf of bufs) |
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 a for(;;)
loop here? for-of is still extremely slower than for(;;)
.
|
||
handle.finishWrite(req, errCode); | ||
setImmediate(() => { | ||
self.finishWrite(handle, errCode); |
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.
you can avoid this closure completely with setImmediate(finishWrite, self, handle, errCode)
.
|
||
this.finishWrite(handle, uv.UV_ECANCELED); | ||
this.finishShutdown(handle, uv.UV_ECANCELED); | ||
|
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 remove this closure as well?
@mcollina I’ll get to addressing your comments later, but I’ll point out that at least in the case of the |
The streams implementation generally ensures that only one write() call is active at a time. `JSStreamWrap` instances still kept queue of write reqeuests in spite of that; refactor it away. Also, fold `isAlive()` into a constant function on the native side.
4be705e
to
a17b0d9
Compare
I'm 👍 if you want to keep if it does not regress anything. I prefer to not use code that might become problematic just for stylistic reasons (and Have you thought about refactoring all those closures as well? I don't expect to get any perf boost, but it might help memory consumption and the gc in the long run. Feel free to ignore those, it's just a nit. |
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
@mcollina I benchmarked all of your suggestions together (via that linked benchmark). I hadn’t really thought about gc, thanks for the reminder! What would be the best way to measure the impact of a change like that? |
@addaleax Slight tangent but an idea I've had is roughly to:
With the idea that you compare runs of the benchmarks or the test suite to see if there are large swings in GC frequency or heap usage. |
I used |
@bnoordhuis I think what you've descried is basically what |
By 'log' I mean 'write to file' in a format that's machine readable.
|
Landed in b171adc I’ll take a look at the closures at another point, this PR isn’t introducing new ones and I’d like to get around to addressing the issue from #17938 (comment) |
The streams implementation generally ensures that only one write() call is active at a time. `JSStreamWrap` instances still kept queue of write reqeuests in spite of that; refactor it away. Also, fold `isAlive()` into a constant function on the native side. PR-URL: #17918 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: Minwoo Jung <minwoo@nodesource.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
The streams implementation generally ensures that only one write() call is active at a time. `JSStreamWrap` instances still kept queue of write reqeuests in spite of that; refactor it away. Also, fold `isAlive()` into a constant function on the native side. PR-URL: #17918 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: Minwoo Jung <minwoo@nodesource.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
The streams implementation generally ensures that only one write() call is active at a time. `JSStreamWrap` instances still kept queue of write reqeuests in spite of that; refactor it away. Also, fold `isAlive()` into a constant function on the native side. PR-URL: #17918 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: Minwoo Jung <minwoo@nodesource.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This is currently breaking some stuff on v9.x It is possible that after #18050 this will work |
@MylesBorins It applies and tests cleanly on my machine … could you show the error you were seeing? |
@addaleax I'm assuming it was unblocked by the http2 update. Will look at this again in a bit |
The streams implementation generally ensures that only one write() call is active at a time. `JSStreamWrap` instances still kept queue of write reqeuests in spite of that; refactor it away. Also, fold `isAlive()` into a constant function on the native side. PR-URL: #17918 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: Minwoo Jung <minwoo@nodesource.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
The streams implementation generally ensures that only one write() call is active at a time. `JSStreamWrap` instances still kept queue of write reqeuests in spite of that; refactor it away. Also, fold `isAlive()` into a constant function on the native side. PR-URL: #17918 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: Minwoo Jung <minwoo@nodesource.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
The streams implementation generally ensures that only one write()
call is active at a time.
JSStreamWrap
instances still keptqueue of write reqeuests in spite of that; refactor it away.
Also, fold
isAlive()
into a constant function on the native side.Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
lib