Skip to content

Commit

Permalink
perf: cut allocations (#691)
Browse files Browse the repository at this point in the history
**Summary of Changes**

Hello!

I found a few "low hanging" allocations that can be deferred until
needed or
 even skipped entirely.

With all the optimizations combined, we can see the best improvement for
simple, static routes (like a `/status` endpoint) that do not read the
`Route`
from the request context via `CurrentRoute` and do not populate any
vars.
On these routes, we can process requests with a single allocation for
the
 `RouteMatch` object. Previously there were 9 extra allocations.
For said routes the processing overhead (ns/op) in mux dropped by 75%,
which is
 a speedup of 4x.

Other routes can expect to see a double-digit percentage reduction in
both
 processing overhead (ns/op) and allocations as well.
These are driven by merging the context population into a single
operation,
 eliminating two of ten allocations.

(Eliminating that last allocation for the `RouteMatch` in the best case
requires significant refactoring to maintain full backwards
compatibility.
 Something for another day.)

Each commit message contains benchmark results for showcasing particular
(micro) optimizations in reduced allocations and in a few cases notable
direct
 CPU time savings.

I also ran longer benchmarks with 100 repetitions in multiple settings
on
 different generations of (server) CPUs.
First, there is the full set of benchmarks in this repository and
second, the
popular benchmarks
https://github.com/julienschmidt/go-http-routing-benchmark.

All but the last change are entirely "free", as in they do not cut
features for
 gains in performance. The last change for omitting the `Route` from the
context is behind an optional flag that users can opt in when they do
not read
 the `Route` from the request context.
Said flag is stored local in a `Router`, so users can enable/disable the
flag
 on Subrouters individually.

<details>
<summary> Benchmark results </summary>

I added all the new benchmarks onto a `baseline` branch for comparing
the
performance of the changes, tip is
0eba4f5731f329d9a95b67359e795344343a6119.

I'm running these tests on "shared" compute instances (and my Laptop),
so
 expect some noise (and frequency scaling on the i7).

<details>
<summary> mux project benchmarks </summary>

You can reproduce these benchmarks using docker, pinned to CPU 1:

```bash
docker run --rm --pull always -v /logs:/logs --cpuset-cpus 1 -d golang:1.18 bash -exc 'git clone https://github.com/das7pad/mux.git && cd mux && for branch in baseline perf-cut-allocations; do git checkout "$branch" && go test -benchmem -bench . -count 100 -timeout 1h > "/logs/$branch-all.txt"; done; go install golang.org/x/perf/cmd/benchstat@latest; benchstat /logs/baseline-all.txt /logs/perf-cut-allocations-all.txt > /logs/compare-all.txt'
```

<details>
<summary> Modern Xeon E, 3.4 GHz </summary>

```
goos: linux
goarch: amd64
pkg: github.com/gorilla/mux
cpu: Intel(R) Xeon(R) E-2278G CPU @ 3.40GHz

name                                 old time/op    new time/op    delta
Mux                                    1.09碌s 卤 5%    0.96碌s 卤 6%  -12.33%  (p=0.000 n=90+90)
MuxSimple/default                       654ns 卤 5%     333ns 卤 4%  -49.06%  (p=0.000 n=90+94)
MuxSimple/omit_route_from_ctx           655ns 卤 5%     146ns 卤 3%  -77.78%  (p=0.000 n=93+95)
MuxAlternativeInRegexp                 1.58碌s 卤 5%    1.30碌s 卤 3%  -17.75%  (p=0.000 n=92+90)
ManyPathVariables                      1.82碌s 卤 6%    1.65碌s 卤 5%   -9.73%  (p=0.000 n=94+93)
PopulateContext/no_populated_vars       665ns 卤 5%     339ns 卤 5%  -48.97%  (p=0.000 n=95+96)
PopulateContext/empty_var               910ns 卤 5%     763ns 卤 6%  -16.16%  (p=0.000 n=84+87)
PopulateContext/populated_vars          974ns 卤10%     807ns 卤 7%  -17.13%  (p=0.000 n=96+89)
PopulateContext/omit_route_/static      664ns 卤 5%     148ns 卤 3%  -77.66%  (p=0.000 n=94+89)
PopulateContext/omit_route_/dynamic     915ns 卤 6%     741ns 卤 6%  -18.98%  (p=0.000 n=90+94)
_findQueryKey/0                         158ns 卤 2%     146ns 卤 2%   -7.07%  (p=0.000 n=91+88)
_findQueryKey/1                         198ns 卤 4%     196ns 卤 5%   -0.56%  (p=0.001 n=92+95)
_findQueryKey/2                         710ns 卤 4%     705ns 卤 4%   -0.80%  (p=0.000 n=94+94)
_findQueryKey/3                         804ns 卤 4%     798ns 卤 5%   -0.82%  (p=0.000 n=90+94)
_findQueryKey/4                        3.85ns 卤 2%    3.85ns 卤 3%     ~     (p=0.224 n=89+93)
_findQueryKeyGoLib/0                    664ns 卤 4%     668ns 卤 5%   +0.67%  (p=0.030 n=97+94)
_findQueryKeyGoLib/1                    359ns 卤 6%     359ns 卤 6%     ~     (p=0.830 n=94+93)
_findQueryKeyGoLib/2                   2.24碌s 卤 3%    2.23碌s 卤 4%   -0.37%  (p=0.041 n=95+93)
_findQueryKeyGoLib/3                   2.94碌s 卤 4%    2.92碌s 卤 3%   -0.68%  (p=0.001 n=90+94)
_findQueryKeyGoLib/4                   3.63ns 卤 4%    3.62ns 卤 3%   -0.38%  (p=0.014 n=91+88)

name                                 old alloc/op   new alloc/op   delta
Mux                                    1.31kB 卤 0%    0.91kB 卤 0%  -30.49%  (p=0.000 n=100+100)
MuxSimple/default                      1.01kB 卤 0%    0.50kB 卤 0%  -50.79%  (p=0.000 n=100+100)
MuxSimple/omit_route_from_ctx          1.01kB 卤 0%    0.05kB 卤 0%  -95.24%  (p=0.000 n=100+100)
MuxAlternativeInRegexp                 2.62kB 卤 0%    1.82kB 卤 0%  -30.49%  (p=0.000 n=100+100)
ManyPathVariables                      1.53kB 卤 1%    1.13kB 卤 0%  -26.45%  (p=0.000 n=99+93)
PopulateContext/no_populated_vars      1.01kB 卤 0%    0.50kB 卤 0%  -50.79%  (p=0.000 n=100+100)
PopulateContext/empty_var              1.33kB 卤 0%    0.93kB 卤 0%  -30.12%  (p=0.000 n=100+100)
PopulateContext/populated_vars         1.31kB 卤 0%    0.91kB 卤 0%  -30.49%  (p=0.000 n=100+100)
PopulateContext/omit_route_/static     1.01kB 卤 0%    0.05kB 卤 0%  -95.24%  (p=0.000 n=100+100)
PopulateContext/omit_route_/dynamic    1.33kB 卤 0%    0.88kB 卤 0%  -33.73%  (p=0.000 n=100+100)
_findQueryKey/0                         0.00B          0.00B          ~     (all equal)
_findQueryKey/1                         40.0B 卤 0%     40.0B 卤 0%     ~     (all equal)
_findQueryKey/2                          483B 卤 0%      483B 卤 0%     ~     (all equal)
_findQueryKey/3                          543B 卤 0%      543B 卤 0%     ~     (all equal)
_findQueryKey/4                         0.00B          0.00B          ~     (all equal)
_findQueryKeyGoLib/0                     864B 卤 0%      864B 卤 0%     ~     (all equal)
_findQueryKeyGoLib/1                     432B 卤 0%      432B 卤 0%     ~     (all equal)
_findQueryKeyGoLib/2                   1.54kB 卤 0%    1.54kB 卤 0%     ~     (all equal)
_findQueryKeyGoLib/3                   1.98kB 卤 0%    1.98kB 卤 0%     ~     (all equal)
_findQueryKeyGoLib/4                    0.00B          0.00B          ~     (all equal)

name                                 old allocs/op  new allocs/op  delta
Mux                                      10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
MuxSimple/default                        9.00 卤 0%      4.00 卤 0%  -55.56%  (p=0.000 n=100+100)
MuxSimple/omit_route_from_ctx            9.00 卤 0%      1.00 卤 0%  -88.89%  (p=0.000 n=100+100)
MuxAlternativeInRegexp                   20.0 卤 0%      16.0 卤 0%  -20.00%  (p=0.000 n=100+100)
ManyPathVariables                        14.0 卤 0%      12.0 卤 0%  -14.29%  (p=0.000 n=100+100)
PopulateContext/no_populated_vars        9.00 卤 0%      4.00 卤 0%  -55.56%  (p=0.000 n=100+100)
PopulateContext/empty_var                11.0 卤 0%       9.0 卤 0%  -18.18%  (p=0.000 n=100+100)
PopulateContext/populated_vars           10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
PopulateContext/omit_route_/static       9.00 卤 0%      1.00 卤 0%  -88.89%  (p=0.000 n=100+100)
PopulateContext/omit_route_/dynamic      11.0 卤 0%       8.0 卤 0%  -27.27%  (p=0.000 n=100+100)
_findQueryKey/0                          0.00           0.00          ~     (all equal)
_findQueryKey/1                          3.00 卤 0%      3.00 卤 0%     ~     (all equal)
_findQueryKey/2                          10.0 卤 0%      10.0 卤 0%     ~     (all equal)
_findQueryKey/3                          11.0 卤 0%      11.0 卤 0%     ~     (all equal)
_findQueryKey/4                          0.00           0.00          ~     (all equal)
_findQueryKeyGoLib/0                     8.00 卤 0%      8.00 卤 0%     ~     (all equal)
_findQueryKeyGoLib/1                     4.00 卤 0%      4.00 卤 0%     ~     (all equal)
_findQueryKeyGoLib/2                     24.0 卤 0%      24.0 卤 0%     ~     (all equal)
_findQueryKeyGoLib/3                     28.0 卤 0%      28.0 卤 0%     ~     (all equal)
_findQueryKeyGoLib/4                     0.00           0.00          ~     (all equal)
```

---

</details>

<details>
<summary> Older Xeon Gold, 2.3 GHz </summary>

(Actual CPU identifier is rather `Intel(R) Xeon(R) Gold 5122 CPU @
2.30GHz`)
```
goos: linux
goarch: amd64
pkg: github.com/gorilla/mux
cpu: Intel Xeon Processor (Skylake, IBRS) 

name                                 old time/op    new time/op    delta
Mux                                    1.61碌s 卤 6%    1.43碌s 卤 6%  -11.38%  (p=0.000 n=97+96)
MuxSimple/default                       979ns 卤 8%     508ns 卤 7%  -48.15%  (p=0.000 n=93+98)
MuxSimple/omit_route_from_ctx          1.00碌s 卤12%    0.22碌s 卤 4%  -77.76%  (p=0.000 n=99+96)
MuxAlternativeInRegexp                 2.40碌s 卤 9%    2.03碌s 卤12%  -15.15%  (p=0.000 n=94+98)
ManyPathVariables                      2.77碌s 卤 8%    2.60碌s 卤12%   -6.17%  (p=0.000 n=94+99)
PopulateContext/no_populated_vars      1.03碌s 卤11%    0.54碌s 卤13%  -47.57%  (p=0.000 n=94+98)
PopulateContext/empty_var              1.35碌s 卤 6%    1.23碌s 卤11%   -9.01%  (p=0.000 n=95+96)
PopulateContext/populated_vars         1.40碌s 卤 8%    1.30碌s 卤14%   -6.98%  (p=0.000 n=97+99)
PopulateContext/omit_route_/static      989ns 卤 7%     239ns 卤10%  -75.78%  (p=0.000 n=99+99)
PopulateContext/omit_route_/dynamic    1.34碌s 卤 7%    1.21碌s 卤15%  -10.04%  (p=0.000 n=95+99)
_findQueryKey/0                         242ns 卤 8%     228ns 卤 8%   -6.00%  (p=0.000 n=97+95)
_findQueryKey/1                         304ns 卤 7%     309ns 卤 9%   +1.60%  (p=0.002 n=97+97)
_findQueryKey/2                        1.08碌s 卤 8%    1.14碌s 卤10%   +5.28%  (p=0.000 n=99+97)
_findQueryKey/3                        1.20碌s 卤 6%    1.23碌s 卤 9%   +2.03%  (p=0.000 n=92+99)
_findQueryKey/4                        5.86ns 卤 4%    5.89ns 卤 5%   +0.56%  (p=0.041 n=93+96)
_findQueryKeyGoLib/0                    992ns 卤 7%    1067ns 卤11%   +7.59%  (p=0.000 n=94+98)
_findQueryKeyGoLib/1                    528ns 卤 6%     571ns 卤11%   +8.04%  (p=0.000 n=97+100)
_findQueryKeyGoLib/2                   3.46碌s 卤 6%    3.60碌s 卤10%   +4.18%  (p=0.000 n=96+95)
_findQueryKeyGoLib/3                   4.54碌s 卤 6%    4.75碌s 卤11%   +4.62%  (p=0.000 n=92+98)
_findQueryKeyGoLib/4                   5.50ns 卤 4%    5.62ns 卤 7%   +2.14%  (p=0.000 n=91+96)

name                                 old alloc/op   new alloc/op   delta
Mux                                    1.31kB 卤 0%    0.91kB 卤 0%  -30.49%  (p=0.000 n=100+100)
MuxSimple/default                      1.01kB 卤 0%    0.50kB 卤 0%  -50.79%  (p=0.000 n=100+100)
MuxSimple/omit_route_from_ctx          1.01kB 卤 0%    0.05kB 卤 0%  -95.24%  (p=0.000 n=100+100)
MuxAlternativeInRegexp                 2.62kB 卤 0%    1.82kB 卤 0%  -30.49%  (p=0.000 n=100+100)
ManyPathVariables                      1.52kB 卤 0%    1.12kB 卤 0%  -26.50%  (p=0.000 n=92+97)
PopulateContext/no_populated_vars      1.01kB 卤 0%    0.50kB 卤 0%  -50.79%  (p=0.000 n=100+100)
PopulateContext/empty_var              1.33kB 卤 0%    0.93kB 卤 0%  -30.12%  (p=0.000 n=100+100)
PopulateContext/populated_vars         1.31kB 卤 0%    0.91kB 卤 0%  -30.49%  (p=0.000 n=100+100)
PopulateContext/omit_route_/static     1.01kB 卤 0%    0.05kB 卤 0%  -95.24%  (p=0.000 n=100+100)
PopulateContext/omit_route_/dynamic    1.33kB 卤 0%    0.88kB 卤 0%  -33.73%  (p=0.000 n=100+100)
_findQueryKey/0                         0.00B          0.00B          ~     (all equal)
_findQueryKey/1                         40.0B 卤 0%     40.0B 卤 0%     ~     (all equal)
_findQueryKey/2                          483B 卤 0%      483B 卤 0%     ~     (all equal)
_findQueryKey/3                          543B 卤 0%      543B 卤 0%     ~     (all equal)
_findQueryKey/4                         0.00B          0.00B          ~     (all equal)
_findQueryKeyGoLib/0                     864B 卤 0%      864B 卤 0%     ~     (all equal)
_findQueryKeyGoLib/1                     432B 卤 0%      432B 卤 0%     ~     (all equal)
_findQueryKeyGoLib/2                   1.54kB 卤 0%    1.54kB 卤 0%     ~     (all equal)
_findQueryKeyGoLib/3                   1.98kB 卤 0%    1.98kB 卤 0%     ~     (all equal)
_findQueryKeyGoLib/4                    0.00B          0.00B          ~     (all equal)

name                                 old allocs/op  new allocs/op  delta
Mux                                      10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
MuxSimple/default                        9.00 卤 0%      4.00 卤 0%  -55.56%  (p=0.000 n=100+100)
MuxSimple/omit_route_from_ctx            9.00 卤 0%      1.00 卤 0%  -88.89%  (p=0.000 n=100+100)
MuxAlternativeInRegexp                   20.0 卤 0%      16.0 卤 0%  -20.00%  (p=0.000 n=100+100)
ManyPathVariables                        14.0 卤 0%      12.0 卤 0%  -14.29%  (p=0.000 n=100+100)
PopulateContext/no_populated_vars        9.00 卤 0%      4.00 卤 0%  -55.56%  (p=0.000 n=100+100)
PopulateContext/empty_var                11.0 卤 0%       9.0 卤 0%  -18.18%  (p=0.000 n=100+100)
PopulateContext/populated_vars           10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
PopulateContext/omit_route_/static       9.00 卤 0%      1.00 卤 0%  -88.89%  (p=0.000 n=100+100)
PopulateContext/omit_route_/dynamic      11.0 卤 0%       8.0 卤 0%  -27.27%  (p=0.000 n=100+100)
_findQueryKey/0                          0.00           0.00          ~     (all equal)
_findQueryKey/1                          3.00 卤 0%      3.00 卤 0%     ~     (all equal)
_findQueryKey/2                          10.0 卤 0%      10.0 卤 0%     ~     (all equal)
_findQueryKey/3                          11.0 卤 0%      11.0 卤 0%     ~     (all equal)
_findQueryKey/4                          0.00           0.00          ~     (all equal)
_findQueryKeyGoLib/0                     8.00 卤 0%      8.00 卤 0%     ~     (all equal)
_findQueryKeyGoLib/1                     4.00 卤 0%      4.00 卤 0%     ~     (all equal)
_findQueryKeyGoLib/2                     24.0 卤 0%      24.0 卤 0%     ~     (all equal)
_findQueryKeyGoLib/3                     28.0 卤 0%      28.0 卤 0%     ~     (all equal)
_findQueryKeyGoLib/4                     0.00           0.00          ~     (all equal)
```

---

</details>

<details>
<summary> Older Xeon E, 2.4 GHz </summary>

```
goos: linux
goarch: amd64
pkg: github.com/gorilla/mux
cpu: Intel(R) Xeon(R) CPU E5-2680 v4 @ 2.40GHz

name                                 old time/op    new time/op    delta
Mux                                    1.81碌s 卤13%    1.57碌s 卤10%  -13.50%  (p=0.000 n=99+97)
MuxSimple/default                      1.09碌s 卤 8%    0.55碌s 卤10%  -49.51%  (p=0.000 n=96+95)
MuxSimple/omit_route_from_ctx          1.08碌s 卤10%    0.25碌s 卤 8%  -76.66%  (p=0.000 n=95+94)
MuxAlternativeInRegexp                 2.59碌s 卤12%    2.14碌s 卤13%  -17.06%  (p=0.000 n=95+92)
ManyPathVariables                      3.11碌s 卤 9%    2.78碌s 卤10%  -10.62%  (p=0.000 n=96+99)
PopulateContext/no_populated_vars      1.09碌s 卤 9%    0.56碌s 卤 7%  -48.63%  (p=0.000 n=94+93)
PopulateContext/empty_var              1.48碌s 卤 9%    1.28碌s 卤12%  -13.52%  (p=0.000 n=97+96)
PopulateContext/populated_vars         1.56碌s 卤11%    1.34碌s 卤10%  -13.84%  (p=0.000 n=96+97)
PopulateContext/omit_route_/static     1.08碌s 卤 9%    0.26碌s 卤 9%  -75.89%  (p=0.000 n=98+97)
PopulateContext/omit_route_/dynamic    1.50碌s 卤11%    1.20碌s 卤 9%  -19.96%  (p=0.000 n=94+93)
_findQueryKey/0                         254ns 卤 8%     243ns 卤 8%   -4.44%  (p=0.000 n=96+91)
_findQueryKey/1                         336ns 卤 7%     336ns 卤 8%     ~     (p=0.920 n=96+95)
_findQueryKey/2                        1.25碌s 卤12%    1.27碌s 卤14%   +1.55%  (p=0.043 n=97+98)
_findQueryKey/3                        1.37碌s 卤 8%    1.38碌s 卤 9%   +0.97%  (p=0.030 n=97+95)
_findQueryKey/4                        5.93ns 卤 6%    5.97ns 卤 7%     ~     (p=0.074 n=97+97)
_findQueryKeyGoLib/0                   1.07碌s 卤 9%    1.13碌s 卤10%   +4.99%  (p=0.000 n=96+95)
_findQueryKeyGoLib/1                    581ns 卤 8%     586ns 卤 9%     ~     (p=0.089 n=96+99)
_findQueryKeyGoLib/2                   3.93碌s 卤12%    3.80碌s 卤10%   -3.31%  (p=0.000 n=96+91)
_findQueryKeyGoLib/3                   5.18碌s 卤10%    5.06碌s 卤 8%   -2.27%  (p=0.000 n=98+99)
_findQueryKeyGoLib/4                   6.52ns 卤 6%    6.49ns 卤 4%     ~     (p=0.232 n=96+94)

name                                 old alloc/op   new alloc/op   delta
Mux                                    1.31kB 卤 0%    0.91kB 卤 0%  -30.49%  (p=0.000 n=100+100)
MuxSimple/default                      1.01kB 卤 0%    0.50kB 卤 0%  -50.79%  (p=0.000 n=100+100)
MuxSimple/omit_route_from_ctx          1.01kB 卤 0%    0.05kB 卤 0%  -95.24%  (p=0.000 n=100+100)
MuxAlternativeInRegexp                 2.62kB 卤 0%    1.82kB 卤 0%  -30.49%  (p=0.000 n=100+100)
ManyPathVariables                      1.52kB 卤 0%    1.12kB 卤 1%  -26.58%  (p=0.000 n=92+96)
PopulateContext/no_populated_vars      1.01kB 卤 0%    0.50kB 卤 0%  -50.79%  (p=0.000 n=100+100)
PopulateContext/empty_var              1.33kB 卤 0%    0.93kB 卤 0%  -30.12%  (p=0.000 n=100+100)
PopulateContext/populated_vars         1.31kB 卤 0%    0.91kB 卤 0%  -30.49%  (p=0.000 n=100+100)
PopulateContext/omit_route_/static     1.01kB 卤 0%    0.05kB 卤 0%  -95.24%  (p=0.000 n=100+100)
PopulateContext/omit_route_/dynamic    1.33kB 卤 0%    0.88kB 卤 0%  -33.73%  (p=0.000 n=100+100)
_findQueryKey/0                         0.00B          0.00B          ~     (all equal)
_findQueryKey/1                         40.0B 卤 0%     40.0B 卤 0%     ~     (all equal)
_findQueryKey/2                          483B 卤 0%      483B 卤 0%     ~     (all equal)
_findQueryKey/3                          543B 卤 0%      543B 卤 0%     ~     (all equal)
_findQueryKey/4                         0.00B          0.00B          ~     (all equal)
_findQueryKeyGoLib/0                     864B 卤 0%      864B 卤 0%     ~     (all equal)
_findQueryKeyGoLib/1                     432B 卤 0%      432B 卤 0%     ~     (all equal)
_findQueryKeyGoLib/2                   1.54kB 卤 0%    1.54kB 卤 0%     ~     (all equal)
_findQueryKeyGoLib/3                   1.98kB 卤 0%    1.98kB 卤 0%     ~     (all equal)
_findQueryKeyGoLib/4                    0.00B          0.00B          ~     (all equal)

name                                 old allocs/op  new allocs/op  delta
Mux                                      10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
MuxSimple/default                        9.00 卤 0%      4.00 卤 0%  -55.56%  (p=0.000 n=100+100)
MuxSimple/omit_route_from_ctx            9.00 卤 0%      1.00 卤 0%  -88.89%  (p=0.000 n=100+100)
MuxAlternativeInRegexp                   20.0 卤 0%      16.0 卤 0%  -20.00%  (p=0.000 n=100+100)
ManyPathVariables                        14.0 卤 0%      12.0 卤 0%  -14.29%  (p=0.000 n=100+100)
PopulateContext/no_populated_vars        9.00 卤 0%      4.00 卤 0%  -55.56%  (p=0.000 n=100+100)
PopulateContext/empty_var                11.0 卤 0%       9.0 卤 0%  -18.18%  (p=0.000 n=100+100)
PopulateContext/populated_vars           10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
PopulateContext/omit_route_/static       9.00 卤 0%      1.00 卤 0%  -88.89%  (p=0.000 n=100+100)
PopulateContext/omit_route_/dynamic      11.0 卤 0%       8.0 卤 0%  -27.27%  (p=0.000 n=100+100)
_findQueryKey/0                          0.00           0.00          ~     (all equal)
_findQueryKey/1                          3.00 卤 0%      3.00 卤 0%     ~     (all equal)
_findQueryKey/2                          10.0 卤 0%      10.0 卤 0%     ~     (all equal)
_findQueryKey/3                          11.0 卤 0%      11.0 卤 0%     ~     (all equal)
_findQueryKey/4                          0.00           0.00          ~     (all equal)
_findQueryKeyGoLib/0                     8.00 卤 0%      8.00 卤 0%     ~     (all equal)
_findQueryKeyGoLib/1                     4.00 卤 0%      4.00 卤 0%     ~     (all equal)
_findQueryKeyGoLib/2                     24.0 卤 0%      24.0 卤 0%     ~     (all equal)
_findQueryKeyGoLib/3                     28.0 卤 0%      28.0 卤 0%     ~     (all equal)
_findQueryKeyGoLib/4                     0.00           0.00          ~     (all equal)
```

---

</details>

---

</details>


<details>
<summary> Popular go-http-routing-benchmark </summary>

I pushed three branches for comparison to my fork:
https://github.com/das7pad/go-http-routing-benchmark

- `before`, this is the baseline branch mentioned above
- `after`, this is the PR revision
- `after-omit-route`, like `after` with the `OmitRouteFromContext` flag
enabled

You can reproduce these benchmarks using docker, pinned to CPU 1:

```bash
docker run --rm --pull always -v /logs:/logs --cpuset-cpus 1 -d golang:1.18 bash -exc 'git clone https://github.com/das7pad/go-http-routing-benchmark.git && cd go-http-routing-benchmark && for branch in before after after-omit-route; do git checkout "$branch" && go test -benchmem -bench Gorilla -count 100 -timeout 1h > "/logs/$branch.txt"; done; go install golang.org/x/perf/cmd/benchstat@latest; benchstat /logs/before.txt /logs/after.txt > /logs/compare-before-vs-after.txt; benchstat /logs/before.txt /logs/after-omit-route.txt > /logs/compare-before-vs-after-omit-route.txt'
```

<details>
<summary> Modern Xeon E, 3.4 GHz </summary>

Before vs After with omit Route flag enabled

```
goos: linux
goarch: amd64
pkg: github.com/gorilla/mux
cpu: Intel(R) Xeon(R) E-2278G CPU @ 3.40GHz

name                     old time/op    new time/op    delta
GorillaMux_Param           1.86碌s 卤13%    1.37碌s 卤 6%  -26.08%  (p=0.000 n=94+96)
GorillaMux_Param5          2.61碌s 卤 4%    2.20碌s 卤 4%  -15.92%  (p=0.000 n=89+95)
GorillaMux_Param20         6.13碌s 卤 3%    3.98碌s 卤 4%  -35.07%  (p=0.000 n=90+94)
GorillaMux_ParamWrite      1.87碌s 卤 5%    1.43碌s 卤 8%  -23.51%  (p=0.000 n=95+92)
GorillaMux_GithubStatic    3.77碌s 卤 5%    2.43碌s 卤 4%  -35.40%  (p=0.000 n=96+96)
GorillaMux_GithubParam     5.68碌s 卤 6%    5.21碌s 卤 5%   -8.32%  (p=0.000 n=93+93)
GorillaMux_GithubAll       2.86ms 卤 6%    2.71ms 卤 4%   -5.44%  (p=0.000 n=99+96)
GorillaMux_GPlusStatic     1.31碌s 卤 5%    0.21碌s 卤 4%  -84.29%  (p=0.000 n=92+95)
GorillaMux_GPlusParam      2.37碌s 卤 3%    1.96碌s 卤 2%  -17.42%  (p=0.000 n=96+94)
GorillaMux_GPlus2Params    4.43碌s 卤 3%    3.90碌s 卤 3%  -11.89%  (p=0.000 n=91+90)
GorillaMux_GPlusAll        37.1碌s 卤 6%    28.9碌s 卤 5%  -22.26%  (p=0.000 n=93+92)
GorillaMux_ParseStatic     1.55碌s 卤 5%    0.42碌s 卤 4%  -72.78%  (p=0.000 n=95+91)
GorillaMux_ParseParam      1.88碌s 卤 7%    1.41碌s 卤 7%  -24.66%  (p=0.000 n=94+93)
GorillaMux_Parse2Params    2.21碌s 卤 4%    1.74碌s 卤 6%  -21.16%  (p=0.000 n=94+96)
GorillaMux_ParseAll        71.8碌s 卤 4%    51.3碌s 卤 4%  -28.51%  (p=0.000 n=93+94)
GorillaMux_StaticAll        771碌s 卤 4%     492碌s 卤 3%  -36.17%  (p=0.000 n=95+90)

name                     old alloc/op   new alloc/op   delta
GorillaMux_Param           1.31kB 卤 0%    0.86kB 卤 0%  -34.15%  (p=0.000 n=100+100)
GorillaMux_Param5          1.38kB 卤 0%    0.93kB 卤 0%  -32.56%  (p=0.000 n=100+100)
GorillaMux_Param20         3.48kB 卤 0%    2.10kB 卤 0%  -39.86%  (p=0.000 n=100+80)
GorillaMux_ParamWrite      1.31kB 卤 0%    0.86kB 卤 0%  -34.15%  (p=0.000 n=100+100)
GorillaMux_GithubStatic    1.01kB 卤 0%    0.05kB 卤 0%  -95.24%  (p=0.000 n=100+100)
GorillaMux_GithubParam     1.33kB 卤 0%    0.88kB 卤 0%  -33.73%  (p=0.000 n=100+100)
GorillaMux_GithubAll        258kB 卤 0%     149kB 卤 0%  -42.37%  (p=0.000 n=86+99)
GorillaMux_GPlusStatic     1.01kB 卤 0%    0.05kB 卤 0%  -95.24%  (p=0.000 n=100+100)
GorillaMux_GPlusParam      1.31kB 卤 0%    0.86kB 卤 0%  -34.15%  (p=0.000 n=100+100)
GorillaMux_GPlus2Params    1.33kB 卤 0%    0.88kB 卤 0%  -33.73%  (p=0.000 n=100+100)
GorillaMux_GPlusAll        16.5kB 卤 0%     9.7kB 卤 0%  -41.43%  (p=0.000 n=100+100)
GorillaMux_ParseStatic     1.01kB 卤 0%    0.05kB 卤 0%  -95.24%  (p=0.000 n=100+100)
GorillaMux_ParseParam      1.31kB 卤 0%    0.86kB 卤 0%  -34.15%  (p=0.000 n=100+100)
GorillaMux_Parse2Params    1.33kB 卤 0%    0.88kB 卤 0%  -33.73%  (p=0.000 n=100+100)
GorillaMux_ParseAll        31.1kB 卤 0%    14.4kB 卤 0%  -53.88%  (p=0.000 n=100+100)
GorillaMux_StaticAll        158kB 卤 0%       8kB 卤 0%  -95.24%  (p=0.000 n=100+100)

name                     old allocs/op  new allocs/op  delta
GorillaMux_Param             10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=100+100)
GorillaMux_Param5            10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=100+100)
GorillaMux_Param20           12.0 卤 0%       7.0 卤 0%  -41.67%  (p=0.000 n=100+100)
GorillaMux_ParamWrite        10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=100+100)
GorillaMux_GithubStatic      9.00 卤 0%      1.00 卤 0%  -88.89%  (p=0.000 n=100+100)
GorillaMux_GithubParam       10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=100+100)
GorillaMux_GithubAll        1.99k 卤 0%     1.21k 卤 0%  -39.57%  (p=0.000 n=100+100)
GorillaMux_GPlusStatic       9.00 卤 0%      1.00 卤 0%  -88.89%  (p=0.000 n=100+100)
GorillaMux_GPlusParam        10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=100+100)
GorillaMux_GPlus2Params      10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=100+100)
GorillaMux_GPlusAll           128 卤 0%        79 卤 0%  -38.28%  (p=0.000 n=100+100)
GorillaMux_ParseStatic       9.00 卤 0%      1.00 卤 0%  -88.89%  (p=0.000 n=100+100)
GorillaMux_ParseParam        10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=100+100)
GorillaMux_Parse2Params      10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=100+100)
GorillaMux_ParseAll           250 卤 0%       122 卤 0%  -51.20%  (p=0.000 n=100+100)
GorillaMux_StaticAll        1.41k 卤 0%     0.16k 卤 0%  -88.89%  (p=0.000 n=100+100)
```

Before vs After

```
goos: linux
goarch: amd64
pkg: github.com/gorilla/mux
cpu: Intel(R) Xeon(R) E-2278G CPU @ 3.40GHz

name                     old time/op    new time/op    delta
GorillaMux_Param           1.86碌s 卤13%    1.47碌s 卤11%  -21.05%  (p=0.000 n=94+93)
GorillaMux_Param5          2.61碌s 卤 4%    2.25碌s 卤 2%  -13.64%  (p=0.000 n=89+90)
GorillaMux_Param20         6.13碌s 卤 3%    4.05碌s 卤 4%  -33.96%  (p=0.000 n=90+91)
GorillaMux_ParamWrite      1.87碌s 卤 5%    1.47碌s 卤 4%  -21.03%  (p=0.000 n=95+96)
GorillaMux_GithubStatic    3.77碌s 卤 5%    3.16碌s 卤 3%  -16.11%  (p=0.000 n=96+95)
GorillaMux_GithubParam     5.68碌s 卤 6%    5.31碌s 卤 6%   -6.57%  (p=0.000 n=93+94)
GorillaMux_GithubAll       2.86ms 卤 6%    2.72ms 卤 4%   -4.97%  (p=0.000 n=99+95)
GorillaMux_GPlusStatic     1.31碌s 卤 5%    0.66碌s 卤 6%  -49.50%  (p=0.000 n=92+95)
GorillaMux_GPlusParam      2.37碌s 卤 3%    2.04碌s 卤 4%  -13.87%  (p=0.000 n=96+90)
GorillaMux_GPlus2Params    4.43碌s 卤 3%    3.98碌s 卤 5%  -10.21%  (p=0.000 n=91+92)
GorillaMux_GPlusAll        37.1碌s 卤 6%    30.6碌s 卤 6%  -17.65%  (p=0.000 n=93+94)
GorillaMux_ParseStatic     1.55碌s 卤 5%    0.90碌s 卤 4%  -41.88%  (p=0.000 n=95+91)
GorillaMux_ParseParam      1.88碌s 卤 7%    1.47碌s 卤 6%  -21.53%  (p=0.000 n=94+95)
GorillaMux_Parse2Params    2.21碌s 卤 4%    1.80碌s 卤 5%  -18.26%  (p=0.000 n=94+90)
GorillaMux_ParseAll        71.8碌s 卤 4%    57.9碌s 卤 3%  -19.30%  (p=0.000 n=93+97)
GorillaMux_StaticAll        771碌s 卤 4%     664碌s 卤 4%  -13.87%  (p=0.000 n=95+95)

name                     old alloc/op   new alloc/op   delta
GorillaMux_Param           1.31kB 卤 0%    0.91kB 卤 0%  -30.49%  (p=0.000 n=100+100)
GorillaMux_Param5          1.38kB 卤 0%    0.98kB 卤 0%  -29.07%  (p=0.000 n=100+100)
GorillaMux_Param20         3.48kB 卤 0%    2.14kB 卤 0%  -38.48%  (p=0.000 n=100+83)
GorillaMux_ParamWrite      1.31kB 卤 0%    0.91kB 卤 0%  -30.49%  (p=0.000 n=100+100)
GorillaMux_GithubStatic    1.01kB 卤 0%    0.50kB 卤 0%  -50.79%  (p=0.000 n=100+100)
GorillaMux_GithubParam     1.33kB 卤 0%    0.93kB 卤 0%  -30.12%  (p=0.000 n=100+100)
GorillaMux_GithubAll        258kB 卤 0%     173kB 卤 0%  -33.02%  (p=0.000 n=86+100)
GorillaMux_GPlusStatic     1.01kB 卤 0%    0.50kB 卤 0%  -50.79%  (p=0.000 n=100+100)
GorillaMux_GPlusParam      1.31kB 卤 0%    0.91kB 卤 0%  -30.49%  (p=0.000 n=100+100)
GorillaMux_GPlus2Params    1.33kB 卤 0%    0.93kB 卤 0%  -30.12%  (p=0.000 n=100+100)
GorillaMux_GPlusAll        16.5kB 卤 0%    11.1kB 卤 0%  -32.82%  (p=0.000 n=100+100)
GorillaMux_ParseStatic     1.01kB 卤 0%    0.50kB 卤 0%  -50.79%  (p=0.000 n=100+100)
GorillaMux_ParseParam      1.31kB 卤 0%    0.91kB 卤 0%  -30.49%  (p=0.000 n=100+100)
GorillaMux_Parse2Params    1.33kB 卤 0%    0.93kB 卤 0%  -30.12%  (p=0.000 n=100+100)
GorillaMux_ParseAll        31.1kB 卤 0%    19.6kB 卤 0%  -37.02%  (p=0.000 n=100+100)
GorillaMux_StaticAll        158kB 卤 0%      78kB 卤 0%  -50.79%  (p=0.000 n=100+100)

name                     old allocs/op  new allocs/op  delta
GorillaMux_Param             10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
GorillaMux_Param5            10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
GorillaMux_Param20           12.0 卤 0%       8.0 卤 0%  -33.33%  (p=0.000 n=100+100)
GorillaMux_ParamWrite        10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
GorillaMux_GithubStatic      9.00 卤 0%      4.00 卤 0%  -55.56%  (p=0.000 n=100+100)
GorillaMux_GithubParam       10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
GorillaMux_GithubAll        1.99k 卤 0%     1.48k 卤 0%  -25.78%  (p=0.000 n=100+100)
GorillaMux_GPlusStatic       9.00 卤 0%      4.00 卤 0%  -55.56%  (p=0.000 n=100+100)
GorillaMux_GPlusParam        10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
GorillaMux_GPlus2Params      10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
GorillaMux_GPlusAll           128 卤 0%        96 卤 0%  -25.00%  (p=0.000 n=100+100)
GorillaMux_ParseStatic       9.00 卤 0%      4.00 卤 0%  -55.56%  (p=0.000 n=100+100)
GorillaMux_ParseParam        10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
GorillaMux_Parse2Params      10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
GorillaMux_ParseAll           250 卤 0%       168 卤 0%  -32.80%  (p=0.000 n=100+100)
GorillaMux_StaticAll        1.41k 卤 0%     0.63k 卤 0%  -55.56%  (p=0.000 n=100+100)
```

---

</details>


<details>
<summary> Older Xeon Gold, 2.3 GHz </summary>

Before vs After with omit Route flag enabled

(Actual CPU identifier is rather `Intel(R) Xeon(R) Gold 5122 CPU @
2.30GHz`)
```
goos: linux
goarch: amd64
pkg: github.com/gorilla/mux
cpu: Intel Xeon Processor (Skylake, IBRS)

name                     old time/op    new time/op    delta
GorillaMux_Param           3.02碌s 卤14%    2.24碌s 卤12%  -25.60%  (p=0.000 n=100+99)
GorillaMux_Param5          4.20碌s 卤12%    3.45碌s 卤10%  -17.84%  (p=0.000 n=95+97)
GorillaMux_Param20         9.86碌s 卤12%    6.36碌s 卤 9%  -35.54%  (p=0.000 n=96+93)
GorillaMux_ParamWrite      2.97碌s 卤 7%    2.21碌s 卤 5%  -25.40%  (p=0.000 n=96+96)
GorillaMux_GithubStatic    5.82碌s 卤 6%    3.62碌s 卤 5%  -37.87%  (p=0.000 n=99+98)
GorillaMux_GithubParam     8.81碌s 卤 7%    7.90碌s 卤 5%  -10.37%  (p=0.000 n=97+95)
GorillaMux_GithubAll       3.93ms 卤 4%    3.62ms 卤 6%   -7.72%  (p=0.000 n=97+99)
GorillaMux_GPlusStatic     2.04碌s 卤 7%    0.33碌s 卤 9%  -83.77%  (p=0.000 n=98+99)
GorillaMux_GPlusParam      3.72碌s 卤 6%    3.14碌s 卤13%  -15.44%  (p=0.000 n=99+99)
GorillaMux_GPlus2Params    6.89碌s 卤 8%    6.57碌s 卤 9%   -4.70%  (p=0.000 n=92+98)
GorillaMux_GPlusAll        56.1碌s 卤 6%    46.5碌s 卤11%  -17.14%  (p=0.000 n=95+98)
GorillaMux_ParseStatic     2.43碌s 卤 6%    0.67碌s 卤11%  -72.49%  (p=0.000 n=96+99)
GorillaMux_ParseParam      2.91碌s 卤 8%    2.29碌s 卤12%  -21.07%  (p=0.000 n=98+97)
GorillaMux_Parse2Params    3.44碌s 卤 8%    2.84碌s 卤 8%  -17.53%  (p=0.000 n=98+95)
GorillaMux_ParseAll         111碌s 卤 5%      80碌s 卤11%  -27.91%  (p=0.000 n=96+98)
GorillaMux_StaticAll       1.13ms 卤 4%    0.71ms 卤 5%  -37.32%  (p=0.000 n=97+97)

name                     old alloc/op   new alloc/op   delta
GorillaMux_Param           1.31kB 卤 0%    0.86kB 卤 0%  -34.15%  (p=0.000 n=100+100)
GorillaMux_Param5          1.38kB 卤 0%    0.93kB 卤 0%  -32.56%  (p=0.000 n=100+100)
GorillaMux_Param20         3.48kB 卤 0%    2.10kB 卤 0%  -39.86%  (p=0.000 n=100+79)
GorillaMux_ParamWrite      1.31kB 卤 0%    0.86kB 卤 0%  -34.15%  (p=0.000 n=100+100)
GorillaMux_GithubStatic    1.01kB 卤 0%    0.05kB 卤 0%  -95.24%  (p=0.000 n=100+100)
GorillaMux_GithubParam     1.33kB 卤 0%    0.88kB 卤 0%  -33.73%  (p=0.000 n=100+100)
GorillaMux_GithubAll        258kB 卤 0%     149kB 卤 0%  -42.37%  (p=0.000 n=80+96)
GorillaMux_GPlusStatic     1.01kB 卤 0%    0.05kB 卤 0%  -95.24%  (p=0.000 n=100+100)
GorillaMux_GPlusParam      1.31kB 卤 0%    0.86kB 卤 0%  -34.15%  (p=0.000 n=100+100)
GorillaMux_GPlus2Params    1.33kB 卤 0%    0.88kB 卤 0%  -33.73%  (p=0.000 n=100+100)
GorillaMux_GPlusAll        16.5kB 卤 0%     9.7kB 卤 0%  -41.43%  (p=0.000 n=100+100)
GorillaMux_ParseStatic     1.01kB 卤 0%    0.05kB 卤 0%  -95.24%  (p=0.000 n=100+100)
GorillaMux_ParseParam      1.31kB 卤 0%    0.86kB 卤 0%  -34.15%  (p=0.000 n=100+100)
GorillaMux_Parse2Params    1.33kB 卤 0%    0.88kB 卤 0%  -33.73%  (p=0.000 n=100+100)
GorillaMux_ParseAll        31.1kB 卤 0%    14.4kB 卤 0%  -53.88%  (p=0.000 n=100+100)
GorillaMux_StaticAll        158kB 卤 0%       8kB 卤 0%  -95.24%  (p=0.000 n=100+100)

name                     old allocs/op  new allocs/op  delta
GorillaMux_Param             10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=100+100)
GorillaMux_Param5            10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=100+100)
GorillaMux_Param20           12.0 卤 0%       7.0 卤 0%  -41.67%  (p=0.000 n=100+100)
GorillaMux_ParamWrite        10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=100+100)
GorillaMux_GithubStatic      9.00 卤 0%      1.00 卤 0%  -88.89%  (p=0.000 n=100+100)
GorillaMux_GithubParam       10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=100+100)
GorillaMux_GithubAll        1.99k 卤 0%     1.21k 卤 0%  -39.57%  (p=0.000 n=100+100)
GorillaMux_GPlusStatic       9.00 卤 0%      1.00 卤 0%  -88.89%  (p=0.000 n=100+100)
GorillaMux_GPlusParam        10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=100+100)
GorillaMux_GPlus2Params      10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=100+100)
GorillaMux_GPlusAll           128 卤 0%        79 卤 0%  -38.28%  (p=0.000 n=100+100)
GorillaMux_ParseStatic       9.00 卤 0%      1.00 卤 0%  -88.89%  (p=0.000 n=100+100)
GorillaMux_ParseParam        10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=100+100)
GorillaMux_Parse2Params      10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=100+100)
GorillaMux_ParseAll           250 卤 0%       122 卤 0%  -51.20%  (p=0.000 n=100+100)
GorillaMux_StaticAll        1.41k 卤 0%     0.16k 卤 0%  -88.89%  (p=0.000 n=100+100)
```

Before vs After

(Actual CPU identifier is rather `Intel(R) Xeon(R) Gold 5122 CPU @
2.30GHz`)
```
goos: linux
goarch: amd64
pkg: github.com/gorilla/mux
cpu: Intel Xeon Processor (Skylake, IBRS) 

name                     old time/op    new time/op    delta
GorillaMux_Param           3.02碌s 卤14%    2.27碌s 卤 8%  -24.70%  (p=0.000 n=100+98)
GorillaMux_Param5          4.20碌s 卤12%    3.48碌s 卤 5%  -17.29%  (p=0.000 n=95+98)
GorillaMux_Param20         9.86碌s 卤12%    6.41碌s 卤 6%  -35.05%  (p=0.000 n=96+92)
GorillaMux_ParamWrite      2.97碌s 卤 7%    2.31碌s 卤 6%  -22.12%  (p=0.000 n=96+98)
GorillaMux_GithubStatic    5.82碌s 卤 6%    4.69碌s 卤 5%  -19.52%  (p=0.000 n=99+96)
GorillaMux_GithubParam     8.81碌s 卤 7%    7.98碌s 卤 4%   -9.48%  (p=0.000 n=97+96)
GorillaMux_GithubAll       3.93ms 卤 4%    3.64ms 卤 5%   -7.18%  (p=0.000 n=97+94)
GorillaMux_GPlusStatic     2.04碌s 卤 7%    1.05碌s 卤12%  -48.53%  (p=0.000 n=98+94)
GorillaMux_GPlusParam      3.72碌s 卤 6%    3.09碌s 卤 5%  -16.76%  (p=0.000 n=99+96)
GorillaMux_GPlus2Params    6.89碌s 卤 8%    6.18碌s 卤 5%  -10.28%  (p=0.000 n=92+95)
GorillaMux_GPlusAll        56.1碌s 卤 6%    46.0碌s 卤 5%  -17.98%  (p=0.000 n=95+93)
GorillaMux_ParseStatic     2.43碌s 卤 6%    1.44碌s 卤 5%  -40.52%  (p=0.000 n=96+95)
GorillaMux_ParseParam      2.91碌s 卤 8%    2.30碌s 卤 5%  -20.93%  (p=0.000 n=98+98)
GorillaMux_Parse2Params    3.44碌s 卤 8%    2.82碌s 卤 7%  -18.04%  (p=0.000 n=98+94)
GorillaMux_ParseAll         111碌s 卤 5%      91碌s 卤13%  -18.12%  (p=0.000 n=96+98)
GorillaMux_StaticAll       1.13ms 卤 4%    0.95ms 卤 9%  -16.38%  (p=0.000 n=97+96)

name                     old alloc/op   new alloc/op   delta
GorillaMux_Param           1.31kB 卤 0%    0.91kB 卤 0%  -30.49%  (p=0.000 n=100+100)
GorillaMux_Param5          1.38kB 卤 0%    0.98kB 卤 0%  -29.07%  (p=0.000 n=100+100)
GorillaMux_Param20         3.48kB 卤 0%    2.14kB 卤 0%  -38.49%  (p=0.000 n=100+100)
GorillaMux_ParamWrite      1.31kB 卤 0%    0.91kB 卤 0%  -30.49%  (p=0.000 n=100+100)
GorillaMux_GithubStatic    1.01kB 卤 0%    0.50kB 卤 0%  -50.79%  (p=0.000 n=100+100)
GorillaMux_GithubParam     1.33kB 卤 0%    0.93kB 卤 0%  -30.12%  (p=0.000 n=100+100)
GorillaMux_GithubAll        258kB 卤 0%     173kB 卤 0%  -33.02%  (p=0.000 n=80+100)
GorillaMux_GPlusStatic     1.01kB 卤 0%    0.50kB 卤 0%  -50.79%  (p=0.000 n=100+100)
GorillaMux_GPlusParam      1.31kB 卤 0%    0.91kB 卤 0%  -30.49%  (p=0.000 n=100+100)
GorillaMux_GPlus2Params    1.33kB 卤 0%    0.93kB 卤 0%  -30.12%  (p=0.000 n=100+100)
GorillaMux_GPlusAll        16.5kB 卤 0%    11.1kB 卤 0%  -32.82%  (p=0.000 n=100+100)
GorillaMux_ParseStatic     1.01kB 卤 0%    0.50kB 卤 0%  -50.79%  (p=0.000 n=100+100)
GorillaMux_ParseParam      1.31kB 卤 0%    0.91kB 卤 0%  -30.49%  (p=0.000 n=100+100)
GorillaMux_Parse2Params    1.33kB 卤 0%    0.93kB 卤 0%  -30.12%  (p=0.000 n=100+100)
GorillaMux_ParseAll        31.1kB 卤 0%    19.6kB 卤 0%  -37.02%  (p=0.000 n=100+100)
GorillaMux_StaticAll        158kB 卤 0%      78kB 卤 0%  -50.79%  (p=0.000 n=100+95)

name                     old allocs/op  new allocs/op  delta
GorillaMux_Param             10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
GorillaMux_Param5            10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
GorillaMux_Param20           12.0 卤 0%       8.0 卤 0%  -33.33%  (p=0.000 n=100+100)
GorillaMux_ParamWrite        10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
GorillaMux_GithubStatic      9.00 卤 0%      4.00 卤 0%  -55.56%  (p=0.000 n=100+100)
GorillaMux_GithubParam       10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
GorillaMux_GithubAll        1.99k 卤 0%     1.48k 卤 0%  -25.78%  (p=0.000 n=100+100)
GorillaMux_GPlusStatic       9.00 卤 0%      4.00 卤 0%  -55.56%  (p=0.000 n=100+100)
GorillaMux_GPlusParam        10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
GorillaMux_GPlus2Params      10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
GorillaMux_GPlusAll           128 卤 0%        96 卤 0%  -25.00%  (p=0.000 n=100+100)
GorillaMux_ParseStatic       9.00 卤 0%      4.00 卤 0%  -55.56%  (p=0.000 n=100+100)
GorillaMux_ParseParam        10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
GorillaMux_Parse2Params      10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
GorillaMux_ParseAll           250 卤 0%       168 卤 0%  -32.80%  (p=0.000 n=100+100)
GorillaMux_StaticAll        1.41k 卤 0%     0.63k 卤 0%  -55.56%  (p=0.000 n=100+100)
```

---

</details>



<details>
<summary> Older Xeon E, 2.4 GHz </summary>

Before vs After with omit Route flag enabled

```
goos: linux
goarch: amd64
pkg: github.com/gorilla/mux
cpu: Intel(R) Xeon(R) CPU E5-2680 v4 @ 2.40GHz

name                     old time/op    new time/op    delta
GorillaMux_Param           3.31碌s 卤11%    2.44碌s 卤11%  -26.34%  (p=0.000 n=95+92)
GorillaMux_Param5          4.68碌s 卤 9%    3.96碌s 卤14%  -15.22%  (p=0.000 n=97+100)
GorillaMux_Param20         11.1碌s 卤10%     7.2碌s 卤 9%  -35.03%  (p=0.000 n=100+97)
GorillaMux_ParamWrite      3.37碌s 卤10%    2.56碌s 卤 8%  -24.21%  (p=0.000 n=95+94)
GorillaMux_GithubStatic    6.90碌s 卤 7%    3.85碌s 卤 8%  -44.16%  (p=0.000 n=96+91)
GorillaMux_GithubParam     9.85碌s 卤 6%    8.89碌s 卤11%   -9.74%  (p=0.000 n=98+96)
GorillaMux_GithubAll       5.15ms 卤10%    4.77ms 卤 7%   -7.36%  (p=0.000 n=96+96)
GorillaMux_GPlusStatic     2.38碌s 卤 8%    0.36碌s 卤 7%  -84.98%  (p=0.000 n=95+94)
GorillaMux_GPlusParam      4.30碌s 卤11%    3.33碌s 卤10%  -22.60%  (p=0.000 n=97+95)
GorillaMux_GPlus2Params    7.80碌s 卤 8%    6.82碌s 卤10%  -12.55%  (p=0.000 n=98+94)
GorillaMux_GPlusAll        65.8碌s 卤10%    50.5碌s 卤10%  -23.24%  (p=0.000 n=97+98)
GorillaMux_ParseStatic     2.98碌s 卤10%    0.70碌s 卤 9%  -76.68%  (p=0.000 n=99+94)
GorillaMux_ParseParam      3.31碌s 卤 9%    2.55碌s 卤 9%  -23.11%  (p=0.000 n=96+95)
GorillaMux_Parse2Params    3.92碌s 卤 8%    3.18碌s 卤12%  -18.86%  (p=0.000 n=97+96)
GorillaMux_ParseAll         125碌s 卤 9%      90碌s 卤12%  -28.23%  (p=0.000 n=99+96)
GorillaMux_StaticAll       1.32ms 卤 6%    0.79ms 卤 6%  -40.41%  (p=0.000 n=99+95)

name                     old alloc/op   new alloc/op   delta
GorillaMux_Param           1.31kB 卤 0%    0.86kB 卤 0%  -34.15%  (p=0.000 n=100+100)
GorillaMux_Param5          1.38kB 卤 0%    0.93kB 卤 0%  -32.56%  (p=0.000 n=100+100)
GorillaMux_Param20         3.48kB 卤 0%    2.10kB 卤 0%  -39.86%  (p=0.000 n=100+79)
GorillaMux_ParamWrite      1.31kB 卤 0%    0.86kB 卤 0%  -34.15%  (p=0.000 n=100+100)
GorillaMux_GithubStatic    1.01kB 卤 0%    0.05kB 卤 0%  -95.24%  (p=0.000 n=100+100)
GorillaMux_GithubParam     1.33kB 卤 0%    0.88kB 卤 0%  -33.73%  (p=0.000 n=100+100)
GorillaMux_GithubAll        258kB 卤 0%     149kB 卤 0%  -42.37%  (p=0.000 n=79+86)
GorillaMux_GPlusStatic     1.01kB 卤 0%    0.05kB 卤 0%  -95.24%  (p=0.000 n=100+100)
GorillaMux_GPlusParam      1.31kB 卤 0%    0.86kB 卤 0%  -34.15%  (p=0.000 n=100+100)
GorillaMux_GPlus2Params    1.33kB 卤 0%    0.88kB 卤 0%  -33.73%  (p=0.000 n=100+100)
GorillaMux_GPlusAll        16.5kB 卤 0%     9.7kB 卤 0%  -41.43%  (p=0.000 n=100+100)
GorillaMux_ParseStatic     1.01kB 卤 0%    0.05kB 卤 0%  -95.24%  (p=0.000 n=100+100)
GorillaMux_ParseParam      1.31kB 卤 0%    0.86kB 卤 0%  -34.15%  (p=0.000 n=100+100)
GorillaMux_Parse2Params    1.33kB 卤 0%    0.88kB 卤 0%  -33.73%  (p=0.000 n=100+100)
GorillaMux_ParseAll        31.1kB 卤 0%    14.4kB 卤 0%  -53.88%  (p=0.000 n=100+100)
GorillaMux_StaticAll        158kB 卤 0%       8kB 卤 0%  -95.24%  (p=0.000 n=100+100)

name                     old allocs/op  new allocs/op  delta
GorillaMux_Param             10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=100+100)
GorillaMux_Param5            10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=100+100)
GorillaMux_Param20           12.0 卤 0%       7.0 卤 0%  -41.67%  (p=0.000 n=100+100)
GorillaMux_ParamWrite        10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=100+100)
GorillaMux_GithubStatic      9.00 卤 0%      1.00 卤 0%  -88.89%  (p=0.000 n=100+100)
GorillaMux_GithubParam       10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=100+100)
GorillaMux_GithubAll        1.99k 卤 0%     1.21k 卤 0%  -39.57%  (p=0.000 n=100+100)
GorillaMux_GPlusStatic       9.00 卤 0%      1.00 卤 0%  -88.89%  (p=0.000 n=100+100)
GorillaMux_GPlusParam        10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=100+100)
GorillaMux_GPlus2Params      10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=100+100)
GorillaMux_GPlusAll           128 卤 0%        79 卤 0%  -38.28%  (p=0.000 n=100+100)
GorillaMux_ParseStatic       9.00 卤 0%      1.00 卤 0%  -88.89%  (p=0.000 n=100+100)
GorillaMux_ParseParam        10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=100+100)
GorillaMux_Parse2Params      10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=100+100)
GorillaMux_ParseAll           250 卤 0%       122 卤 0%  -51.20%  (p=0.000 n=100+100)
GorillaMux_StaticAll        1.41k 卤 0%     0.16k 卤 0%  -88.89%  (p=0.000 n=100+100)
```

Before vs After

```
goos: linux
goarch: amd64
pkg: github.com/gorilla/mux
cpu: Intel(R) Xeon(R) CPU E5-2680 v4 @ 2.40GHz

name                     old time/op    new time/op    delta
GorillaMux_Param           3.31碌s 卤11%    2.59碌s 卤12%  -21.76%  (p=0.000 n=95+96)
GorillaMux_Param5          4.68碌s 卤 9%    3.80碌s 卤 7%  -18.79%  (p=0.000 n=97+92)
GorillaMux_Param20         11.1碌s 卤10%     7.2碌s 卤 9%  -35.19%  (p=0.000 n=100+99)
GorillaMux_ParamWrite      3.37碌s 卤10%    2.68碌s 卤 7%  -20.69%  (p=0.000 n=95+95)
GorillaMux_GithubStatic    6.90碌s 卤 7%    5.06碌s 卤 7%  -26.57%  (p=0.000 n=96+91)
GorillaMux_GithubParam     9.85碌s 卤 6%    8.83碌s 卤 9%  -10.42%  (p=0.000 n=98+98)
GorillaMux_GithubAll       5.15ms 卤10%    4.71ms 卤 9%   -8.50%  (p=0.000 n=96+97)
GorillaMux_GPlusStatic     2.38碌s 卤 8%    1.19碌s 卤10%  -50.24%  (p=0.000 n=95+100)
GorillaMux_GPlusParam      4.30碌s 卤11%    3.40碌s 卤 5%  -21.08%  (p=0.000 n=97+96)
GorillaMux_GPlus2Params    7.80碌s 卤 8%    6.96碌s 卤 8%  -10.71%  (p=0.000 n=98+98)
GorillaMux_GPlusAll        65.8碌s 卤10%    52.2碌s 卤10%  -20.65%  (p=0.000 n=97+96)
GorillaMux_ParseStatic     2.98碌s 卤10%    1.61碌s 卤10%  -46.04%  (p=0.000 n=99+100)
GorillaMux_ParseParam      3.31碌s 卤 9%    2.63碌s 卤 7%  -20.46%  (p=0.000 n=96+91)
GorillaMux_Parse2Params    3.92碌s 卤 8%    3.23碌s 卤 6%  -17.58%  (p=0.000 n=97+93)
GorillaMux_ParseAll         125碌s 卤 9%     102碌s 卤 9%  -18.79%  (p=0.000 n=99+96)
GorillaMux_StaticAll       1.32ms 卤 6%    1.07ms 卤 7%  -18.78%  (p=0.000 n=99+95)

name                     old alloc/op   new alloc/op   delta
GorillaMux_Param           1.31kB 卤 0%    0.91kB 卤 0%  -30.49%  (p=0.000 n=100+100)
GorillaMux_Param5          1.38kB 卤 0%    0.98kB 卤 0%  -29.07%  (p=0.000 n=100+100)
GorillaMux_Param20         3.48kB 卤 0%    2.14kB 卤 0%  -38.49%  (p=0.000 n=100+100)
GorillaMux_ParamWrite      1.31kB 卤 0%    0.91kB 卤 0%  -30.49%  (p=0.000 n=100+100)
GorillaMux_GithubStatic    1.01kB 卤 0%    0.50kB 卤 0%  -50.79%  (p=0.000 n=100+100)
GorillaMux_GithubParam     1.33kB 卤 0%    0.93kB 卤 0%  -30.12%  (p=0.000 n=100+100)
GorillaMux_GithubAll        258kB 卤 0%     173kB 卤 0%  -33.02%  (p=0.000 n=79+96)
GorillaMux_GPlusStatic     1.01kB 卤 0%    0.50kB 卤 0%  -50.79%  (p=0.000 n=100+100)
GorillaMux_GPlusParam      1.31kB 卤 0%    0.91kB 卤 0%  -30.49%  (p=0.000 n=100+100)
GorillaMux_GPlus2Params    1.33kB 卤 0%    0.93kB 卤 0%  -30.12%  (p=0.000 n=100+100)
GorillaMux_GPlusAll        16.5kB 卤 0%    11.1kB 卤 0%  -32.82%  (p=0.000 n=100+100)
GorillaMux_ParseStatic     1.01kB 卤 0%    0.50kB 卤 0%  -50.79%  (p=0.000 n=100+100)
GorillaMux_ParseParam      1.31kB 卤 0%    0.91kB 卤 0%  -30.49%  (p=0.000 n=100+100)
GorillaMux_Parse2Params    1.33kB 卤 0%    0.93kB 卤 0%  -30.12%  (p=0.000 n=100+100)
GorillaMux_ParseAll        31.1kB 卤 0%    19.6kB 卤 0%  -37.02%  (p=0.000 n=100+100)
GorillaMux_StaticAll        158kB 卤 0%      78kB 卤 0%  -50.79%  (p=0.000 n=100+100)

name                     old allocs/op  new allocs/op  delta
GorillaMux_Param             10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
GorillaMux_Param5            10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
GorillaMux_Param20           12.0 卤 0%       8.0 卤 0%  -33.33%  (p=0.000 n=100+100)
GorillaMux_ParamWrite        10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
GorillaMux_GithubStatic      9.00 卤 0%      4.00 卤 0%  -55.56%  (p=0.000 n=100+100)
GorillaMux_GithubParam       10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
GorillaMux_GithubAll        1.99k 卤 0%     1.48k 卤 0%  -25.78%  (p=0.000 n=100+100)
GorillaMux_GPlusStatic       9.00 卤 0%      4.00 卤 0%  -55.56%  (p=0.000 n=100+100)
GorillaMux_GPlusParam        10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
GorillaMux_GPlus2Params      10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
GorillaMux_GPlusAll           128 卤 0%        96 卤 0%  -25.00%  (p=0.000 n=100+100)
GorillaMux_ParseStatic       9.00 卤 0%      4.00 卤 0%  -55.56%  (p=0.000 n=100+100)
GorillaMux_ParseParam        10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
GorillaMux_Parse2Params      10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=100+100)
GorillaMux_ParseAll           250 卤 0%       168 卤 0%  -32.80%  (p=0.000 n=100+100)
GorillaMux_StaticAll        1.41k 卤 0%     0.63k 卤 0%  -55.56%  (p=0.000 n=100+100)
```

---

</details>


<details>
<summary> Older i7, frequency scaling around 3.4 GHz, n=10 </summary>

Sorry, only 10 iterations each. I do not want to hear the fan for too
long :)

Before vs After with omit Route flag enabled

```
goos: linux
goarch: amd64
pkg: github.com/julienschmidt/go-http-routing-benchmark
cpu: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz

name                     old time/op    new time/op    delta
GorillaMux_Param           1.80碌s 卤 2%    1.41碌s 卤 3%  -21.64%  (p=0.000 n=10+10)
GorillaMux_Param5          2.68碌s 卤 0%    2.34碌s 卤 1%  -12.43%  (p=0.000 n=10+10)
GorillaMux_Param20         5.92碌s 卤 0%    4.02碌s 卤 0%  -32.10%  (p=0.000 n=10+9)
GorillaMux_ParamWrite      1.89碌s 卤 1%    1.47碌s 卤 0%  -22.22%  (p=0.000 n=9+8)
GorillaMux_GithubStatic    4.05碌s 卤 1%    2.80碌s 卤 0%  -31.04%  (p=0.000 n=9+10)
GorillaMux_GithubParam     6.30碌s 卤 1%    5.90碌s 卤 1%   -6.27%  (p=0.000 n=10+10)
GorillaMux_GithubAll       3.14ms 卤 1%    2.87ms 卤 2%   -8.42%  (p=0.000 n=10+10)
GorillaMux_GPlusStatic     1.29碌s 卤 1%    0.23碌s 卤 1%  -82.37%  (p=0.000 n=10+10)
GorillaMux_GPlusParam      2.52碌s 卤 0%    2.07碌s 卤 1%  -17.69%  (p=0.000 n=10+10)
GorillaMux_GPlus2Params    4.92碌s 卤 0%    4.49碌s 卤 1%   -8.71%  (p=0.000 n=10+10)
GorillaMux_GPlusAll        39.0碌s 卤 1%    31.5碌s 卤 1%  -19.28%  (p=0.000 n=10+10)
GorillaMux_ParseStatic     1.58碌s 卤 1%    0.47碌s 卤 1%  -70.01%  (p=0.000 n=10+10)
GorillaMux_ParseParam      1.89碌s 卤 0%    1.46碌s 卤 1%  -22.70%  (p=0.000 n=10+10)
GorillaMux_Parse2Params    2.31碌s 卤 2%    1.87碌s 卤 0%  -18.96%  (p=0.000 n=10+8)
GorillaMux_ParseAll        74.3碌s 卤 1%    55.4碌s 卤 0%  -25.48%  (p=0.000 n=10+10)
GorillaMux_StaticAll        797碌s 卤 0%     561碌s 卤 1%  -29.66%  (p=0.000 n=10+10)

name                     old alloc/op   new alloc/op   delta
GorillaMux_Param           1.31kB 卤 0%    0.86kB 卤 0%  -34.15%  (p=0.000 n=10+10)
GorillaMux_Param5          1.38kB 卤 0%    0.93kB 卤 0%  -32.56%  (p=0.000 n=10+10)
GorillaMux_Param20         3.48kB 卤 0%    2.09kB 卤 0%  -39.87%  (p=0.000 n=10+10)
GorillaMux_ParamWrite      1.31kB 卤 0%    0.86kB 卤 0%  -34.15%  (p=0.000 n=10+10)
GorillaMux_GithubStatic    1.01kB 卤 0%    0.05kB 卤 0%  -95.24%  (p=0.000 n=10+10)
GorillaMux_GithubParam     1.33kB 卤 0%    0.88kB 卤 0%  -33.73%  (p=0.000 n=10+10)
GorillaMux_GithubAll        258kB 卤 0%     149kB 卤 0%  -42.37%  (p=0.000 n=10+9)
GorillaMux_GPlusStatic     1.01kB 卤 0%    0.05kB 卤 0%  -95.24%  (p=0.000 n=10+10)
GorillaMux_GPlusParam      1.31kB 卤 0%    0.86kB 卤 0%  -34.15%  (p=0.000 n=10+10)
GorillaMux_GPlus2Params    1.33kB 卤 0%    0.88kB 卤 0%  -33.73%  (p=0.000 n=10+10)
GorillaMux_GPlusAll        16.5kB 卤 0%     9.7kB 卤 0%  -41.43%  (p=0.000 n=10+10)
GorillaMux_ParseStatic     1.01kB 卤 0%    0.05kB 卤 0%  -95.24%  (p=0.000 n=10+10)
GorillaMux_ParseParam      1.31kB 卤 0%    0.86kB 卤 0%  -34.15%  (p=0.000 n=10+10)
GorillaMux_Parse2Params    1.33kB 卤 0%    0.88kB 卤 0%  -33.73%  (p=0.000 n=10+10)
GorillaMux_ParseAll        31.1kB 卤 0%    14.4kB 卤 0%  -53.88%  (p=0.000 n=10+10)
GorillaMux_StaticAll        158kB 卤 0%       8kB 卤 0%  -95.24%  (p=0.000 n=10+10)

name                     old allocs/op  new allocs/op  delta
GorillaMux_Param             10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=10+10)
GorillaMux_Param5            10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=10+10)
GorillaMux_Param20           12.0 卤 0%       7.0 卤 0%  -41.67%  (p=0.000 n=10+10)
GorillaMux_ParamWrite        10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=10+10)
GorillaMux_GithubStatic      9.00 卤 0%      1.00 卤 0%  -88.89%  (p=0.000 n=10+10)
GorillaMux_GithubParam       10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=10+10)
GorillaMux_GithubAll        1.99k 卤 0%     1.21k 卤 0%  -39.57%  (p=0.000 n=10+10)
GorillaMux_GPlusStatic       9.00 卤 0%      1.00 卤 0%  -88.89%  (p=0.000 n=10+10)
GorillaMux_GPlusParam        10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=10+10)
GorillaMux_GPlus2Params      10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=10+10)
GorillaMux_GPlusAll           128 卤 0%        79 卤 0%  -38.28%  (p=0.000 n=10+10)
GorillaMux_ParseStatic       9.00 卤 0%      1.00 卤 0%  -88.89%  (p=0.000 n=10+10)
GorillaMux_ParseParam        10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=10+10)
GorillaMux_Parse2Params      10.0 卤 0%       7.0 卤 0%  -30.00%  (p=0.000 n=10+10)
GorillaMux_ParseAll           250 卤 0%       122 卤 0%  -51.20%  (p=0.000 n=10+10)
GorillaMux_StaticAll        1.41k 卤 0%     0.16k 卤 0%  -88.89%  (p=0.000 n=10+10)
```

Before vs After
```
goos: linux
goarch: amd64
pkg: github.com/julienschmidt/go-http-routing-benchmark
cpu: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz

name                     old time/op    new time/op    delta
GorillaMux_Param           1.80碌s 卤 2%    1.38碌s 卤 2%  -23.29%  (p=0.000 n=10+10)
GorillaMux_Param5          2.68碌s 卤 0%    2.29碌s 卤 1%  -14.51%  (p=0.000 n=10+10)
GorillaMux_Param20         5.92碌s 卤 0%    3.95碌s 卤 1%  -33.32%  (p=0.000 n=10+10)
GorillaMux_ParamWrite      1.89碌s 卤 1%    1.46碌s 卤 2%  -22.59%  (p=0.000 n=9+10)
GorillaMux_GithubStatic    4.05碌s 卤 1%    3.41碌s 卤 1%  -15.89%  (p=0.000 n=9+9)
GorillaMux_GithubParam     6.30碌s 卤 1%    5.80碌s 卤 1%   -7.91%  (p=0.000 n=10+10)
GorillaMux_GithubAll       3.14ms 卤 1%    2.89ms 卤 1%   -7.79%  (p=0.000 n=10+10)
GorillaMux_GPlusStatic     1.29碌s 卤 1%    0.65碌s 卤 1%  -49.87%  (p=0.000 n=10+10)
GorillaMux_GPlusParam      2.52碌s 卤 0%    2.14碌s 卤 1%  -15.03%  (p=0.000 n=10+10)
GorillaMux_GPlus2Params    4.92碌s 卤 0%    4.46碌s 卤 1%   -9.40%  (p=0.000 n=10+10)
GorillaMux_GPlusAll        39.0碌s 卤 1%    33.0碌s 卤 1%  -15.53%  (p=0.000 n=10+10)
GorillaMux_ParseStatic     1.58碌s 卤 1%    0.93碌s 卤 1%  -41.36%  (p=0.000 n=10+10)
GorillaMux_ParseParam      1.89碌s 卤 0%    1.51碌s 卤 2%  -20.23%  (p=0.000 n=10+9)
GorillaMux_Parse2Params    2.31碌s 卤 2%    1.92碌s 卤 1%  -16.95%  (p=0.000 n=10+10)
GorillaMux_ParseAll        74.3碌s 卤 1%    60.9碌s 卤 1%  -17.99%  (p=0.000 n=10+10)
GorillaMux_StaticAll        797碌s 卤 0%     699碌s 卤 0%  -12.25%  (p=0.000 n=10+10)

name                     old alloc/op   new alloc/op   delta
GorillaMux_Param           1.31kB 卤 0%    0.91kB 卤 0%  -30.49%  (p=0.000 n=10+10)
GorillaMux_Param5          1.38kB 卤 0%    0.98kB 卤 0%  -29.07%  (p=0.000 n=10+10)
GorillaMux_Param20         3.48kB 卤 0%    2.14kB 卤 0%  -38.48%  (p=0.000 n=10+10)
GorillaMux_ParamWrite      1.31kB 卤 0%    0.91kB 卤 0%  -30.49%  (p=0.000 n=10+10)
GorillaMux_GithubStatic    1.01kB 卤 0%    0.50kB 卤 0%  -50.79%  (p=0.000 n=10+10)
GorillaMux_GithubParam     1.33kB 卤 0%    0.93kB 卤 0%  -30.12%  (p=0.000 n=10+10)
GorillaMux_GithubAll        258kB 卤 0%     173kB 卤 0%  -33.02%  (p=0.000 n=10+10)
GorillaMux_GPlusStatic     1.01kB 卤 0%    0.50kB 卤 0%  -50.79%  (p=0.000 n=10+10)
GorillaMux_GPlusParam      1.31kB 卤 0%    0.91kB 卤 0%  -30.49%  (p=0.000 n=10+10)
GorillaMux_GPlus2Params    1.33kB 卤 0%    0.93kB 卤 0%  -30.12%  (p=0.000 n=10+10)
GorillaMux_GPlusAll        16.5kB 卤 0%    11.1kB 卤 0%  -32.82%  (p=0.000 n=10+10)
GorillaMux_ParseStatic     1.01kB 卤 0%    0.50kB 卤 0%  -50.79%  (p=0.000 n=10+10)
GorillaMux_ParseParam      1.31kB 卤 0%    0.91kB 卤 0%  -30.49%  (p=0.000 n=10+10)
GorillaMux_Parse2Params    1.33kB 卤 0%    0.93kB 卤 0%  -30.12%  (p=0.000 n=10+10)
GorillaMux_ParseAll        31.1kB 卤 0%    19.6kB 卤 0%  -37.02%  (p=0.000 n=10+10)
GorillaMux_StaticAll        158kB 卤 0%      78kB 卤 0%  -50.79%  (p=0.000 n=10+10)

name                     old allocs/op  new allocs/op  delta
GorillaMux_Param             10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=10+10)
GorillaMux_Param5            10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=10+10)
GorillaMux_Param20           12.0 卤 0%       8.0 卤 0%  -33.33%  (p=0.000 n=10+10)
GorillaMux_ParamWrite        10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=10+10)
GorillaMux_GithubStatic      9.00 卤 0%      4.00 卤 0%  -55.56%  (p=0.000 n=10+10)
GorillaMux_GithubParam       10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=10+10)
GorillaMux_GithubAll        1.99k 卤 0%     1.48k 卤 0%  -25.78%  (p=0.000 n=10+10)
GorillaMux_GPlusStatic       9.00 卤 0%      4.00 卤 0%  -55.56%  (p=0.000 n=10+10)
GorillaMux_GPlusParam        10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=10+10)
GorillaMux_GPlus2Params      10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=10+10)
GorillaMux_GPlusAll           128 卤 0%        96 卤 0%  -25.00%  (p=0.000 n=10+10)
GorillaMux_ParseStatic       9.00 卤 0%      4.00 卤 0%  -55.56%  (p=0.000 n=10+10)
GorillaMux_ParseParam        10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=10+10)
GorillaMux_Parse2Params      10.0 卤 0%       8.0 卤 0%  -20.00%  (p=0.000 n=10+10)
GorillaMux_ParseAll           250 卤 0%       168 卤 0%  -32.80%  (p=0.000 n=10+10)
GorillaMux_StaticAll        1.41k 卤 0%     0.63k 卤 0%  -55.56%  (p=0.000 n=10+10)
```

---

</details>


---

</details>

---

</details>

If you read this far, please consider running benchmarks for your own
use cases
 of `mux` and report back any changes. Thanks!

<details>
<summary> go.mod override </summary>

You can use the following override in your `go.mod` file:
```
replace github.com/gorilla/mux v1.8.1 => github.com/das7pad/mux v1.8.1-0.20220803193445-4e593050ec93
```
Optionally, you can enable the flag for not storing the `Route` in the
request context:
```
m := mux.NewRouter()
m.OmitRouteFromContext(true)
```
</details>

---------

Signed-off-by: Jakob Ackermann <das7pad@outlook.com>
Co-authored-by: Alex Vulaj <avulaj@redhat.com>
  • Loading branch information
das7pad and AlexVulaj committed Dec 7, 2023
1 parent f79c3af commit e44017d
Show file tree
Hide file tree
Showing 5 changed files with 303 additions and 108 deletions.
32 changes: 32 additions & 0 deletions bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,38 @@ func BenchmarkMux(b *testing.B) {
}
}

func BenchmarkMuxSimple(b *testing.B) {
router := new(Router)
handler := func(w http.ResponseWriter, r *http.Request) {}
router.HandleFunc("/status", handler)

testCases := []struct {
name string
omitRouteFromContext bool
}{
{
name: "default",
omitRouteFromContext: false,
},
{
name: "omit route from ctx",
omitRouteFromContext: true,
},
}
for _, tc := range testCases {
b.Run(tc.name, func(b *testing.B) {
router.OmitRouteFromContext(tc.omitRouteFromContext)

request, _ := http.NewRequest("GET", "/status", nil)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
router.ServeHTTP(nil, request)
}
})
}
}

func BenchmarkMuxAlternativeInRegexp(b *testing.B) {
router := new(Router)
handler := func(w http.ResponseWriter, r *http.Request) {}
Expand Down
57 changes: 45 additions & 12 deletions mux.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"errors"
"fmt"
"net/http"
"net/url"
"path"
"regexp"
)
Expand Down Expand Up @@ -84,6 +85,9 @@ type routeConf struct {
// will not redirect
skipClean bool

// If true, the http.Request context will not contain the Route.
omitRouteFromContext bool

// Manager for the variables from host and path.
regexp routeRegexpGroup

Expand Down Expand Up @@ -180,15 +184,7 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
}
// Clean path to canonical form and redirect.
if p := cleanPath(path); p != path {

// Added 3 lines (Philip Schlump) - It was dropping the query string and #whatever from query.
// This matches with fix in go 1.2 r.c. 4 for same problem. Go Issue:
// http://code.google.com/p/go/issues/detail?id=5252
url := *req.URL
url.Path = p
p = url.String()

w.Header().Set("Location", p)
w.Header().Set("Location", replaceURLPath(req.URL, p))
w.WriteHeader(http.StatusMovedPermanently)
return
}
Expand All @@ -197,8 +193,15 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
var handler http.Handler
if r.Match(req, &match) {
handler = match.Handler
req = requestWithVars(req, match.Vars)
req = requestWithRoute(req, match.Route)
if handler != nil {
// Populate context for custom handlers
if r.omitRouteFromContext {
// Only populate the match vars (if any) into the context.
req = requestWithVars(req, match.Vars)
} else {
req = requestWithRouteAndVars(req, match.Route, match.Vars)
}
}
}

if handler == nil && match.MatchErr == ErrMethodMismatch {
Expand Down Expand Up @@ -260,6 +263,16 @@ func (r *Router) SkipClean(value bool) *Router {
return r
}

// OmitRouteFromContext defines the behavior of omitting the Route from the
//
// http.Request context.
//
// CurrentRoute will yield nil with this option.
func (r *Router) OmitRouteFromContext(value bool) *Router {
r.omitRouteFromContext = value
return r
}

// UseEncodedPath tells the router to match the encoded original path
// to the routes.
// For eg. "/path/foo%2Fbar/to" will match the path "/path/{var}/to".
Expand Down Expand Up @@ -445,13 +458,25 @@ func CurrentRoute(r *http.Request) *Route {
return nil
}

// requestWithRouteAndVars adds the matched vars to the request ctx.
// It shortcuts the operation when the vars are empty.
func requestWithVars(r *http.Request, vars map[string]string) *http.Request {
if len(vars) == 0 {
return r
}
ctx := context.WithValue(r.Context(), varsKey, vars)
return r.WithContext(ctx)
}

func requestWithRoute(r *http.Request, route *Route) *http.Request {
// requestWithRouteAndVars adds the matched route and vars to the request ctx.
// It saves extra allocations in cloning the request once and skipping the
//
// population of empty vars, which in turn mux.Vars can handle gracefully.
func requestWithRouteAndVars(r *http.Request, route *Route, vars map[string]string) *http.Request {
ctx := context.WithValue(r.Context(), routeKey, route)
if len(vars) > 0 {
ctx = context.WithValue(ctx, varsKey, vars)
}
return r.WithContext(ctx)
}

Expand All @@ -478,6 +503,14 @@ func cleanPath(p string) string {
return np
}

// replaceURLPath prints an url.URL with a different path.
func replaceURLPath(u *url.URL, p string) string {
// Operate on a copy of the request url.
u2 := *u
u2.Path = p
return u2.String()
}

// uniqueVars returns an error if two slices contain duplicated strings.
func uniqueVars(s1, s2 []string) error {
for _, v1 := range s1 {
Expand Down

0 comments on commit e44017d

Please sign in to comment.