rustwasm / wee_alloc

The Wasm-Enabled, Elfin Allocator
Mozilla Public License 2.0
666 stars 49 forks source link

Binary size larger than advertized #66

Open frehberg opened 6 years ago

frehberg commented 6 years ago

Summary

Compiling a test-app with different settings (dlmalloc and wee_alloc) the resulting binary sizes of wee_alloc builds are not as small as expected. Benefit is just 3KB, the relation is 25KB for dlmalloc-builds compared to 22KB for wee_alloc-builds with code using simple String-allocation. see

With an application without any dynamic memory allocation, wee_alloc is adding 2500 bytes:

   829  wasm-game-of-life-dlmalloc/pkg/wasm_game_of_life_bg.wasm
3666  wasm-game-of-life-wee_alloc/pkg/wasm_game_of_life_bg.wasm

With an application using simple String allocation, wee_alloc is adding ca 21000 bytes, being just 3KB better than dlmalloc.

25179  wasm-game-of-life-dlmalloc-dyn/pkg/wasm_game_of_life_bg.wasm
22141  wasm-game-of-life-wee_alloc-dyn/pkg/wasm_game_of_life_bg.wasm

Steps to Reproduce

git clone https://github.com/frehberg/wasm-dyn-mem.git cd wasm-dyn-mem/rust-bindgen make build print-sizes

Expected Results

Linking against wee_alloc instead of dlmalloc I expected binaries being much more smaller and gaining larger benefit compared to dlmallic. Just, in some cases the binary is larger and the relation is just 22KB vs 25KB Maybe wee_alloc is using some code-patterns that can not be optimized as good as expected

fitzgen commented 6 years ago

The dynamic allocation example is measuring a whole lot more than just dynamic allocation: string formatting is rather heavy, and I suspect it is pulling in the panicking infrastructure as well.

If you are trying to specifically measure the code size of allocators, I suggest something more targeted, like https://github.com/rustwasm/wee_alloc/blob/master/example/src/lib.rs

You can built that with the ./build.sh script in this repo. If size classes are disabled, I get a 1,148 bytes binary, and if I enable size classes, then I get a 1,415 bytes binary (after wasm-gc and wasm-opt):

1148 ../target/wasm32-unknown-unknown/release/wee_alloc_example.gc.opt.wasm
1415 ../target/wasm32-unknown-unknown/release/wee_alloc_example.size_classes.gc.opt.wasm
sffc commented 5 years ago

I have the following lib.rs file:

use wasm_bindgen::prelude::*;
use wee_alloc::WeeAlloc;

// Use `wee_alloc` as the global allocator.
#[global_allocator]
static ALLOC: WeeAlloc = WeeAlloc::INIT;

#[wasm_bindgen]
extern "C" {
    fn alert(s: &str);
}

#[wasm_bindgen]
pub fn greet(name: &str) {
    alert(name);
}

When I compile that using wasm-pack and then inspect the output using twiggy, I get:

 Shallow Bytes │ Shallow % │ Item
───────────────┼───────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
          1353 ┊    25.55% ┊ "function names" subsection
          1065 ┊    20.11% ┊ data[0]
           580 ┊    10.95% ┊ <wee_alloc::WeeAlloc as core::alloc::GlobalAlloc>::alloc::h56b2fbb231097050
           574 ┊    10.84% ┊ wee_alloc::alloc_first_fit::hc3745372ad8f8d4e
           327 ┊     6.18% ┊ wee_alloc::WeeAlloc::dealloc_impl::{{closure}}::h92c7acfcf75e2e63
           252 ┊     4.76% ┊ <wee_alloc::size_classes::SizeClassAllocPolicy as wee_alloc::AllocPolicy>::new_cell_for_free_list::h6ef3252c1cc78ab3
           176 ┊     3.32% ┊ <wee_alloc::WeeAlloc as core::alloc::GlobalAlloc>::dealloc::haa7b6f21eac5aae6
           121 ┊     2.29% ┊ <wee_alloc::LargeAllocPolicy as wee_alloc::AllocPolicy>::new_cell_for_free_list::h8d68be1a53220a52
           113 ┊     2.13% ┊ custom section 'producers'
            80 ┊     1.51% ┊ data[1]
            57 ┊     1.08% ┊ __rg_realloc
            56 ┊     1.06% ┊ memcpy
            47 ┊     0.89% ┊ __wbindgen_malloc
            35 ┊     0.66% ┊ import wbg::__wbg_alert_e4f89deb17f7e8ca
            35 ┊     0.66% ┊ __wbindgen_realloc
            26 ┊     0.49% ┊ greet
            21 ┊     0.40% ┊ export "__wbindgen_realloc"
            21 ┊     0.40% ┊ __rust_realloc
            20 ┊     0.38% ┊ export "__wbindgen_malloc"
            17 ┊     0.32% ┊ __rust_alloc
           319 ┊     6.02% ┊ ... and 42 more.
          5295 ┊   100.00% ┊ Σ [62 Total Rows]

Rows 3-8 all appear to be wee_alloc, and it adds up to 2030 bytes. That includes size_classes, but still bigger than the 1.2 KB advertised in the README.

It's still much smaller than the default allocator though.

frehberg commented 5 years ago

Probably this ticket can be closed now. The size was related to a bug in Rust-lang, as rust kept dependencies to both, wee-alloc and dlmalloc. It was caused by some hard coded function name for an intrinsic in rust-lang, keeping a dependency to dlmalloc. This caused the Wee-alloc based binary to be even larger than the pure dlmalloc binary.

sffc commented 5 years ago

When building with opt-level = "s" and then running through wasm-opt -Os, the size gets smaller. It's hard to tell which symbols are which in the wasm-opt output, but even just enabling opt-level = "s" brings the payload down to 1534 bytes. So I guess I just wasn't using opt-level = "s" earlier.