body-parser icon indicating copy to clipboard operation
body-parser copied to clipboard

perf: eliminate conditional check in json strict mode hot path

Open Phillip9587 opened this issue 2 months ago • 2 comments

This change refactors the JSON parser to eliminate the per-request if (strict) conditional check from the parsing hot path.

Instead of checking strict mode during parsing, we now create specialized parser functions at middleware initialization based on the strict option.

I'm aware that this introduces some code duplication between the strict and non-strict parser implementations, but I think that is a necessary trade-off.

Phillip9587 avatar Oct 28 '25 20:10 Phillip9587

Ref: https://github.com/expressjs/perf-wg/pull/77

A (Baseline):

npm run test:load -- --test=@expressjs/perf-load-body-parser --write

B (This branch):

npm run test:load -- --test=@expressjs/perf-load-body-parser --write --overrides='{"body-parser":"Phillip9587/body-parser#perf-json-strict-hot-path"}'

My local load test results:

A Results: ./perf/load/body-parser/results/result-1764606166571.json
====================================================================

┌─────────┬────────┬────────┬─────────┬─────────┬───────────┬──────────┬─────────┐
│ Stat    │ 2.5%   │ 50%    │ 97.5%   │ 99%     │ Avg       │ Stdev    │ Max     │
├─────────┼────────┼────────┼─────────┼─────────┼───────────┼──────────┼─────────┤
│ Latency │ 678 ms │ 724 ms │ 1003 ms │ 1202 ms │ 753.07 ms │ 96.18 ms │ 1901 ms │
└─────────┴────────┴────────┴─────────┴─────────┴───────────┴──────────┴─────────┘
┌───────────┬────────┬─────────┬─────────┬─────────┬───────────┬──────────┬────────┐
│ Stat      │ 1%     │ 2.5%    │ 50%     │ 97.5%   │ Avg       │ Stdev    │ Min    │
├───────────┼────────┼─────────┼─────────┼─────────┼───────────┼──────────┼────────┤
│ Req/Sec   │ 458    │ 10,335  │ 19,951  │ 21,423  │ 19,303.24 │ 3,059.32 │ 458    │
├───────────┼────────┼─────────┼─────────┼─────────┼───────────┼──────────┼────────┤
│ Bytes/Sec │ 322 kB │ 7.54 MB │ 14.5 MB │ 15.6 MB │ 14.1 MB   │ 2.23 MB  │ 321 kB │
└───────────┴────────┴─────────┴─────────┴─────────┴───────────┴──────────┴────────┘

Req/Bytes counts sampled once per second.
# of samples: 60

1173k requests in 60.03s, 844 MB read
83 errors (0 timeouts)

B Results: ./perf/load/body-parser/results/result-1764606062525.json
====================================================================

┌─────────┬────────┬────────┬────────┬────────┬───────────┬──────────┬─────────┐
│ Stat    │ 2.5%   │ 50%    │ 97.5%  │ 99%    │ Avg       │ Stdev    │ Max     │
├─────────┼────────┼────────┼────────┼────────┼───────────┼──────────┼─────────┤
│ Latency │ 594 ms │ 609 ms │ 844 ms │ 970 ms │ 628.79 ms │ 66.41 ms │ 1548 ms │
└─────────┴────────┴────────┴────────┴────────┴───────────┴──────────┴─────────┘
┌───────────┬────────┬─────────┬─────────┬─────────┬───────────┬──────────┬────────┐
│ Stat      │ 1%     │ 2.5%    │ 50%     │ 97.5%   │ Avg       │ Stdev    │ Min    │
├───────────┼────────┼─────────┼─────────┼─────────┼───────────┼──────────┼────────┤
│ Req/Sec   │ 409    │ 17,279  │ 21,295  │ 21,727  │ 20,632.29 │ 2,789.21 │ 409    │
├───────────┼────────┼─────────┼─────────┼─────────┼───────────┼──────────┼────────┤
│ Bytes/Sec │ 307 kB │ 12.6 MB │ 15.5 MB │ 15.8 MB │ 15 MB     │ 2.03 MB  │ 307 kB │
└───────────┴────────┴─────────┴─────────┴─────────┴───────────┴──────────┴────────┘

Req/Bytes counts sampled once per second.
# of samples: 60

1251k requests in 60.02s, 902 MB read
4 errors (0 timeouts)

Comparison: B Wins
==================
{
  diff: { rps: '-6.44%', throughput: '-6.44%', latency: '19.76%' },
  a: {
    avgRPS: 19303.24,
    avgThroughput: 14071464.54,
    avgLatency: 753.07,
    status: { '200': { count: 1158142 } }
  },
  b: {
    avgRPS: 20632.29,
    avgThroughput: 15040637.87,
    avgLatency: 628.79,
    status: { '200': { count: 1237872 } }
  }
}

cc: @wesleytodd

Phillip9587 avatar Dec 01 '25 16:12 Phillip9587

Ah awesome, yeah the perf tests are still a work in progress. So there is inconsistencies between runs and sometimes you may want to change the test requests or server implementation a bit to get real results. I just threw together some low effort requests with bodies in that PR but feel free to write ones that show the perf improvement even more than this did on your machine. And any feedback on running these is welcome!

wesleytodd avatar Dec 02 '25 14:12 wesleytodd