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

Large file size with fetch example? #1078

Closed
liamcurry opened this issue Dec 2, 2018 · 5 comments
Closed

Large file size with fetch example? #1078

liamcurry opened this issue Dec 2, 2018 · 5 comments
Labels
file-size Issues related to compiled wasm file sizes

Comments

@liamcurry
Copy link
Contributor

Compiling the fetch example here: https://github.com/rustwasm/wasm-bindgen/tree/master/examples/fetch

Generates a larger .wasm file than expected at 155KB, which can be reduced to 115KB with wasm-opt.

I've copied the source to my own project and compiled with these commands:

cargo build --target wasm32-unknown-unknown --release
wasm-bindgen target/wasm32-unknown-unknown/release/fetch.wasm --out-dir dist
wasm-opt -Oz --output dist/fetch_bg_opt.wasm dist/fetch_bg.wasm
$ ls -lah dist
total 449K
drwxr-xr-x 1 sagan 197121    0 Dec  2 12:11 ./
drwxr-xr-x 1 sagan 197121    0 Dec  2 12:11 ../
-rw-r--r-- 1 sagan 197121   50 Dec  2 12:23 fetch.d.ts
-rw-r--r-- 1 sagan 197121 9.3K Dec  2 12:23 fetch.js
-rw-r--r-- 1 sagan 197121 155K Dec  2 12:23 fetch_bg.wasm
-rw-r--r-- 1 sagan 197121 115K Dec  2 12:25 fetch_bg_opt.wasm

I have this in my Cargo.toml file:

[profile.release]
lto = true
opt-level = "s"
debug = false
panic = "abort"

Is there any way to shrink this file down? 100KB is kind of a lot for just fetching/deserializing some JSON.

@alexcrichton
Copy link
Contributor

Thanks for the report! Sounds like you've already skimmed over (at least) the guide for making small wasm binaries, and after all the low-hanging fruit is out of the way the main contenders left to reduce the size here are more invasive tools and techniques

The fetch example in particular has lots of stuff inside it:

  • A JSON parser for Branch
  • A JSON serializer for Branch
  • A runtime executor for futures
  • Surely the formatting/panic code from libstd
  • An allocator somewhere in there

That's actually quite a lot to pack into 100KB! Reducing the size here would come about from algorithmic changes, such as relying on JS's JSON parser or avoiding all runtime panics in the code itself (extra hard mode).

Does that help explain what's going on?

@liamcurry
Copy link
Contributor Author

Does that help explain what's going on?

Yes it does, thank you! It sounds like reducing the code size here would involve replacing serde and futures, which at that point it might be better to handle fetching logic purely in JS. Do you think this is something that could be improved with host bindings?

avoiding all runtime panics in the code itself (extra hard mode).

I wish Rust had an opt-in feature to disallow any panicing code at compile time, that would be really useful!

@alexcrichton
Copy link
Contributor

Do you think this is something that could be improved with host bindings?

Perhaps! Most likely no, though. I think the generate JS bindings will tend to get a bit smaller, but the Rust side of things will likely remain about the same. Hard to say though for certain as we don't have any actual implementations yet!

This is something where while it'd be awesome tends to not be a 1:1 tradeoff with JS and wasm file sizes. If you trade N bytes of JS for N bytes of wasm you're unlikely to reach feature parity with the JS nowadays (unfortunately). Wasm is simply so small (the specification) and it has had so little time to develop good standards (like CDNs for commonly used JS libraries) that it's still a "bring your own runtime" situation.

Fear not though! File size is only one metric towards what's probably the most important metric, time to user interaction. Wasm, while often larger than equivalent JS, compiles much quicker than JS and can often get up and running in the engine far more quickly than JS. Wasm, using instantiateStreaming, is basically ready to execute the second the network transfer finishes. JS, however, typically takes a bit longer to catch up with parsing and get up to speed in the interpreter.

In any case, it's good to measure either way for your local use case!

I wish Rust had an opt-in feature to disallow any panicing code at compile time, that would be really useful!

It's funny you should mention that...

@liamcurry
Copy link
Contributor Author

Fear not though! File size is only one metric towards what's probably the most important metric, time to user interaction. Wasm, while often larger than equivalent JS, compiles much quicker than JS and can often get up and running in the engine far more quickly than JS.

That is a great point that I hadn't thought of. Thanks!

@Pauan
Copy link
Contributor

Pauan commented Dec 6, 2018

It sounds like reducing the code size here would involve replacing serde

Replacing serde_json with the native JSON.parse will probably have a significant performance slowdown.

As an example, I have a stdweb app which parses 50 MBs of JSON:

  • JSON.parse takes 1,491 milliseconds to parse the JSON, and it does not convert it into Rust structs.

  • serde_json takes 478 milliseconds to parse the JSON and convert it into Rust structs.

So serde_json is much faster, and more convenient (since it can auto-convert into Rust structs).

So you might have to make a code size vs code performance trade-off.

And as always: measure the performance in your own app.

@alexcrichton alexcrichton added the file-size Issues related to compiled wasm file sizes label Dec 21, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
file-size Issues related to compiled wasm file sizes
Projects
None yet
Development

No branches or pull requests

3 participants