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

Update benchmark versions #3441

Merged
merged 6 commits into from
Oct 15, 2023
Merged

Update benchmark versions #3441

merged 6 commits into from
Oct 15, 2023

Conversation

rtsao
Copy link
Contributor

@rtsao rtsao commented Oct 11, 2023

Parcel v2.10.0 was just released and appears to significantly improve build performance.

This PR updates all bundler versions to latest. Notably, Parcel v2.10.0 now runs the three benchmark in around 7 seconds on my machine.

⏱️ `make bench-three` log on my M1 Max 64GB MacBook Pro:
❯ make bench-three
node scripts/esbuild.js --update-version-go
CGO_ENABLED=0 go build "-ldflags=-s -w" -trimpath ./cmd/esbuild
rm -fr bench/three/esbuild
time -p ./esbuild --bundle --global-name=THREE --sourcemap --minify bench/three/src/entry.js --outfile=bench/three/esbuild/entry.esbuild.js --timing
▶ [INFO] Timing information (times may not nest hierarchically due to parallelism)

  Scan phase: 241ms
    On-start callbacks: 0ms
    Preprocess injected files: 0ms
    Add entry points: 2ms
    Scan all dependencies: 237ms
    Process scanned files: 1ms
  Compile phase: 114ms
    Spawn source map tasks: 6ms
    Link: 106ms
      Clone linker graph: 12ms
      Scan imports and exports: 16ms
        Step 1: 0ms
        Step 2: 0ms
        Step 3: 0ms
        Step 4: 5ms
        Step 5: 4ms
        Step 6: 4ms
      Tree shaking: 1ms
      Code splitting: 1ms
      Compute chunks: 4ms
      Compute cross-chunk dependencies: 0ms
      Waiting for mangle cache: 0ms
      Mangle props: 0ms
      Mangle local CSS: 0ms
      Generate chunks: 69ms
        Generate chunk "entry.esbuild.js": 67ms
          Minify symbols: 12ms
            Compute reserved names: 1ms
            Accumulate symbol counts: 7ms
              Parallel phase: 4ms
              Serial phase: 3ms
            Assign names by frequency: 2ms
          Print JavaScript files: 38ms
          Join JavaScript files: 2ms
          Generate source map: 13ms
        Generate final output files: 1ms
  Write output files: 3ms
  On-end callbacks: 0ms


  bench/three/esbuild/entry.esbuild.js       5.8mb ⚠️
  bench/three/esbuild/entry.esbuild.js.map  19.7mb

⚡ Done in 362ms
real 0.78
user 1.18
sys 0.42
du -h bench/three/esbuild/entry.esbuild.js*
5.8M	bench/three/esbuild/entry.esbuild.js
 20M	bench/three/esbuild/entry.esbuild.js.map
shasum bench/three/esbuild/entry.esbuild.js*
1fab8f5660f49850edec482120604ce8645433b6  bench/three/esbuild/entry.esbuild.js
15282d14da3af1d8cc1038f2d18bd555e9322658  bench/three/esbuild/entry.esbuild.js.map
rm -fr require/rollup/bench/three bench/three/rollup
mkdir -p require/rollup/bench/three bench/three/rollup
echo "import terser from '@rollup/plugin-terser'; export default { output: { format: 'iife', name: 'THREE', sourcemap: true }, plugins: [terser()], }" > require/rollup/bench/three/config.mjs
ln -s ../../../../bench/three/src require/rollup/bench/three/src
ln -s ../../../../bench/three/rollup require/rollup/bench/three/out
cd require/rollup/bench/three && time -p ../../node_modules/.bin/rollup src/entry.js -o out/entry.rollup.js -c config.mjs

src/entry.js → out/entry.rollup.js...
(!) Circular dependencies
src/copy1/renderers/WebGLRenderTargetCube.js -> src/copy1/cameras/CubeCamera.js -> src/copy1/renderers/WebGLRenderTargetCube.js
src/copy2/renderers/WebGLRenderTargetCube.js -> src/copy2/cameras/CubeCamera.js -> src/copy2/renderers/WebGLRenderTargetCube.js
src/copy3/renderers/WebGLRenderTargetCube.js -> src/copy3/cameras/CubeCamera.js -> src/copy3/renderers/WebGLRenderTargetCube.js
...and 7 more
created out/entry.rollup.js in 22s
real 22.38
user 33.41
sys 4.46
du -h bench/three/rollup/entry.rollup.js*
5.8M	bench/three/rollup/entry.rollup.js
 19M	bench/three/rollup/entry.rollup.js.map
rm -fr require/webpack5/bench/three bench/three/webpack5
mkdir -p require/webpack5/bench/three bench/three/webpack5
ln -s ../../../../bench/three/src require/webpack5/bench/three/src
ln -s ../../../../bench/three/webpack5 require/webpack5/bench/three/out
cd require/webpack5/bench/three && time -p ../../node_modules/.bin/webpack --entry ./src/entry.js --devtool=source-map --mode=production --output-library THREE -o out/entry.webpack5.js
asset main.js 5.84 MiB [emitted] [minimized] [big] (name: main) 2 related assets
orphan modules 11.4 MiB [orphan] 3680 modules
runtime modules 670 bytes 3 modules
cacheable modules 11.5 MiB
  ../../../../bench/three/src/entry.js + 3680 modules 11.4 MiB [built] [code generated]
  ../../../../bench/three/src/copy1/polyfills.js 1.65 KiB [built] [code generated]
  ../../../../bench/three/src/copy2/polyfills.js 1.65 KiB [built] [code generated]
  ../../../../bench/three/src/copy3/polyfills.js 1.65 KiB [built] [code generated]
  ../../../../bench/three/src/copy4/polyfills.js 1.65 KiB [built] [code generated]
  ../../../../bench/three/src/copy5/polyfills.js 1.65 KiB [built] [code generated]
  ../../../../bench/three/src/copy6/polyfills.js 1.65 KiB [built] [code generated]
  ../../../../bench/three/src/copy7/polyfills.js 1.65 KiB [built] [code generated]
  ../../../../bench/three/src/copy8/polyfills.js 1.65 KiB [built] [code generated]
  ../../../../bench/three/src/copy9/polyfills.js 1.65 KiB [built] [code generated]
  ../../../../bench/three/src/copy10/polyfills.js 1.65 KiB [built] [code generated]

WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
This can impact web performance.
Assets:
  main.js (5.84 MiB)

WARNING in entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.
Entrypoints:
  main (5.84 MiB)
      main.js


WARNING in webpack performance recommendations:
You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
For more info visit https://webpack.js.org/guides/code-splitting/

webpack 5.88.2 compiled with 3 warnings in 26977 ms
real 27.54
user 38.12
sys 2.49
du -h bench/three/webpack5/entry.webpack5.js*
 25M	bench/three/webpack5/entry.webpack5.js
rm -fr require/parcel2/bench/three bench/three/parcel2
mkdir -p require/parcel2/bench/three bench/three/parcel2
# Copy the whole source tree since symlinks mess up Parcel's internal package lookup for "@babel/core"
cp -r bench/three/src require/parcel2/bench/three/src
echo 'import * as THREE from "./src/entry.js"; window.THREE = THREE' > require/parcel2/bench/three/entry.parcel2.js
cd require/parcel2/bench/three && time -p node ../../node_modules/.bin/parcel build \
		entry.parcel2.js --dist-dir ../../../../bench/three/parcel2 --cache-dir .cache
✨ Built in 7.06s

../../../../bench/three/parcel2/entry.parcel2.js    ⚠️  6.64 MB    3.75s
real 7.51
user 14.19
sys 2.05
du -h bench/three/parcel2/entry.parcel2.js*
6.6M	bench/three/parcel2/entry.parcel2.js
 34M	bench/three/parcel2/entry.parcel2.js.map

@evanw
Copy link
Owner

evanw commented Oct 12, 2023

Cool! It's great to see everyone's hard work on performance paying off. I'm a little too busy right now but I'm going to try to get some time to re-run the benchmarks this weekend (it takes a good bit of time because I restart my computer in between runs to make sure the file system cache is clean).

@evanw
Copy link
Owner

evanw commented Oct 15, 2023

I took a look at this. My findings:

  1. Webpack 5 and Rollup 4 and esbuild output sizes and build times don't change significantly.

  2. Parcel 2 is faster but I get build times around 15 seconds, not 7 seconds. Presumably because the benchmark machine isn't a M1 Max 64GB MacBook Pro.

  3. Parcel 2's output is much larger because the new minifier strangely preserves all comments (not just license-related comments). Disabling this requires an extra config file, which I can add to the benchmark. This seems like a Parcel 2 bug to me.

  4. Parcel 2 can handle the JavaScript benchmark but not the TypeScript benchmark, which is kind of a deal-breaker. It looks like bundling for node (specifically engines: node in package.json) disables interpretation of aliases (specifically alias in package.json) which is required for bundling this code base. I see this regression as a bug with Parcel 2's new resolver. This is a bug that esbuild had too, before I fixed it in esbuild: The module imported with the path alias specified in paths in tsconfig.json is not being bundled #3160.

    Edit: I found Parcel fails to bundle require('node:stream/web') used in node-fetch: gets transformed to import "8a78abd0b0f7c0d4:stream/web"; parcel-bundler/parcel#7387 (comment). This scenario requires includeNodeModules: true to be present for it to work. Now the TypeScript benchmark builds and runs successfully with Parcel 2. Next up I need to figure out why Parcel 2 is no longer minifying the TypeScript benchmark output...

    Edit 2: I discovered that a production build with engines: node needs optimize: true in package.json or the result is not minified. Plus I need the same minifier config file as before or the minifier preserves all comments in the source code. So this benchmark now works with Parcel 2.

evanw added 2 commits October 15, 2023 13:13
Bundling `alias` with `engine: node` needs `includeNodeModules: true` or aliases are ignored. See parcel-bundler/parcel#7387 (comment) for more info.
@evanw
Copy link
Owner

evanw commented Oct 15, 2023

Here are the updated benchmark results:

JavaScript benchmark

Old:

Bundler Time Relative slowdown Absolute speed Output size
esbuild 0.37s 1x 1479.6 kloc/s 5.80mb
parcel 2 30.50s 80x 17.9 kloc/s 5.87mb
rollup 3 + terser 32.07s 84x 17.1 kloc/s 5.81mb
webpack 5 39.70s 104x 13.8 kloc/s 5.84mb

New:

Bundler Time Relative slowdown Absolute speed Output size
esbuild 0.39ѕ 1x 1403.7 kloc/ѕ 5.80mb
parcel 2 14.91ѕ 38x 36.7 kloc/ѕ 5.78mb
rollup 4 + terser 34.10ѕ 87x 16.1 kloc/ѕ 5.82mb
webpack 5 41.21ѕ 106x 13.3 kloc/ѕ 5.84mb

So Parcel 2 is roughly twice as fast than before on this benchmark.

TypeScript benchmark

Old:

Bundler Time Relative slowdown Absolute speed Output size
esbuild 0.10s 1x 1318.4 kloc/s 0.97mb
parcel 2 8.18s 82x 16.1 kloc/s 0.97mb
webpack 5 15.96s 160x 8.3 kloc/s 1.27mb

New:

Bundler Time Relative slowdown Absolute speed Output size
esbuild 0.10ѕ 1x 1318.4 kloc/ѕ 0.97mb
parcel 2 6.91ѕ 69x 19.1 kloc/ѕ 0.96mb
webpack 5 16.69ѕ 167x 7.9 kloc/ѕ 1.27mb

So Parcel 2 is roughly 20% faster than before on this benchmark.

@evanw evanw merged commit cc679e0 into evanw:main Oct 15, 2023
6 checks passed
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