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

perf(ext/http): Object pooling for HttpRecord and HeaderMap #20809

Merged
merged 6 commits into from
Nov 13, 2023

Conversation

lrowe
Copy link
Contributor

@lrowe lrowe commented Oct 6, 2023

Reuse existing existing allocations for HttpRecord and response HeaderMap where possible.

At request end used allocations are returned to the pool and the pool and the pool sized to 1/8th the current number of inflight requests.

For http1 hyper will reuse the response HeaderMap for the following request on the connection.

Builds upon #20770

@lrowe
Copy link
Contributor Author

lrowe commented Oct 6, 2023

Benchmarking on my not very consistent MacBook Air shows around a ~1.5% performance improvement in the minimal benchmark, 121645 req/s vs 120351 req/s on main.

@lrowe
Copy link
Contributor Author

lrowe commented Oct 6, 2023

Note the change to op_http_close to only wait for connections to drain on graceful shutdown: 2d02f4e

This Is necessary for the "Throw if disturbed" test to pass which otherwise deadlocks waiting for server.finished while with the pooling change the server refcount lives until HttpRecord.complete when the record is recycled.

https://github.com/denoland/deno/blob/main/cli/tests/unit/serve_test.ts#L3323-L3374

EDIT: In #20822 I've added a tokio::task::yield_now().await to the non-graceful shutdown path to give the streaming response body resources a chance to close.

@lrowe
Copy link
Contributor Author

lrowe commented Oct 7, 2023

The change to op_http_close exposed a race condition where HttpRecord::recycle would not be called when the future was cancelled between HttpRecord::complete calling waker.wake() and the async scheduler resuming execution of the async fn.

No actual impact as the pool was about to be destroyed anyway, but it's easier to reason about when we ensure HttpRecord::recycle is called for every HttpRecord.

Fixed in 908df83.

Reuse existing existing allocations for HttpRecord and response HeaderMap where possible.

At request end used allocations are returned to the pool and the pool and the pool sized to 1/8th the current number of inflight requests.

For http1 hyper will reuse the response HeaderMap for the following request on the connection.
@mmastrac
Copy link
Contributor

/bench http[minimal,realistic]

@denobot
Copy link
Collaborator

denobot commented Nov 13, 2023

http[minimal]

rps latency bytes relative
node 88,162 111.77 µs σ=34.48 750,068 kB -71.3%
bun 307,692 32.51 µs σ=15.99 1,513,671 kB best
deno 164,288 59.11 µs σ=17.4 1,347,656 kB -46.6%
deno-baseline 167,630 57.98 µs σ=17.4 1,376,953 kB -45.5%

http[realistic]

rps latency bytes relative
node 86,719 114 µs σ=37.11 937,500 kB -55.6%
bun 195,198 58.81 µs σ=127.22 1,826,171 kB best
deno 136,092 72.12 µs σ=23.85 1,445,312 kB -30.3%
deno-baseline 137,761 71.16 µs σ=22.94 1,464,843 kB -29.4%

start: Mon, 13 Nov 2023 14:36:20 GMT

id: b86df968-3dfc-47e2-8f2f-95921e57ecaa

server: 5d1349b0-551a-4627-9cc0-94fb25bd0ff4

Copy link
Contributor

@mmastrac mmastrac left a comment

Choose a reason for hiding this comment

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

LGTM. This is slightly slower than baseline but the next PR in the series makes it all faster.

@mmastrac mmastrac merged commit 25950ba into denoland:main Nov 13, 2023
13 checks passed
@mmastrac
Copy link
Contributor

/bench http[minimal,realistic]

@denobot
Copy link
Collaborator

denobot commented Nov 13, 2023

http[minimal]

rps latency bytes relative
node 87,620 113.43 µs σ=39.12 745,458 kB -71.8%
bun 310,301 32.21 µs σ=17.8 1,523,437 kB best
deno 168,399 57.48 µs σ=15.91 1,376,953 kB -45.7%
deno-baseline 167,996 57.72 µs σ=15.75 1,376,953 kB -45.9%

http[realistic]

rps latency bytes relative
node 87,003 113.65 µs σ=38.67 937,500 kB -56.2%
bun 198,797 57.76 µs σ=126.17 1,855,468 kB best
deno 139,022 70.31 µs σ=22.18 1,474,609 kB -30.1%
deno-baseline 140,044 69.76 µs σ=21.18 1,484,375 kB -29.6%

start: Mon, 13 Nov 2023 17:34:04 GMT

id: 7ac10cbf-9400-43b5-bf50-78836bb288f1

server: 0f7ec490-6658-44e4-b62b-32f658666ad0

mmastrac added a commit that referenced this pull request Nov 13, 2023
…dy completion (#20822)

Use HttpRecord as response body so requests can be tracked all the way
to response body completion.

This allows Request properties to be accessed while the response body is
streaming.

Graceful shutdown now awaits a future instead of async spinning waiting
for requests to finish.

On the minimal benchmark this refactor improves performance an
additional 2% over pooling alone for a net 3% increase over the previous
deno main branch.

Builds upon #20809 and
#20770.

---------

Co-authored-by: Matt Mastracci <[email protected]>
kt3k pushed a commit that referenced this pull request Nov 17, 2023
Reuse existing existing allocations for HttpRecord and response
HeaderMap where possible.

At request end used allocations are returned to the pool and the pool
and the pool sized to 1/8th the current number of inflight requests.

For http1 hyper will reuse the response HeaderMap for the following
request on the connection.

Builds upon #20770

---------

Co-authored-by: Matt Mastracci <[email protected]>
kt3k pushed a commit that referenced this pull request Nov 17, 2023
…dy completion (#20822)

Use HttpRecord as response body so requests can be tracked all the way
to response body completion.

This allows Request properties to be accessed while the response body is
streaming.

Graceful shutdown now awaits a future instead of async spinning waiting
for requests to finish.

On the minimal benchmark this refactor improves performance an
additional 2% over pooling alone for a net 3% increase over the previous
deno main branch.

Builds upon #20809 and
#20770.

---------

Co-authored-by: Matt Mastracci <[email protected]>
zifeo pushed a commit to metatypedev/deno that referenced this pull request Nov 22, 2023
…#20809)

Reuse existing existing allocations for HttpRecord and response
HeaderMap where possible.

At request end used allocations are returned to the pool and the pool
and the pool sized to 1/8th the current number of inflight requests.

For http1 hyper will reuse the response HeaderMap for the following
request on the connection.

Builds upon denoland#20770

---------

Co-authored-by: Matt Mastracci <[email protected]>
zifeo pushed a commit to metatypedev/deno that referenced this pull request Nov 22, 2023
…dy completion (denoland#20822)

Use HttpRecord as response body so requests can be tracked all the way
to response body completion.

This allows Request properties to be accessed while the response body is
streaming.

Graceful shutdown now awaits a future instead of async spinning waiting
for requests to finish.

On the minimal benchmark this refactor improves performance an
additional 2% over pooling alone for a net 3% increase over the previous
deno main branch.

Builds upon denoland#20809 and
denoland#20770.

---------

Co-authored-by: Matt Mastracci <[email protected]>
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

3 participants