AssemblyScript / assemblyscript

A TypeScript-like language for WebAssembly.
https://www.assemblyscript.org
Apache License 2.0
16.94k stars 664 forks source link

asc takes too long to initialize #2298

Open Heath123 opened 2 years ago

Heath123 commented 2 years ago
$ time asc --version
Version 0.20.6

________________________________________________________
Executed in    2.32 secs    fish           external
   usr time    7.88 secs    0.00 micros    7.88 secs
   sys time    0.15 secs  951.00 micros    0.15 secs

The problem is even worse when limited to one CPU core:

$ time taskset -c 0 asc --version
Version 0.20.6

________________________________________________________
Executed in    7.06 secs    fish           external
   usr time    6.86 secs  541.00 micros    6.86 secs
   sys time    0.15 secs  829.00 micros    0.15 secs

2 to 7 seconds? Does that matter?

On large codebases that don't get compiled often, maybe not so much, but when iterating quickly on a small piece of code that takes a fraction of a second to actually compile, this is a big problem. Imagine someone with a much worse PC than me trying to learn AssemblyScript - they may have to wait 30 seconds to compile their Hello World. Maybe that seems like an exaggeration but on the website repl.it (which, admittedly, has very low compute resources) it does take 20 seconds to compile a Hello World, with a warning about 100% CPU usage the whole time. Multiply this by hundreds of thousands of compilations in the development process and this is a big problem.

Why is it taking so long?

I asked on the AssemblyScript Discord and apparently this is caused by loading a 5MBish WASM file of Binaryen on each start. I was told it was probably because of parsing/base64 decoding, as it is stored in a base64 string in a JS file. but because the time reduces with the amount of CPU cores I think this is WASM module compilation.

nodejs does not yet have a WASM module cache, so it has to compile the Binaryen WASM file to native code from scratch on every start.

Possible solutions

With my limited knowledge. here are some solutions that seem like they could work:

dcodeIO commented 2 years ago

Binaryen's Wasm code is embedded in Binaryen's JS code as a base64 blob. That leads to the following situation:

  1. The JavaScript code that includes the large blob is parsed and compiled by the JS engine.
  2. JavaScript is used to decode the base64 encoded blob from a string to a byte array.
  3. Only then WebAssembly APIs compile and instantiate the byte array as a Wasm module.

There'd probably already be an improvement by moving Binaryen's Wasm code to a .wasm file as it eliminates part of 1, eliminates 2 and allows compilation to start sooner instead of waiting for 1 and 2. Perfectly possible of course that there are additional factors.

MaxGraey commented 2 years ago

I agree that we should improve initial startup time. But I'm wondering what is you system, node.js version and cpu? Here is my time for MacBook 2019, macOS 12.5, node v18.4.0:

time npx asc --version:

Version 0.20.12
npx asc --version  0.73s user 0.12s system 128% cpu 0.665 total

so it seems ~11x faster compared to your system

Heath123 commented 2 years ago

I agree that we should improve initial startup time. But I'm wondering what is you system, node.js version and cpu? Here is my time for MacBook 2019, macOS 12.5, node v18.4.0:

time npx asc --version:

Version 0.20.12
npx asc --version  0.73s user 0.12s system 128% cpu 0.665 total

so it seems ~11x faster compared to your system

Arch Linux, nodejs v18.6.0, Ryzen 7 5700U. I checked again and this time is now around 1 second.