go-resty / resty

Simple HTTP and REST client library for Go
MIT License
9.89k stars 696 forks source link

Add Benchmarks and Unit tests for parseRequestBody and improve it #714

Closed SVilgelm closed 11 months ago

SVilgelm commented 11 months ago

Improve the parseRequestBody function and all nested functions.

Original benchmarks:

% go test -benchmem -bench=. -run=^Benchmark
goos: darwin
goarch: amd64
pkg: github.com/go-resty/resty/v2
cpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
Benchmark_parseRequestBody_string-16       2199196    550.3 ns/op     128 B/op      3 allocs/op
Benchmark_parseRequestBody_byte-16         2264421    532.9 ns/op     128 B/op      3 allocs/op
Benchmark_parseRequestBody_reader-16       8307141    141.8 ns/op      16 B/op      1 allocs/op
Benchmark_parseRequestBody_struct-16        931632     1317 ns/op     156 B/op      5 allocs/op
Benchmark_parseRequestBody_struct_xml-16    409074     2921 ns/op    4765 B/op     13 allocs/op
Benchmark_parseRequestBody_map-16           566750     2158 ns/op     570 B/op     15 allocs/op
Benchmark_parseRequestBody_slice-16         957828     1279 ns/op     146 B/op      4 allocs/op
Benchmark_parseRequestBody_FormData-16      954213     1266 ns/op     304 B/op     14 allocs/op
Benchmark_parseRequestBody_MultiPart-16      94276    12538 ns/op    8746 B/op    131 allocs/op

After the improvements:

Benchmark_parseRequestBody_string-16                              7635237    155.7 ns/op      16 B/op      1 allocs/op
Benchmark_parseRequestBody_byte-16                                8453085    140.4 ns/op      16 B/op      1 allocs/op
Benchmark_parseRequestBody_reader_with_SetContentLength-16       17494558    67.62 ns/op      16 B/op      1 allocs/op
Benchmark_parseRequestBody_reader_without_SetContentLength-16    26582679    45.11 ns/op       0 B/op      0 allocs/op
Benchmark_parseRequestBody_struct-16                              1264702    943.9 ns/op      40 B/op      2 allocs/op
Benchmark_parseRequestBody_struct_xml-16                           479361     2496 ns/op    4645 B/op     10 allocs/op
Benchmark_parseRequestBody_map-16                                  685204     1770 ns/op     454 B/op     12 allocs/op
Benchmark_parseRequestBody_slice-16                               1318749    910.2 ns/op      32 B/op      2 allocs/op
Benchmark_parseRequestBody_FormData-16                            1000000     1116 ns/op     272 B/op      9 allocs/op
Benchmark_parseRequestBody_MultiPart-16                             92143    12532 ns/op    8738 B/op    130 allocs/op
codecov[bot] commented 11 months ago

Codecov Report

Attention: 2 lines in your changes are missing coverage. Please review.

Comparison is base (3face0d) 96.34% compared to head (3408a15) 96.57%.

Additional details and impacted files ```diff @@ Coverage Diff @@ ## master #714 +/- ## ========================================== + Coverage 96.34% 96.57% +0.22% ========================================== Files 12 12 Lines 1616 1607 -9 ========================================== - Hits 1557 1552 -5 + Misses 37 35 -2 + Partials 22 20 -2 ``` | [Files](https://app.codecov.io/gh/go-resty/resty/pull/714?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-resty) | Coverage Δ | | |---|---|---| | [middleware.go](https://app.codecov.io/gh/go-resty/resty/pull/714?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-resty#diff-bWlkZGxld2FyZS5nbw==) | `94.03% <96.00%> (+1.17%)` | :arrow_up: |

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

moorereason commented 11 months ago

Tip: use benchstat.

SVilgelm commented 11 months ago
% benchstat old.txt new.txt 
goos: darwin
goarch: amd64
pkg: github.com/go-resty/resty/v2
cpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
                                                     │    old.txt    │                new.txt                │
                                                     │    sec/op     │    sec/op     vs base                 │
_parseRequestHeader-16                                  159.6n ± ∞ ¹   152.4n ± ∞ ¹        ~ (p=1.000 n=1) ²
_parseRequestBody_string-16                             550.2n ± ∞ ¹   156.8n ± ∞ ¹        ~ (p=1.000 n=1) ²
_parseRequestBody_byte-16                               531.5n ± ∞ ¹   142.1n ± ∞ ¹        ~ (p=1.000 n=1) ²
_parseRequestBody_reader_with_SetContentLength-16      141.40n ± ∞ ¹   69.34n ± ∞ ¹        ~ (p=1.000 n=1) ²
_parseRequestBody_reader_without_SetContentLength-16    84.30n ± ∞ ¹   44.86n ± ∞ ¹        ~ (p=1.000 n=1) ²
_parseRequestBody_struct-16                            1307.0n ± ∞ ¹   953.0n ± ∞ ¹        ~ (p=1.000 n=1) ²
_parseRequestBody_struct_xml-16                         2.886µ ± ∞ ¹   2.471µ ± ∞ ¹        ~ (p=1.000 n=1) ²
_parseRequestBody_map-16                                2.152µ ± ∞ ¹   1.775µ ± ∞ ¹        ~ (p=1.000 n=1) ²
_parseRequestBody_slice-16                             1264.0n ± ∞ ¹   913.0n ± ∞ ¹        ~ (p=1.000 n=1) ²
_parseRequestBody_FormData-16                           1.243µ ± ∞ ¹   1.247µ ± ∞ ¹        ~ (p=1.000 n=1) ²
_parseRequestBody_MultiPart-16                          12.32µ ± ∞ ¹   12.54µ ± ∞ ¹        ~ (p=1.000 n=1) ²
geomean                                                 801.3n         511.7n        -36.13%
¹ need >= 6 samples for confidence interval at level 0.95
² need >= 4 samples to detect a difference at alpha level 0.05

                                                     │    old.txt    │                new.txt                 │
                                                     │     B/op      │     B/op       vs base                 │
_parseRequestHeader-16                                   0.000 ± ∞ ¹     0.000 ± ∞ ¹        ~ (p=1.000 n=1) ²
_parseRequestBody_string-16                             128.00 ± ∞ ¹     16.00 ± ∞ ¹        ~ (p=1.000 n=1) ³
_parseRequestBody_byte-16                               128.00 ± ∞ ¹     16.00 ± ∞ ¹        ~ (p=1.000 n=1) ³
_parseRequestBody_reader_with_SetContentLength-16        16.00 ± ∞ ¹     16.00 ± ∞ ¹        ~ (p=1.000 n=1) ²
_parseRequestBody_reader_without_SetContentLength-16     0.000 ± ∞ ¹     0.000 ± ∞ ¹        ~ (p=1.000 n=1) ²
_parseRequestBody_struct-16                             155.00 ± ∞ ¹     40.00 ± ∞ ¹        ~ (p=1.000 n=1) ³
_parseRequestBody_struct_xml-16                        4.650Ki ± ∞ ¹   4.533Ki ± ∞ ¹        ~ (p=1.000 n=1) ³
_parseRequestBody_map-16                                 569.0 ± ∞ ¹     454.0 ± ∞ ¹        ~ (p=1.000 n=1) ³
_parseRequestBody_slice-16                              146.00 ± ∞ ¹     32.00 ± ∞ ¹        ~ (p=1.000 n=1) ³
_parseRequestBody_FormData-16                            304.0 ± ∞ ¹     272.0 ± ∞ ¹        ~ (p=1.000 n=1) ³
_parseRequestBody_MultiPart-16                         8.541Ki ± ∞ ¹   8.533Ki ± ∞ ¹        ~ (p=1.000 n=1) ³
geomean                                                            ⁴                  -48.94%               ⁴
¹ need >= 6 samples for confidence interval at level 0.95
² all samples are equal
³ need >= 4 samples to detect a difference at alpha level 0.05
⁴ summaries must be >0 to compute geomean

                                                     │   old.txt    │               new.txt                │
                                                     │  allocs/op   │  allocs/op   vs base                 │
_parseRequestHeader-16                                  0.000 ± ∞ ¹   0.000 ± ∞ ¹        ~ (p=1.000 n=1) ²
_parseRequestBody_string-16                             3.000 ± ∞ ¹   1.000 ± ∞ ¹        ~ (p=1.000 n=1) ³
_parseRequestBody_byte-16                               3.000 ± ∞ ¹   1.000 ± ∞ ¹        ~ (p=1.000 n=1) ³
_parseRequestBody_reader_with_SetContentLength-16       1.000 ± ∞ ¹   1.000 ± ∞ ¹        ~ (p=1.000 n=1) ²
_parseRequestBody_reader_without_SetContentLength-16    0.000 ± ∞ ¹   0.000 ± ∞ ¹        ~ (p=1.000 n=1) ²
_parseRequestBody_struct-16                             5.000 ± ∞ ¹   2.000 ± ∞ ¹        ~ (p=1.000 n=1) ³
_parseRequestBody_struct_xml-16                         13.00 ± ∞ ¹   10.00 ± ∞ ¹        ~ (p=1.000 n=1) ³
_parseRequestBody_map-16                                15.00 ± ∞ ¹   12.00 ± ∞ ¹        ~ (p=1.000 n=1) ³
_parseRequestBody_slice-16                              4.000 ± ∞ ¹   2.000 ± ∞ ¹        ~ (p=1.000 n=1) ³
_parseRequestBody_FormData-16                          14.000 ± ∞ ¹   9.000 ± ∞ ¹        ~ (p=1.000 n=1) ³
_parseRequestBody_MultiPart-16                          131.0 ± ∞ ¹   130.0 ± ∞ ¹        ~ (p=1.000 n=1) ³
geomean                                                           ⁴                -35.02%               ⁴
¹ need >= 6 samples for confidence interval at level 0.95
² all samples are equal
³ need >= 4 samples to detect a difference at alpha level 0.05
⁴ summaries must be >0 to compute geomean
SVilgelm commented 11 months ago

Tip: use benchstat.

thank you, didn't know

moorereason commented 11 months ago

Also, use something like -count=10 to gather more samples. That should get rid of the benchstat footnotes.

SVilgelm commented 11 months ago
goos: darwin
goarch: amd64
pkg: github.com/go-resty/resty/v2
cpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
                                                     │   old.txt    │               new.txt                │
                                                     │    sec/op    │    sec/op     vs base                │
_parseRequestHeader-16                                  172.4n ± 1%   172.6n ±  1%        ~ (p=0.518 n=10)
_parseRequestBody_string-16                             539.1n ± 1%   182.6n ±  5%  -66.13% (p=0.000 n=10)
_parseRequestBody_byte-16                               527.5n ± 1%   173.8n ±  0%  -67.04% (p=0.000 n=10)
_parseRequestBody_reader_with_SetContentLength-16      157.80n ± 0%   87.33n ±  0%  -44.66% (p=0.000 n=10)
_parseRequestBody_reader_without_SetContentLength-16    89.64n ± 0%   49.93n ±  1%  -44.30% (p=0.000 n=10)
_parseRequestBody_struct-16                            1206.0n ± 1%   860.2n ±  3%  -28.67% (p=0.000 n=10)
_parseRequestBody_struct_xml-16                         2.889µ ± 6%   2.414µ ±  2%  -16.46% (p=0.000 n=10)
_parseRequestBody_map-16                                1.804µ ± 1%   1.445µ ±  2%  -19.93% (p=0.000 n=10)
_parseRequestBody_slice-16                             1161.5n ± 0%   832.1n ±  1%  -28.36% (p=0.000 n=10)
_parseRequestBody_FormData-16                           1.260µ ± 2%   1.929µ ± 19%  +53.06% (p=0.000 n=10)
_parseRequestBody_MultiPart-16                          14.86µ ± 4%   23.39µ ± 17%  +57.43% (p=0.000 n=10)
geomean                                                 807.2n        583.9n        -27.66%

                                                     │    old.txt     │                new.txt                 │
                                                     │      B/op      │     B/op      vs base                  │
_parseRequestHeader-16                                   0.000 ± 0%       0.000 ± 0%        ~ (p=1.000 n=10) ¹
_parseRequestBody_string-16                             128.00 ± 0%       16.00 ± 0%  -87.50% (p=0.000 n=10)
_parseRequestBody_byte-16                               128.00 ± 0%       16.00 ± 0%  -87.50% (p=0.000 n=10)
_parseRequestBody_reader_with_SetContentLength-16        16.00 ± 0%       16.00 ± 0%        ~ (p=1.000 n=10) ¹
_parseRequestBody_reader_without_SetContentLength-16     0.000 ± 0%       0.000 ± 0%        ~ (p=1.000 n=10) ¹
_parseRequestBody_struct-16                             155.00 ± 0%       40.00 ± 0%  -74.19% (p=0.000 n=10)
_parseRequestBody_struct_xml-16                        4.652Ki ± 0%     4.537Ki ± 0%   -2.49% (p=0.000 n=10)
_parseRequestBody_map-16                                 487.0 ± 0%       371.0 ± 0%  -23.82% (p=0.000 n=10)
_parseRequestBody_slice-16                              145.00 ± 0%       32.00 ± 0%  -77.93% (p=0.000 n=10)
_parseRequestBody_FormData-16                            304.0 ± 0%       272.0 ± 0%  -10.53% (p=0.000 n=10)
_parseRequestBody_MultiPart-16                         9.919Ki ± 0%     9.911Ki ± 0%   -0.08% (p=0.000 n=10)
geomean                                                             ²                 -49.12%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                                     │    old.txt    │               new.txt                │
                                                     │   allocs/op   │ allocs/op   vs base                  │
_parseRequestHeader-16                                  0.000 ± 0%     0.000 ± 0%        ~ (p=1.000 n=10) ¹
_parseRequestBody_string-16                             3.000 ± 0%     1.000 ± 0%  -66.67% (p=0.000 n=10)
_parseRequestBody_byte-16                               3.000 ± 0%     1.000 ± 0%  -66.67% (p=0.000 n=10)
_parseRequestBody_reader_with_SetContentLength-16       1.000 ± 0%     1.000 ± 0%        ~ (p=1.000 n=10) ¹
_parseRequestBody_reader_without_SetContentLength-16    0.000 ± 0%     0.000 ± 0%        ~ (p=1.000 n=10) ¹
_parseRequestBody_struct-16                             5.000 ± 0%     2.000 ± 0%  -60.00% (p=0.000 n=10)
_parseRequestBody_struct_xml-16                         13.00 ± 0%     10.00 ± 0%  -23.08% (p=0.000 n=10)
_parseRequestBody_map-16                                13.00 ± 0%     10.00 ± 0%  -23.08% (p=0.000 n=10)
_parseRequestBody_slice-16                              4.000 ± 0%     2.000 ± 0%  -50.00% (p=0.000 n=10)
_parseRequestBody_FormData-16                          14.000 ± 0%     9.000 ± 0%  -35.71% (p=0.000 n=10)
_parseRequestBody_MultiPart-16                          133.0 ± 0%     132.0 ± 0%   -0.75% (p=0.000 n=10)
geomean                                                            ²               -35.25%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean
SVilgelm commented 11 months ago

New benchmarks, also no significant changes:

goos: darwin
goarch: amd64
pkg: github.com/go-resty/resty/v2
cpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
                                                     │    old.txt    │               new.txt               │
                                                     │    sec/op     │   sec/op     vs base                │
_parseRequestHeader-16                                  171.2n ±  3%   173.7n ± 6%   +1.46% (p=0.009 n=10)
_parseRequestBody_string-16                             542.7n ±  2%   183.3n ± 1%  -66.22% (p=0.000 n=10)
_parseRequestBody_byte-16                               536.8n ±  1%   176.3n ± 1%  -67.15% (p=0.000 n=10)
_parseRequestBody_reader_with_SetContentLength-16      161.15n ±  0%   87.97n ± 1%  -45.41% (p=0.000 n=10)
_parseRequestBody_reader_without_SetContentLength-16    89.63n ±  1%   50.53n ± 0%  -43.62% (p=0.000 n=10)
_parseRequestBody_struct-16                            1250.0n ± 10%   863.2n ± 0%  -30.94% (p=0.000 n=10)
_parseRequestBody_struct_xml-16                         2.854µ ±  3%   2.534µ ± 3%  -11.23% (p=0.000 n=10)
_parseRequestBody_map-16                                1.842µ ±  2%   1.451µ ± 0%  -21.21% (p=0.000 n=10)
_parseRequestBody_slice-16                             1166.5n ±  1%   834.8n ± 0%  -28.44% (p=0.000 n=10)
_parseRequestBody_FormData-16                           1.288µ ±  1%   1.003µ ± 1%  -22.17% (p=0.000 n=10)
_parseRequestBody_MultiPart-16                          14.65µ ±  1%   14.62µ ± 1%        ~ (p=0.183 n=10)
geomean                                                 814.1n         532.1n       -34.64%

                                                     │    old.txt     │                new.txt                 │
                                                     │      B/op      │     B/op      vs base                  │
_parseRequestHeader-16                                   0.000 ± 0%       0.000 ± 0%        ~ (p=1.000 n=10) ¹
_parseRequestBody_string-16                             128.00 ± 0%       16.00 ± 0%  -87.50% (p=0.000 n=10)
_parseRequestBody_byte-16                               128.00 ± 0%       16.00 ± 0%  -87.50% (p=0.000 n=10)
_parseRequestBody_reader_with_SetContentLength-16        16.00 ± 0%       16.00 ± 0%        ~ (p=1.000 n=10) ¹
_parseRequestBody_reader_without_SetContentLength-16     0.000 ± 0%       0.000 ± 0%        ~ (p=1.000 n=10) ¹
_parseRequestBody_struct-16                             155.00 ± 0%       40.00 ± 0%  -74.19% (p=0.000 n=10)
_parseRequestBody_struct_xml-16                        4.649Ki ± 0%     4.534Ki ± 0%   -2.48% (p=0.000 n=10)
_parseRequestBody_map-16                                 487.0 ± 0%       372.0 ± 0%  -23.61% (p=0.000 n=10)
_parseRequestBody_slice-16                              145.00 ± 0%       32.00 ± 0%  -77.93% (p=0.000 n=10)
_parseRequestBody_FormData-16                            304.0 ± 0%       272.0 ± 0%  -10.53% (p=0.000 n=10)
_parseRequestBody_MultiPart-16                         9.919Ki ± 0%     9.911Ki ± 0%   -0.08% (p=0.000 n=10)
geomean                                                             ²                 -49.11%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                                     │    old.txt    │               new.txt                │
                                                     │   allocs/op   │ allocs/op   vs base                  │
_parseRequestHeader-16                                  0.000 ± 0%     0.000 ± 0%        ~ (p=1.000 n=10) ¹
_parseRequestBody_string-16                             3.000 ± 0%     1.000 ± 0%  -66.67% (p=0.000 n=10)
_parseRequestBody_byte-16                               3.000 ± 0%     1.000 ± 0%  -66.67% (p=0.000 n=10)
_parseRequestBody_reader_with_SetContentLength-16       1.000 ± 0%     1.000 ± 0%        ~ (p=1.000 n=10) ¹
_parseRequestBody_reader_without_SetContentLength-16    0.000 ± 0%     0.000 ± 0%        ~ (p=1.000 n=10) ¹
_parseRequestBody_struct-16                             5.000 ± 0%     2.000 ± 0%  -60.00% (p=0.000 n=10)
_parseRequestBody_struct_xml-16                         13.00 ± 0%     10.00 ± 0%  -23.08% (p=0.000 n=10)
_parseRequestBody_map-16                                13.00 ± 0%     10.00 ± 0%  -23.08% (p=0.000 n=10)
_parseRequestBody_slice-16                              4.000 ± 0%     2.000 ± 0%  -50.00% (p=0.000 n=10)
_parseRequestBody_FormData-16                          14.000 ± 0%     9.000 ± 0%  -35.71% (p=0.000 n=10)
_parseRequestBody_MultiPart-16                          133.0 ± 0%     132.0 ± 0%   -0.75% (p=0.000 n=10)
geomean                                                            ²               -35.25%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean