test(packages/codegen): include string flattening in benchmarks (#26106)
Over the weekend, I asked Fable to work on optimizing write operations when assembling the output string. This uncovered a disturbing finding. ### Unrealistic benchmarks The output string is assembled with repeated `output += segment` calls. This creates "cons strings" - a rope where each append creates a new string which references the previous `output` as its left side, and `segment` as its right side. On each append the rope gets longer - forming a linked list of segments. That rope-string is what `printSync` returns to the user. It is a string, so it's correct, but there's a problem. In order to actually use that string for anything (write it to a file, index into it, search it, run a regex on it, etc) it has to be flattened. V8 does that transparently, so it works fine, but it's a costly operation. So the disturbing finding was that we were ignoring that cost - we pushed it onto the user, and didn't measure it in our benchmarks. So, once this hidden cost is included, the codegen isn't as fast as we thought it was. ### Including the flatten cost This PR alters the benchmarks to include string flattening via the most common path that V8 takes in user code. The effect is pronounced (higher is worse): | Fixture | Bytes | Change | |:---| ---:| ---:| | `tiny.js` | 26 | \+92.4% | | `RadixUIAdoptionSection.jsx` | 2,424 | \+303.8% | | `react.development.js` | 50,496 | \+75.2% | | `binder.ts` | 126,212 | \+85.9% | | `lodash.js` | 182,262 | \+161.5% | | `App.tsx` | 298,130 | \+146.8% | | `kitchen-sink.tsx` | 662,560 | \+116.8% | | `antd.js` | 5,100,647 | \+72.5% | `RadixUIAdoptionSection.jsx` suffers in particular (4x slower) because one of the `JSXText` elements contain non-ASCII characters. This means the string has to be flattened to a 2-byte string (UTF-16) instead of the faster 1-byte (Latin1) representation. This encoding is twice as large, and hits V8's slow paths (because its optimized for 1-byte strings). This doesn't mean that codegen has got slower - we're just now measuring it more realistically. ### Source maps builds Source map builds are not affected - their perf doesn't change. They already flattened the `output` string by calling `indexOf` on it, so they were already paying the cost, we just didn't realize it. ### What to do? The good news is that there are some things we can do to mitigate the impact - see following PRs.
O
overlookmotel committed
5e6d537fca4465108d2d22264faa824dd2d753a1
Parent: 73c09b2