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

feat(lib): re-enable writev support #2338

Merged
merged 10 commits into from Nov 24, 2020
Merged

Conversation

hawkw
Copy link
Contributor

@hawkw hawkw commented Nov 19, 2020

Tokio's AsyncWrite trait once again has support for vectored writes in
Tokio 0.3.4 (see tokio-rs/tokio#3149.

This branch re-enables vectored writes in Hyper. Using vectored writes
in HTTP/2 requires a git dependency on a h2 branch that adds writev
support in h2.

I've removed the adaptive write buffer implementation
that attempts to detect whether vectored IO is or is not available,
since the Tokio 0.3.4 AsyncWrite trait exposes this directly via the
is_write_vectored method. Now, we just ask the IO whether or not it
supports vectored writes, and configure the buffer accordingly. This
makes the implementation somewhat simpler.

This makes a pretty noticeable performance improvement in the
HTTP/1 end to end benchmarks.

Before:

http1_body_both_100kb                                  ...     48,741 ns/iter (+/- 795) = 4201 MB/s
http1_body_both_10mb                                   ...  5,052,611 ns/iter (+/- 191,704) = 4150 MB/s
http1_get                                              ...     13,266 ns/iter (+/- 175)
http1_parallel_x10_empty                               ...    111,058 ns/iter (+/- 2,880)
http1_parallel_x10_req_10kb_100_chunks                 ... 44,978,795 ns/iter (+/- 331,374) = 227 MB/s
http1_parallel_x10_req_10mb                            ... 30,488,288 ns/iter (+/- 966,618) = 3439 MB/s
http1_parallel_x10_res_10mb                            ... 31,197,686 ns/iter (+/- 1,015,384) = 3361 MB/s
http1_parallel_x10_res_1mb                             ...  2,604,156 ns/iter (+/- 32,000) = 4026 MB/s
http1_post                                             ...     15,416 ns/iter (+/- 443) = 1 MB/s
http2_get                                              ...     29,779 ns/iter (+/- 1,478)
http2_parallel_x10_empty                               ...    113,465 ns/iter (+/- 4,347)
http2_parallel_x10_req_10kb_100_chunks                 ...  5,494,508 ns/iter (+/- 76,573) = 1863 MB/s
http2_parallel_x10_req_10kb_100_chunks_adaptive_window ...  5,617,054 ns/iter (+/- 539,833) = 1823 MB/s
http2_parallel_x10_req_10kb_100_chunks_max_window      ...  9,015,224 ns/iter (+/- 4,297,176) = 1135 MB/s
http2_parallel_x10_req_10mb                            ... 28,161,933 ns/iter (+/- 1,425,776) = 3723 MB/s
http2_parallel_x10_res_10mb                            ... 28,270,177 ns/iter (+/- 1,931,240) = 3709 MB/s
http2_parallel_x10_res_1mb                             ...  2,934,070 ns/iter (+/- 232,372) = 3573 MB/s
http2_post                                             ...     34,705 ns/iter (+/- 1,664)
http2_req_100kb                                        ...     71,128 ns/iter (+/- 1,697) = 1439 MB/s

...and after:

http1_body_both_100kb                                  ...      40,922 ns/iter (+/- 948) = 5004 MB/s
http1_body_both_10mb                                   ...   3,133,403 ns/iter (+/- 120,270) = 6692 MB/s
http1_get                                              ...      13,267 ns/iter (+/- 980)
http1_parallel_x10_empty                               ...     113,016 ns/iter (+/- 5,812)
http1_parallel_x10_req_10kb_100_chunks                 ...  44,988,730 ns/iter (+/- 584,882) = 227 MB/s
http1_parallel_x10_req_10mb                            ...  21,539,385 ns/iter (+/- 823,233) = 4868 MB/s
http1_parallel_x10_res_10mb                            ...  22,341,524 ns/iter (+/- 733,779) = 4693 MB/s
http1_parallel_x10_res_1mb                             ...   2,056,770 ns/iter (+/- 28,341) = 5098 MB/s
http1_post                                             ...      15,152 ns/iter (+/- 536) = 1 MB/s
http2_get                                              ...      28,229 ns/iter (+/- 3,301)
http2_parallel_x10_empty                               ...     108,068 ns/iter (+/- 3,227)
http2_parallel_x10_req_10kb_100_chunks                 ...   5,287,486 ns/iter (+/- 4,289,142) = 1936 MB/s
http2_parallel_x10_req_10kb_100_chunks_adaptive_window ...   5,482,784 ns/iter (+/- 156,002) = 1867 MB/s
http2_parallel_x10_req_10kb_100_chunks_max_window      ...   9,049,895 ns/iter (+/- 4,306,978) = 1131 MB/s
http2_parallel_x10_req_10mb                            ...  27,244,510 ns/iter (+/- 1,719,769) = 3848 MB/s
http2_parallel_x10_res_10mb                            ...  37,240,130 ns/iter (+/- 9,692,352) = 2815 MB/s
http2_parallel_x10_res_1mb                             ...   2,863,063 ns/iter (+/- 221,709) = 3662 MB/s
http2_post                                             ...      32,634 ns/iter (+/- 1,770)
http2_req_100kb                                        ...      69,138 ns/iter (+/- 5,281) = 1481 MB/s

Signed-off-by: Eliza Weisman eliza@buoyant.io

BREAKING CHANGE:

Removed http1_writev methods from client::Builder,
client::conn::Builder, server::Builder, and server::conn::Builder.

Vectored writes are now enabled based on whether the AsyncWrite
implementation in use supports them, rather than though adaptive
detection. To explicitly disable vectored writes, users may wrap the IO
in a newtype that implements AsyncRead and AsyncWrite and returns
false from its AsyncWrite::is_write_vectored method.

@seanmonstar
Copy link
Member

I have no idea why CI won't start... (also, super minor conflict in Cargo.toml).

src/proto/h1/io.rs Outdated Show resolved Hide resolved
Tokio's `AsyncWrite` trait once again has support for vectored writes in
Tokio 0.3.4 (see tokio-rs/tokio#3149.

This branch re-enables vectored writes in Hyper for HTTP/1. Using
vectored writes in HTTP/2 will require an upstream change in the `h2`
crate as well.

I've removed the adaptive write buffer implementation
that attempts to detect whether vectored IO is or is not available,
since the Tokio 0.3.4 `AsyncWrite` trait exposes this directly via the
`is_write_vectored` method. Now, we just ask the IO whether or not it
supports vectored writes, and configure the buffer accordingly. This
makes the implementation somewhat simpler.

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Apparently, we actually hit this when the user explicitly enables vectored
writes but  the IO doesn't return `true` from `is_write_vectored`.

This kind of begs the question, do those APIs still make sense? Is there
ever a reason to enable writev on an IO that doesn't return `true` from
`is_write_vectored`? I think that *disabling* vectored writes explicitly
when the IO supports them makes sense, but I'm unconvinced about
*enabling* them when it doesn't.

@seanmonstar any thoughts?

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
These are no longer necessary, as Hyper can now determine whether or not
to use vectored writes based on `is_write_vectored`, rather than trying
to auto-detect it.

BREAKING CHANGE:

Removed `http1_writev` methods from `client::Builder`,
`client::conn::Builder`, `server::Builder`, and `server::conn::Builder`.

Vectored writes are now enabled based on whether the `AsyncWrite`
implementation in use supports them, rather than though adaptive
detection. To explicitly disable vectored writes, users may wrap the IO
in a newtype that implements `AsyncRead` and `AsyncWrite` and returns
`false` from its `AsyncWrite::is_write_vectored` method.
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
also, consolidate the magic numbers.

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
@hawkw hawkw changed the title feat(h1): re-enable writev support feat(lib): re-enable writev support Nov 20, 2020
@hawkw
Copy link
Contributor Author

hawkw commented Nov 20, 2020

h2 pr: hyperium/h2#500

Cargo.toml Outdated Show resolved Hide resolved
now that hyperium/h2#500 has merged, we can switch this back to master
@seanmonstar seanmonstar merged commit d6aadb8 into hyperium:master Nov 24, 2020
BenxiangGe pushed a commit to BenxiangGe/hyper that referenced this pull request Jul 26, 2021
Tokio's `AsyncWrite` trait once again has support for vectored writes in
Tokio 0.3.4 (see tokio-rs/tokio#3149).

This branch re-enables vectored writes in Hyper for HTTP/1. Using
vectored writes in HTTP/2 will require an upstream change in the `h2`
crate as well.

I've removed the adaptive write buffer implementation
that attempts to detect whether vectored IO is or is not available,
since the Tokio 0.3.4 `AsyncWrite` trait exposes this directly via the
`is_write_vectored` method. Now, we just ask the IO whether or not it
supports vectored writes, and configure the buffer accordingly. This
makes the implementation somewhat simpler.

This also removes `http1_writev()` methods from the builders. These are
no longer necessary, as Hyper can now determine whether or not
to use vectored writes based on `is_write_vectored`, rather than trying
to auto-detect it.

Closes hyperium#2320 

BREAKING CHANGE: Removed `http1_writev` methods from `client::Builder`,
  `client::conn::Builder`, `server::Builder`, and `server::conn::Builder`.
  
  Vectored writes are now enabled based on whether the `AsyncWrite`
  implementation in use supports them, rather than though adaptive
  detection. To explicitly disable vectored writes, users may wrap the IO
  in a newtype that implements `AsyncRead` and `AsyncWrite` and returns
  `false` from its `AsyncWrite::is_write_vectored` method.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants