Skip to content

Commit

Permalink
perf(ext/http): use ServeHandlerInfo class instead of object literal (d…
Browse files Browse the repository at this point in the history
…enoland#20122)

This PR improves performance of `Deno.Serve` when providing `info`
argument by creating `ServeHandlerInfo` class instead of creating an
object literal with a getter on every request.

```js
Deno.serve((_req, info) => new Response(info.remoteAddr.transport) });
```

### Benchmarks
```
wrk -d 10s --latency https://127.0.0.1:4500
Running 10s test @ https://127.0.0.1:4500
  2 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    42.34us   16.30us   1.66ms   95.88%
    Req/Sec   118.17k     2.95k  127.38k    76.73%
  Latency Distribution
     50%   38.00us
     75%   41.00us
     90%   56.00us
     99%   83.00us
  2375298 requests in 10.10s, 319.40MB read
Requests/sec: 235177.04
Transfer/sec:     31.62MB
```

**main**
```
wrk -d 10s --latency https://127.0.0.1:4500
Running 10s test @ https://127.0.0.1:4500
  2 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    78.86us  211.06us   3.58ms   96.52%
    Req/Sec   105.90k     4.35k  117.41k    78.22%
  Latency Distribution
     50%   41.00us
     75%   53.00us
     90%   62.00us
     99%    1.18ms
  2127534 requests in 10.10s, 286.09MB read
Requests/sec: 210647.49
Transfer/sec:     28.33MB
```

```
cpu: 13th Gen Intel(R) Core(TM) i9-13900H
runtime: deno 1.36.0 (x86_64-unknown-linux-gnu)

benchmark                 time (avg)        iter/s             (min … max)       p75       p99      p995
-------------------------------------------------------------------------- -----------------------------
new ServeHandlerInfo      3.43 ns/iter 291,508,889.3    (3.07 ns … 12.21 ns)   3.42 ns   3.84 ns   3.87 ns
{} with getter           133.84 ns/iter   7,471,528.9   (92.9 ns … 458.95 ns) 132.45 ns 364.96 ns 429.43 ns
```


----
### Drawbacks:

`.remoteAddr` is now not enumerable

```
ServeHandlerInfo {}
```
vs
```
{ remoteAddr: [Getter] }
```
It'll break any code trying to iterate through `info` keys (Doubt
there's anyone doing it though)

```js
Deno.serve((req, info) => {
  console.log(Object.keys(info).length === 0) // true;
  return new Response("yes");
});
  • Loading branch information
marcosc90 authored Aug 10, 2023
1 parent 2d3d0a5 commit 6b1a976
Showing 1 changed file with 14 additions and 5 deletions.
19 changes: 14 additions & 5 deletions ext/http/00_serve.js
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,16 @@ class CallbackContext {
}
}

class ServeHandlerInfo {
#inner = null;
constructor(inner) {
this.#inner = inner;
}
get remoteAddr() {
return this.#inner.remoteAddr;
}
}

function fastSyncResponseOrStream(req, respBody) {
if (respBody === null || respBody === undefined) {
// Don't set the body
Expand Down Expand Up @@ -535,11 +545,10 @@ function mapToCallback(context, callback, onError) {
if (hasOneCallback) {
response = await callback(request);
} else {
response = await callback(request, {
get remoteAddr() {
return innerRequest.remoteAddr;
},
});
response = await callback(
request,
new ServeHandlerInfo(innerRequest),
);
}
} else {
response = await callback();
Expand Down

0 comments on commit 6b1a976

Please sign in to comment.