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

Using std::cout increases .wasm size by 900kb #87

Closed
DanielHoffmann opened this issue Dec 20, 2019 · 6 comments
Closed

Using std::cout increases .wasm size by 900kb #87

DanielHoffmann opened this issue Dec 20, 2019 · 6 comments

Comments

@DanielHoffmann
Copy link

DanielHoffmann commented Dec 20, 2019

A simple C++ program I wrote was ~40kb, but adding a simple std::cout << "Hello World" increased the bundle size to ~950kb (using -O2, -Os doesn't affect the size much). Using stdio.h printf() doesn't meaningfully change .wasm file size

Not sure if there is a bug in the sdk or there is just a lot of logic inside std::cout that I am not aware of. In any case it can be extremely hard to track down the final .wasm size to the features used, it might be something this project could help track with an external tool somehow (linker flag to add some special tokens to the .wasm file?)

@sunfishcode
Copy link
Member

Not that this isn't a bug, but on a common x86-64 Linux distro, a statically-linked cout hello world is 2.3M while a statically linked printf hello world is 843K. cout pulls in locales which pulls in code for parsing currency values, converting dates, transcoding between utf8 and utf16, the names of the months and days of the week, and all manner of other things, often in two copies to support char and wchar_t.

twiggy is a convenient tool for inspecting code size. The biggest function is printf_core, which is part of libc's wchar_t support. And there are a lot of other smaller functions getting pulled in too.

Wabt's wasm-strip can help, because with all those locale functions the name section gets quite big. Binaryen's wasm-opt can also help. I'm also working on support for building libc and libc++ with LTO (currently blocked on WebAssembly/tool-conventions#134) which will also help. But none of those completely gets rid of the locale code and all its dependencies.

@kripken
Copy link
Member

kripken commented Dec 20, 2019

Definitely libc and libc++ were not designed for compact static linking, however, even without LTO I think wasi-sdk can do better? In particular while C++ iostream code does bring in a lot more syscalls, ctors, etc., plain C stdio should be more compact, so

Using stdio.h printf() doesn't meaningfully change .wasm file size [from around 950 K]

makes me think there are big optimization opportunities here!

For comparison, emscripten -O3 with C++ iostream hello world is 141 K of wasm (222 K with JS) while hello world with stdio is less than 2 K of wasm (16 K with JS). As another datapoint, cheerp sizes were roughly comparable to emscripten last I checked.

Btw, other useful tools for figuring out binary size issues are bloaty and wasm-opt's --func-metrics pass.

@sunfishcode
Copy link
Member

Indeed, and top-of-tree wasi-sdk and wasi-libc have in fact improved substantially in their ability to micro-optimize hello world, but it sounds like the original poster was asking about something more substantial than hello world.

@DanielHoffmann
Copy link
Author

DanielHoffmann commented Dec 21, 2019

I was not asking anything, just wondering if it was a bug and if it is not then it is something that would be very useful to focus on optimising. If you are using a C++ library it will likely be using cout/cerr for debug/error/info messages, so any lib might increase your wasm filesize dramatically.

It might be useful to have a way to build wasi-libc++ in a way that makes assumptions to reduce binary size (for example making cout/cerr not do anything). Unfortunately I am more of a JS person than C++ person so I don't think I can make meaningful contributions to this, but someone reading this might want to take action.

Anyway thanks for the answers! I will take a look at the optimisers you mentioned

I forgot to mention but I am using the latest pre-built binaries for wasi-sdk and clang 9.0.0

@sunfishcode
Copy link
Member

Also, eventually, we'll have support for dynamic linking, which would be another approach, though that's not ready yet either.

A version of libc++ that stubs out cout/cerr/etc. to not do anything may be the best one could do, for now. If someone were interested in building such a library, I'd be open to adding that to wasi-sdk as an option.

@sunfishcode
Copy link
Member

If there are any further questions about this, please file new issues!

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

3 participants