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

Move TypeScript to a seperate isolate #1190

Closed
kitsonk opened this issue Nov 14, 2018 · 5 comments
Closed

Move TypeScript to a seperate isolate #1190

kitsonk opened this issue Nov 14, 2018 · 5 comments
Milestone

Comments

@kitsonk
Copy link
Contributor

kitsonk commented Nov 14, 2018

@ry and I have been having a side conversation about breaking out TypeScript into a seperate isolate. TypeScript would then not be part of the runtime isolate where user code runs. There are potentially various benefits to this approach:

  • Better startup time, as for various reasons the snapshot for Deno continues to increase in size and that takes time to restore. TypeScript is easily the biggest part of that.
  • Having a seperate isolate would mean that Deno could lazily load the "compiler" snapshot when it encounters a module that hasn't been transpiled.
  • It increases security, in the sense that runtime user code would have no access to modify or change how code is transpiled.
  • We can focus on performance a bit easier, the performance of transpilation and the performance of the Deno runtime, without wondering which is which.

Based on that I created a POC (https://github.com/kitsonk/deno/tree/breakup-compiler) which will generate two binaries, deno which is the standard full featured build and deno_runner which is only capable of loading already cached/transpiled modules. If the module isn't cached locally, deno_runner just fails rather ungracefully. This was to find out how much more efficient on "warm" startup.

The binary size is pretty significantly reduced:

$ ls -lh target/debug/deno*
-rwxr-xr-x  1 kkelly  staff   107M 14 Nov 11:43 target/debug/deno
-rwxr-xr-x  1 kkelly  staff    61M 14 Nov 21:48 target/debug/deno_runner

This is unlikely to be the case in the long term, as the binary would need to contain a TypeScript snapshot and could go back up to current size, but it shows that 40% of the binary is essentially related to TypeScript.

The performance is pretty interesting:

hyperfine --ignore-failure --export-json target/debug/benchmark.json --warmup 3 target/debug/deno tests/002_hello.ts target/debug/deno tests/003_relative_import.ts target/debug/deno_runner tests/002_hello.ts target/debug/deno_runner tests/003_relative_import.ts
Benchmark #1: target/debug/deno tests/002_hello.ts
  Time (mean ± σ):     242.0 ms ±   3.2 ms    [User: 181.0 ms, System: 58.1 ms]
  Range (min … max):   238.0 ms … 246.6 ms

Benchmark #2: target/debug/deno tests/003_relative_import.ts
  Time (mean ± σ):     246.3 ms ±   4.3 ms    [User: 186.6 ms, System: 58.0 ms]
  Range (min … max):   240.3 ms … 254.1 ms

Benchmark #3: target/debug/deno_runner tests/002_hello.ts
  Time (mean ± σ):      94.1 ms ±   2.8 ms    [User: 72.4 ms, System: 20.9 ms]
  Range (min … max):    90.7 ms … 102.5 ms

Benchmark #4: target/debug/deno_runner tests/003_relative_import.ts
  Time (mean ± σ):      99.0 ms ±   4.5 ms    [User: 76.0 ms, System: 21.3 ms]
  Range (min … max):    92.5 ms … 111.0 ms

Summary
  'target/debug/deno_runner tests/002_hello.ts' ran
    1.05 ± 0.06 times faster than 'target/debug/deno_runner tests/003_relative_import.ts'
    2.57 ± 0.08 times faster than 'target/debug/deno tests/002_hello.ts'
    2.62 ± 0.09 times faster than 'target/debug/deno tests/003_relative_import.ts'

So on my machine, essentially doing exactly the same thing, startup for Deno is 2.5x faster. @ry did some tests on the branch as well, and discovered that actually runtime performance really isn't impacted.

On the surface, even if it doesn't buy us a specific runtime performance improvement at this point, it just feels that the approach of separating TypeScript and runtime into seperate isolates would be an overall net benefit with no identifiable downsides at this point.

@anjmao
Copy link

anjmao commented Nov 28, 2018

@kitsonk My suggestion is to allow bundle user code into single bundle with command deno build. This way there is no need for warmup. Personally I can't imagine having a web server which takes ~1s to startup because in needs to transpile my Typescript code on runtime. JIT can be still used for deno run main.ts, but for production AOT compilation seems like a better choose.

@kitsonk
Copy link
Contributor Author

kitsonk commented Nov 28, 2018

@anjmao that is #21. Currently Deno (now and when this lands) will simply load all cached transpiled code. The bundle though is still a good idea.

The other thing that is a little bit of a challenge at the moment is that we don't support ES modules directly, so even JavaScript code needs to be transpiled. That is #975.

But delivery of both of those still means we need an efficient way of supporting the TypeScript compiler within Deno and lazy loading it will give us a big boost, likely even a boost on cold startup. The snapshotting is actually really effective and if we are eventually maybe even able to customise snapshots with bundles... 🎉 🍾

@shreeve
Copy link

shreeve commented Jan 7, 2019

Using this approach, can additional isolates such as one for CoffeeScript 2 (which supports native ES modules) one day be supported?

@ry
Copy link
Member

ry commented Jan 7, 2019

@shreeve Sure, I'd like to make the system general enough to support alternative compilations - but it's a ways off - we have to get this big landed and cleaned up first.

@shreeve
Copy link

shreeve commented Jan 7, 2019

@ry - Excellent... deno is looking great! Thanks.

@ry ry closed this as completed in #1460 Jan 9, 2019
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

No branches or pull requests

4 participants