Skip to content
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

http2: refactor outgoing write mechanism #17718

Closed
wants to merge 3 commits into from

Conversation

addaleax
Copy link
Member

@addaleax addaleax commented Dec 17, 2017

The first commits in this are from #17406. It’s blocked on that merge-conflict-wise but generally ready for review.

  • http2: remove redundant write indirection

    nghttp2_stream_write_t was not a necessary redirection layer
    and came with the cost of one additional allocation per stream write.

    Also, having both nghttp2_stream_write and nghttp2_stream_write_t
    as identifiers did not help with readability.

      $ ./node benchmark/compare.js --new ./node --old ./node-before --runs 100 --filter write --set streams=20 --set length=1024 --set size=16 http2 | Rscript benchmark/compare.R
      [00:26:09|% 100| 1/1 files | 200/200 runs | 1/1 configs]: Done
                                                                           improvement confidence     p.value
       http2/write.js benchmarker="h2load" size=16 length=1024 streams=20      0.58 %         ** 0.005535241
    
  • http2: refactor outgoing write mechanism

    • Only finish outgoing WriteWraps once data has actually been
      passed to the underlying socket.

      • This makes HTTP2 streams respect backpressure
    • Use DoTryWrite as a shortcut for sending out as much of
      the data synchronously without blocking as possible

    • Use NGHTTP2_DATA_FLAG_NO_COPY to avoid copying DATA frame
      contents into nghttp2’s buffers before sending them out.

      $ ./node benchmark/compare.js --new ./node --old ./node-before --runs 10 --filter write --set streams=20 --set length=1024 --set size=16 http2 | Rscript benchmark/compare.R
      [00:02:30|% 100| 1/1 files | 20/20 runs | 1/1 configs]: Done
                                                                           improvement confidence      p.value
       http2/write.js benchmarker="h2load" size=16 length=1024 streams=20      6.88 %        *** 2.261566e-08
      
Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • commit message follows commit guidelines
Affected core subsystem(s)

http2 @nodejs/http2

CI: https://ci.nodejs.org/job/node-test-commit/14902/

@addaleax addaleax added blocked PRs that are blocked by other issues or PRs. http2 Issues or PRs related to the http2 subsystem. performance Issues and PRs related to the performance of Node.js. labels Dec 17, 2017
@nodejs-github-bot nodejs-github-bot added the lib / src Issues and PRs related to general changes in the lib or src directory. label Dec 17, 2017
@addaleax addaleax added c++ Issues and PRs that require attention from people who are familiar with C++. and removed lib / src Issues and PRs related to general changes in the lib or src directory. labels Dec 17, 2017
namespace {

inline Http2Stream* GetStream(Http2Session* session,
int32_t id,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit... line up the args :-)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jasnell done, and rebased :)

@jasnell
Copy link
Member

jasnell commented Dec 18, 2017

I love it. Initial read through looks good but will give a more thorough review a bit later on today.

@jasnell
Copy link
Member

jasnell commented Dec 18, 2017

#17406 has landed. This can be rebased to remove those carried over commits :-)

`nghttp2_stream_write_t` was not a necessary redirection layer
and came with the cost of one additional allocation per stream write.

Also, having both `nghttp2_stream_write` and `nghttp2_stream_write_t`
as identifiers did not help with readability.

    $ ./node benchmark/compare.js --new ./node --old ./node-before --runs 100 --filter write --set streams=20 --set length=1024 --set size=16 http2 | Rscript benchmark/compare.R
    [00:26:09|% 100| 1/1 files | 200/200 runs | 1/1 configs]: Done
                                                                         improvement confidence     p.value
     http2/write.js benchmarker="h2load" size=16 length=1024 streams=20      0.58 %         ** 0.005535241
- Only finish outgoing `WriteWrap`s once data has actually been
  passed to the underlying socket.
  - This makes HTTP2 streams respect backpressure
- Use `DoTryWrite` as a shortcut for sending out as much of
  the data synchronously without blocking as possible
- Use `NGHTTP2_DATA_FLAG_NO_COPY` to avoid copying DATA frame
  contents into nghttp2’s buffers before sending them out.

    $ ./node benchmark/compare.js --new ./node --old ./node-before --runs 10 --filter write --set streams=20 --set length=1024 --set size=16 http2 | Rscript benchmark/compare.R
    [00:02:30|% 100| 1/1 files | 20/20 runs | 1/1 configs]: Done
                                                                         improvement confidence      p.value
     http2/write.js benchmarker="h2load" size=16 length=1024 streams=20      6.88 %        *** 2.261566e-08
@addaleax addaleax removed the blocked PRs that are blocked by other issues or PRs. label Dec 18, 2017
@addaleax
Copy link
Member Author

@@ -419,6 +435,9 @@ Http2Session::Http2Session(Environment* env,
// be catching before it gets this far. Either way, crash if this
// fails.
CHECK_EQ(fn(&session_, callbacks, this, *opts), 0);

outgoing_storage_.reserve(4096);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

may want to play with some different numbers here. The default max frame size is 16k.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jasnell This storage is only for data that comes out of nghttp2, not the actual DATA frame payload … and I’m just realizing that padding could also just come from a static buffer. :)

Copy link
Member

@jasnell jasnell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. thanks for this. It was the next big chunk to work on. :-)

@jasnell
Copy link
Member

jasnell commented Dec 19, 2017

@jasnell
Copy link
Member

jasnell commented Dec 20, 2017

CI looks good except for some build bot failures on linux, trying again on those just to be safe: https://ci.nodejs.org/job/node-test-commit-linux/15097/

jasnell pushed a commit that referenced this pull request Dec 20, 2017
`nghttp2_stream_write_t` was not a necessary redirection layer
and came with the cost of one additional allocation per stream write.

Also, having both `nghttp2_stream_write` and `nghttp2_stream_write_t`
as identifiers did not help with readability.

PR-URL: #17718
Reviewed-By: James M Snell <jasnell@gmail.com>
jasnell pushed a commit that referenced this pull request Dec 20, 2017
- Only finish outgoing `WriteWrap`s once data has actually been
  passed to the underlying socket.
  - This makes HTTP2 streams respect backpressure
- Use `DoTryWrite` as a shortcut for sending out as much of
  the data synchronously without blocking as possible
- Use `NGHTTP2_DATA_FLAG_NO_COPY` to avoid copying DATA frame
  contents into nghttp2’s buffers before sending them out.

PR-URL: #17718
Reviewed-By: James M Snell <jasnell@gmail.com>
@jasnell
Copy link
Member

jasnell commented Dec 20, 2017

Landed in e3b44b6 and e0e6b68

MylesBorins pushed a commit to jasnell/node that referenced this pull request Jan 9, 2018
`nghttp2_stream_write_t` was not a necessary redirection layer
and came with the cost of one additional allocation per stream write.

Also, having both `nghttp2_stream_write` and `nghttp2_stream_write_t`
as identifiers did not help with readability.

PR-URL: nodejs#17718
Reviewed-By: James M Snell <jasnell@gmail.com>
MylesBorins pushed a commit to jasnell/node that referenced this pull request Jan 9, 2018
- Only finish outgoing `WriteWrap`s once data has actually been
  passed to the underlying socket.
  - This makes HTTP2 streams respect backpressure
- Use `DoTryWrite` as a shortcut for sending out as much of
  the data synchronously without blocking as possible
- Use `NGHTTP2_DATA_FLAG_NO_COPY` to avoid copying DATA frame
  contents into nghttp2’s buffers before sending them out.

PR-URL: nodejs#17718
Reviewed-By: James M Snell <jasnell@gmail.com>
MylesBorins pushed a commit that referenced this pull request Jan 9, 2018
`nghttp2_stream_write_t` was not a necessary redirection layer
and came with the cost of one additional allocation per stream write.

Also, having both `nghttp2_stream_write` and `nghttp2_stream_write_t`
as identifiers did not help with readability.

Backport-PR-URL: #18050
PR-URL: #17718
Reviewed-By: James M Snell <jasnell@gmail.com>
MylesBorins pushed a commit that referenced this pull request Jan 9, 2018
- Only finish outgoing `WriteWrap`s once data has actually been
  passed to the underlying socket.
  - This makes HTTP2 streams respect backpressure
- Use `DoTryWrite` as a shortcut for sending out as much of
  the data synchronously without blocking as possible
- Use `NGHTTP2_DATA_FLAG_NO_COPY` to avoid copying DATA frame
  contents into nghttp2’s buffers before sending them out.

Backport-PR-URL: #18050
PR-URL: #17718
Reviewed-By: James M Snell <jasnell@gmail.com>
@MylesBorins MylesBorins mentioned this pull request Jan 10, 2018
MylesBorins pushed a commit that referenced this pull request Jan 10, 2018
`nghttp2_stream_write_t` was not a necessary redirection layer
and came with the cost of one additional allocation per stream write.

Also, having both `nghttp2_stream_write` and `nghttp2_stream_write_t`
as identifiers did not help with readability.

Backport-PR-URL: #18050
PR-URL: #17718
Reviewed-By: James M Snell <jasnell@gmail.com>
MylesBorins pushed a commit that referenced this pull request Jan 10, 2018
- Only finish outgoing `WriteWrap`s once data has actually been
  passed to the underlying socket.
  - This makes HTTP2 streams respect backpressure
- Use `DoTryWrite` as a shortcut for sending out as much of
  the data synchronously without blocking as possible
- Use `NGHTTP2_DATA_FLAG_NO_COPY` to avoid copying DATA frame
  contents into nghttp2’s buffers before sending them out.

Backport-PR-URL: #18050
PR-URL: #17718
Reviewed-By: James M Snell <jasnell@gmail.com>
kjin pushed a commit to kjin/node that referenced this pull request May 1, 2018
`nghttp2_stream_write_t` was not a necessary redirection layer
and came with the cost of one additional allocation per stream write.

Also, having both `nghttp2_stream_write` and `nghttp2_stream_write_t`
as identifiers did not help with readability.

Backport-PR-URL: nodejs#18050
PR-URL: nodejs#17718
Reviewed-By: James M Snell <jasnell@gmail.com>
kjin pushed a commit to kjin/node that referenced this pull request May 1, 2018
- Only finish outgoing `WriteWrap`s once data has actually been
  passed to the underlying socket.
  - This makes HTTP2 streams respect backpressure
- Use `DoTryWrite` as a shortcut for sending out as much of
  the data synchronously without blocking as possible
- Use `NGHTTP2_DATA_FLAG_NO_COPY` to avoid copying DATA frame
  contents into nghttp2’s buffers before sending them out.

Backport-PR-URL: nodejs#18050
PR-URL: nodejs#17718
Reviewed-By: James M Snell <jasnell@gmail.com>
MylesBorins pushed a commit that referenced this pull request May 2, 2018
`nghttp2_stream_write_t` was not a necessary redirection layer
and came with the cost of one additional allocation per stream write.

Also, having both `nghttp2_stream_write` and `nghttp2_stream_write_t`
as identifiers did not help with readability.

Backport-PR-URL: #18050
Backport-PR-URL: #20456
PR-URL: #17718
Reviewed-By: James M Snell <jasnell@gmail.com>
MylesBorins pushed a commit that referenced this pull request May 2, 2018
- Only finish outgoing `WriteWrap`s once data has actually been
  passed to the underlying socket.
  - This makes HTTP2 streams respect backpressure
- Use `DoTryWrite` as a shortcut for sending out as much of
  the data synchronously without blocking as possible
- Use `NGHTTP2_DATA_FLAG_NO_COPY` to avoid copying DATA frame
  contents into nghttp2’s buffers before sending them out.

Backport-PR-URL: #18050
Backport-PR-URL: #20456
PR-URL: #17718
Reviewed-By: James M Snell <jasnell@gmail.com>
@MylesBorins MylesBorins mentioned this pull request May 2, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ Issues and PRs that require attention from people who are familiar with C++. http2 Issues or PRs related to the http2 subsystem. performance Issues and PRs related to the performance of Node.js.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants