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(http): remove allocations checking upgrade and connection header values #17727

Merged
merged 6 commits into from
Feb 12, 2023

Conversation

dsherret
Copy link
Member

@dsherret dsherret commented Feb 10, 2023

It's more complicated, but doesn't require any allocations and seems to be much faster in certain cases and about the same in others. "match end string" is essentially the equivalent of "no match" and in this case it's about the same except when the string is very long, in which case this is faster. (Edit: it's even better when we only account for spaces and not all whitespace characters. See past edits for past result. I'm not sure if we need to account for other kinds of whitespace though, but it seems reasonable not to)

benchmark                              time (avg)             (min … max)       p75       p99      p995
------------------------------------------------------------------------- -----------------------------
string split   - start  - 10       164.73 ns/iter (158.82 ns … 239.79 ns) 169.81 ns 193.39 ns 206.38 ns
no allocations - start  - 10        53.19 ns/iter  (51.69 ns … 101.45 ns)  52.11 ns 100.54 ns 100.84 ns

string split   - middle - 10       173.93 ns/iter (167.28 ns … 212.13 ns) 179.27 ns 191.77 ns  194.3 ns
no allocations - middle - 10        82.08 ns/iter  (81.36 ns … 118.71 ns)  81.75 ns  91.87 ns 116.22 ns

string split   - end    - 10       174.19 ns/iter (166.92 ns … 321.94 ns) 175.21 ns 307.33 ns 310.69 ns
no allocations - end    - 10        80.92 ns/iter  (80.53 ns … 119.81 ns)  80.82 ns  83.24 ns  84.51 ns

string split   - start  - 60       624.13 ns/iter (613.78 ns … 633.12 ns) 625.51 ns 633.12 ns 633.12 ns
no allocations - start  - 60        58.83 ns/iter   (57.45 ns … 96.54 ns)  59.06 ns   63.7 ns  69.92 ns

string split   - middle - 60       678.37 ns/iter (669.62 ns … 795.17 ns) 676.32 ns 795.17 ns 795.17 ns
no allocations - middle - 60       262.21 ns/iter (259.12 ns … 364.51 ns) 261.59 ns 272.53 ns 357.89 ns

string split   - end    - 60       738.18 ns/iter   (711.06 ns … 1.45 µs) 723.81 ns   1.45 µs   1.45 µs
no allocations - end    - 60       411.62 ns/iter (401.15 ns … 427.53 ns) 417.06 ns 426.66 ns 427.53 ns

string split   - start  - 510        3.48 µs/iter     (3.45 µs … 3.56 µs)   3.49 µs   3.56 µs   3.56 µs
no allocations - start  - 510       60.28 ns/iter   (58.92 ns … 113.8 ns)  61.18 ns  63.01 ns   67.6 ns

string split   - middle - 510        3.84 µs/iter     (3.82 µs … 3.91 µs)   3.85 µs   3.91 µs   3.91 µs
no allocations - middle - 510        1.63 µs/iter     (1.61 µs … 1.68 µs)   1.63 µs   1.68 µs   1.68 µs

string split   - end    - 510        4.16 µs/iter     (4.11 µs … 4.48 µs)   4.14 µs   4.48 µs   4.48 µs
no allocations - end    - 510        3.22 µs/iter     (3.18 µs … 3.26 µs)   3.23 µs   3.26 µs   3.26 µs

string split   - start  - 5010      31.61 µs/iter    (29.6 µs … 172.8 µs)   31.3 µs   48.1 µs   90.2 µs
no allocations - start  - 5010      59.77 ns/iter   (58.23 ns … 84.54 ns)  60.49 ns  68.69 ns  70.82 ns

string split   - middle - 5010      35.07 µs/iter      (33.3 µs … 178 µs)   34.6 µs   64.7 µs   90.2 µs
no allocations - middle - 5010      15.32 µs/iter     (14.8 µs … 71.8 µs)   15.3 µs     18 µs     20 µs

string split   - end    - 5010      38.09 µs/iter    (36.2 µs … 298.1 µs)   37.3 µs   63.8 µs  110.2 µs
no allocations - end    - 5010      30.81 µs/iter     (29.8 µs … 92.2 µs)   30.7 µs   33.8 µs   39.3 µs

string split   - start  - 50010    314.52 µs/iter     (297.9 µs … 832 µs)  311.2 µs  436.2 µs  477.8 µs
no allocations - start  - 50010      58.9 ns/iter   (55.24 ns … 99.87 ns)  59.46 ns  67.48 ns   71.5 ns

string split   - middle - 50010    356.52 µs/iter   (334.8 µs … 892.7 µs)  345.7 µs  626.7 µs  690.1 µs
no allocations - middle - 50010    149.33 µs/iter   (144.4 µs … 285.9 µs)  150.4 µs  164.5 µs  196.9 µs

string split   - end    - 50010    371.93 µs/iter     (357.5 µs … 608 µs)  372.5 µs  482.8 µs  494.8 µs
no allocations - end    - 50010    301.67 µs/iter   (290.7 µs … 474.4 µs)  304.9 µs  389.2 µs  402.8 µs

string split   - start  - 500010     4.16 ms/iter     (3.58 ms … 13.8 ms)   3.75 ms      8 ms   13.8 ms
no allocations - start  - 500010    59.05 ns/iter  (55.19 ns … 102.26 ns)  59.12 ns  99.78 ns 101.16 ns

string split   - middle - 500010     5.09 ms/iter    (4.09 ms … 12.74 ms)   4.38 ms  11.83 ms  12.74 ms
no allocations - middle - 500010     1.49 ms/iter     (1.44 ms … 1.69 ms)    1.5 ms   1.65 ms   1.68 ms

string split   - end    - 500010     5.99 ms/iter    (4.61 ms … 19.13 ms)   5.03 ms  19.13 ms  19.13 ms
no allocations - end    - 500010     3.04 ms/iter     (2.91 ms … 3.55 ms)   3.09 ms    3.3 ms   3.55 ms

string split   - start  - 5000010   82.88 ms/iter  (38.48 ms … 152.05 ms) 109.65 ms 152.05 ms 152.05 ms
no allocations - start  - 5000010   57.35 ns/iter   (55.19 ns … 76.16 ns)  58.17 ns  65.62 ns  68.07 ns

string split   - middle - 5000010  126.47 ms/iter (111.69 ms … 147.51 ms) 145.67 ms 147.51 ms 147.51 ms
no allocations - middle - 5000010   14.88 ms/iter   (14.57 ms … 15.59 ms)  14.99 ms  15.59 ms  15.59 ms

string split   - end    - 5000010  134.12 ms/iter  (96.19 ms … 158.37 ms) 153.17 ms 158.37 ms 158.37 ms
no allocations - end    - 5000010   30.15 ms/iter   (29.63 ms … 30.69 ms)  30.35 ms  30.69 ms  30.69 ms

@dsherret dsherret marked this pull request as ready for review February 11, 2023 01:38
@@ -471,4 +468,76 @@ function upgradeHttp(req) {
return req[_deferred].promise;
}

const spaceCharCode = StringPrototypeCharCodeAt(" ", 0);
Copy link
Member Author

@dsherret dsherret Feb 11, 2023

Choose a reason for hiding this comment

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

I feel like it's reasonable to only check for plain old spaces instead of all whitespace? I couldn't find anywhere that explained exactly how this is supposed to work though. See past git history when it was checking all kinds of whitespace (and still faster).

Copy link
Collaborator

Choose a reason for hiding this comment

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

https://greenbytes.de/tech/webdav/rfc7230.html#whitespace

At least that particular spec website defines that horizontal tab is also allowed as whitespace.

Copy link
Collaborator

@aapoalas aapoalas left a comment

Choose a reason for hiding this comment

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

Should support tab as well for spec compliance.

@@ -14,6 +14,11 @@ import {
} from "./test_util.ts";
import { join } from "../../../test_util/std/path/mod.ts";

const {
buildCaseInsensitiveCommaValueFinder,
// @ts-expect-error TypeScript (as of 3.7) does not support indexing namespaces by symbol
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this could be done via a mapped type:https://discord.com/channels/684898665143206084/688040863313428503/1055570626787672165

Not relevant for this PR though.

Copy link
Collaborator

@aapoalas aapoalas left a comment

Choose a reason for hiding this comment

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

LGTM.

ext/http/01_http.js Outdated Show resolved Hide resolved
@aapoalas aapoalas enabled auto-merge (squash) February 12, 2023 20:48
@aapoalas aapoalas merged commit dc66fdc into denoland:main Feb 12, 2023
@dsherret dsherret deleted the perf_no_allocations_headers branch February 12, 2023 22:00
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.

2 participants