mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
perf(ext/http): Reduce size of ResponseBytesInner
(#24840)
I noticed
[`set_response_body`](ce42f82b5a/ext/http/service.rs (L439-L443)
)
was unexpectedly hot in profiles, with most of the time being spent in
`memmove`.
It turns out that `ResponseBytesInner` was _massive_ (5624 bytes), so
every time we moved a `ResponseBytesInner` (for instance in
`set_response_body`) we were doing a >5kb memmove, which adds up pretty
quickly.
This PR boxes the two larger variants (the compression streams),
shrinking `ResponseBytesInner` to a reasonable 48 bytes.
---
Benchmarked with a simple hello world server:
```ts
// hello-server.ts
Deno.serve((_req) => {
return new Response("Hello world");
});
// run with `deno run -A hello-server.ts`
// in separate terminal `wrk -d 10s http://127.0.0.1:8000`
```
Main:
```
Running 10s test @ http://127.0.0.1:8000/
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 53.39us 9.53us 0.98ms 92.78%
Req/Sec 86.57k 3.56k 91.58k 91.09%
1739319 requests in 10.10s, 248.81MB read
Requests/sec: 172220.92
Transfer/sec: 24.64MB
```
This PR:
```
Running 10s test @ http://127.0.0.1:8000/
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 45.44us 8.49us 0.91ms 90.04%
Req/Sec 100.65k 2.26k 102.65k 96.53%
2022296 requests in 10.10s, 289.29MB read
Requests/sec: 200226.20
Transfer/sec: 28.64MB
```
So a nice ~15% bump. (With response body compression, the gain is ~10%
for gzip and neutral for brotli)
This commit is contained in:
parent
5c54dc5840
commit
930ccf928a
2 changed files with 8 additions and 6 deletions
|
@ -92,9 +92,9 @@ pub enum ResponseBytesInner {
|
||||||
/// An uncompressed stream.
|
/// An uncompressed stream.
|
||||||
UncompressedStream(ResponseStream),
|
UncompressedStream(ResponseStream),
|
||||||
/// A GZip stream.
|
/// A GZip stream.
|
||||||
GZipStream(GZipResponseStream),
|
GZipStream(Box<GZipResponseStream>),
|
||||||
/// A Brotli stream.
|
/// A Brotli stream.
|
||||||
BrotliStream(BrotliResponseStream),
|
BrotliStream(Box<BrotliResponseStream>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for ResponseBytesInner {
|
impl std::fmt::Debug for ResponseBytesInner {
|
||||||
|
@ -133,9 +133,11 @@ impl ResponseBytesInner {
|
||||||
|
|
||||||
fn from_stream(compression: Compression, stream: ResponseStream) -> Self {
|
fn from_stream(compression: Compression, stream: ResponseStream) -> Self {
|
||||||
match compression {
|
match compression {
|
||||||
Compression::GZip => Self::GZipStream(GZipResponseStream::new(stream)),
|
Compression::GZip => {
|
||||||
|
Self::GZipStream(Box::new(GZipResponseStream::new(stream)))
|
||||||
|
}
|
||||||
Compression::Brotli => {
|
Compression::Brotli => {
|
||||||
Self::BrotliStream(BrotliResponseStream::new(stream))
|
Self::BrotliStream(Box::new(BrotliResponseStream::new(stream)))
|
||||||
}
|
}
|
||||||
_ => Self::UncompressedStream(stream),
|
_ => Self::UncompressedStream(stream),
|
||||||
}
|
}
|
||||||
|
|
|
@ -545,10 +545,10 @@ impl Body for HttpRecordResponse {
|
||||||
ready!(Pin::new(stm).poll_frame(cx))
|
ready!(Pin::new(stm).poll_frame(cx))
|
||||||
}
|
}
|
||||||
ResponseBytesInner::GZipStream(stm) => {
|
ResponseBytesInner::GZipStream(stm) => {
|
||||||
ready!(Pin::new(stm).poll_frame(cx))
|
ready!(Pin::new(stm.as_mut()).poll_frame(cx))
|
||||||
}
|
}
|
||||||
ResponseBytesInner::BrotliStream(stm) => {
|
ResponseBytesInner::BrotliStream(stm) => {
|
||||||
ready!(Pin::new(stm).poll_frame(cx))
|
ready!(Pin::new(stm.as_mut()).poll_frame(cx))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// This is where we retry the NoData response
|
// This is where we retry the NoData response
|
||||||
|
|
Loading…
Reference in a new issue