From 16b7c9cd8d0b23ea51ad0070c7589ebefb3d51fa Mon Sep 17 00:00:00 2001 From: Marcos Casagrande Date: Sat, 16 Sep 2023 23:15:15 +0200 Subject: [PATCH] perf(ext/http): optimize `set_response` for small responses (#20527) This PR introduces an optimization to `set_response` to reduce the overhead for responses with a payload size less than 64 bytes. Performance gains are more noticeable when `is_request_compressible` enters the slow path, ie: `-H 'Accept-Encoding: unknown'` ### Benchmarks ```js Deno.serve({ port: 3000 }, () => new Response("hello")); ``` ``` wrk -d 10s --latency -H 'Accept-Encoding: slow' http://127.0.0.1:3000 ``` --- **main** ``` Running 10s test @ http://127.0.0.1:3000 2 threads and 10 connections Thread Stats Avg Stdev Max +/- Stdev Latency 44.72us 28.12us 3.10ms 97.95% Req/Sec 112.73k 8.25k 123.66k 91.09% 2264092 requests in 10.10s, 308.77MB read Requests/sec: 224187.08 Transfer/sec: 30.57MB ``` **this PR** ``` Running 10s test @ http://127.0.0.1:3000 2 threads and 10 connections Thread Stats Avg Stdev Max +/- Stdev Latency 42.91us 20.57us 2.04ms 97.36% Req/Sec 116.61k 7.95k 204.81k 88.56% 2330970 requests in 10.10s, 317.89MB read Requests/sec: 230806.32 Transfer/sec: 31.48MB ``` --- ext/http/http_next.rs | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/ext/http/http_next.rs b/ext/http/http_next.rs index 94f6f1241a..c6e3ac3841 100644 --- a/ext/http/http_next.rs +++ b/ext/http/http_next.rs @@ -463,7 +463,18 @@ pub fn op_http_set_response_trailers( *http.trailers().borrow_mut() = Some(trailer_map); } -fn is_request_compressible(headers: &HeaderMap) -> Compression { +fn is_request_compressible( + length: Option, + headers: &HeaderMap, +) -> Compression { + if let Some(length) = length { + // By the time we add compression headers and Accept-Encoding, it probably doesn't make sense + // to compress stuff that's smaller than this. + if length < 64 { + return Compression::None; + } + } + let Some(accept_encoding) = headers.get(ACCEPT_ENCODING) else { return Compression::None; }; @@ -521,17 +532,9 @@ fn is_response_compressible(headers: &HeaderMap) -> bool { fn modify_compressibility_from_response( compression: Compression, - length: Option, headers: &mut HeaderMap, ) -> Compression { ensure_vary_accept_encoding(headers); - if let Some(length) = length { - // By the time we add compression headers and Accept-Encoding, it probably doesn't make sense - // to compress stuff that's smaller than this. - if length < 64 { - return Compression::None; - } - } if compression == Compression::None { return Compression::None; } @@ -592,13 +595,11 @@ fn set_response( // do all of this work to send the response. if !http.cancelled() { let resource = http.take_resource(); - let compression = is_request_compressible(&http.request_parts().headers); + let compression = + is_request_compressible(length, &http.request_parts().headers); let response = http.response(); - let compression = modify_compressibility_from_response( - compression, - length, - response.headers_mut(), - ); + let compression = + modify_compressibility_from_response(compression, response.headers_mut()); response .body_mut() .initialize(response_fn(compression), resource);