Repository: rust
Issue: WebAssembly size regression between 1.40 and 1.41
Labels: P-medium,regression-from-stable-to-stable,O-wasm,C-bug,I-heavy

While upgrading the build configs and compiler versions in squoosh.app in [`c5c520a` (#777)](https://github.com/GoogleChromeLabs/squoosh/pull/777/commits/c5c520a71d94d0517e361da36ea2340dc6e5bdf2), we (cc @jakearchibald @surma) have noticed a significant size increase in one of the image codecs - HQX.

Normally we ignore fluctuations between versions, as they are expected, but in this particular case the resulting file grew from 219KB to 381KB - by 162KB or 74%.

For now we reverted that codec to the Rust version it was initially built with - 1.39

Meanwhile, I've started investigating and going through Rust versions starting from 1.39 to the latest 1.45 to find the one that introduced the regression. This process is a bit slow, but in the end I've ended up with the following pinpoint changes, file sizes & included `wasm-objdump -h` logs:

<details>

```
1.40:
(before wasm-opt)
-a---           30-Jul-20    15:07         682058 squooshhqx.wasm
     Type start=0x0000000a end=0x00000075 (size=0x0000006b) count: 16
   Import start=0x00000078 end=0x0000012a (size=0x000000b2) count: 3
 Function start=0x0000012c end=0x00000191 (size=0x00000065) count: 100
    Table start=0x00000193 end=0x00000198 (size=0x00000005) count: 1
   Memory start=0x0000019a end=0x0000019d (size=0x00000003) count: 1
   Global start=0x0000019f end=0x000001b8 (size=0x00000019) count: 3
   Export start=0x000001bb end=0x0000035c (size=0x000001a1) count: 16
     Elem start=0x0000035e end=0x0000037e (size=0x00000020) count: 1
     Code start=0x00000382 end=0x0005569e (size=0x0005531c) count: 100
     Data start=0x000556a1 end=0x000586b8 (size=0x00003017) count: 3
   Custom start=0x000586bc end=0x0006cbea (size=0x0001452e) ".debug_info"
   Custom start=0x0006cbec end=0x0006cbfd (size=0x00000011) ".debug_macinfo"
   Custom start=0x0006cc01 end=0x00073e43 (size=0x00007242) ".debug_pubtypes"
   Custom start=0x00073e47 end=0x0007874d (size=0x00004906) ".debug_ranges"
   Custom start=0x00078750 end=0x00078f98 (size=0x00000848) ".debug_abbrev"
   Custom start=0x00078f9b end=0x0007918f (size=0x000001f4) "__wasm_bindgen_unstable"
   Custom start=0x00079193 end=0x00088b44 (size=0x0000f9b1) ".debug_line"
   Custom start=0x00088b48 end=0x000a09d6 (size=0x00017e8e) ".debug_str"
   Custom start=0x000a09da end=0x000a4fb4 (size=0x000045da) ".debug_pubnames"
   Custom start=0x000a4fb7 end=0x000a67fb (size=0x00001844) "name"
   Custom start=0x000a67fd end=0x000a684a (size=0x0000004d) "producers"
(after wasm-opt)
-a---           30-Jul-20    15:15         220121 squooshhqx_bg.wasm
     Type start=0x0000000a end=0x00000075 (size=0x0000006b) count: 16
 Function start=0x00000077 end=0x000000c2 (size=0x0000004b) count: 74
    Table start=0x000000c4 end=0x000000c9 (size=0x00000005) count: 1
   Memory start=0x000000cb end=0x000000ce (size=0x00000003) count: 1
   Global start=0x000000d0 end=0x000000d9 (size=0x00000009) count: 1
   Export start=0x000000db end=0x00000114 (size=0x00000039) count: 4
     Elem start=0x00000116 end=0x00000136 (size=0x00000020) count: 1
     Code start=0x0000013a end=0x00033193 (size=0x00033059) count: 74
     Data start=0x00033196 end=0x00035b5c (size=0x000029c6) count: 44
   Custom start=0x00035b5e end=0x00035bd9 (size=0x0000007b) "producers"

1.41+
(before wasm-opt)
-a---           30-Jul-20    15:23         777633 squooshhqx.wasm
     Type start=0x0000000a end=0x00000075 (size=0x0000006b) count: 16
   Import start=0x00000078 end=0x0000012a (size=0x000000b2) count: 3
 Function start=0x0000012c end=0x00000190 (size=0x00000064) count: 99
    Table start=0x00000192 end=0x00000197 (size=0x00000005) count: 1
   Memory start=0x00000199 end=0x0000019c (size=0x00000003) count: 1
   Global start=0x0000019e end=0x000001b7 (size=0x00000019) count: 3
   Export start=0x000001ba end=0x0000035b (size=0x000001a1) count: 16
     Elem start=0x0000035d end=0x0000037d (size=0x00000020) count: 1
     Code start=0x00000381 end=0x00055365 (size=0x00054fe4) count: 99
     Data start=0x00055369 end=0x0006e245 (size=0x00018edc) count: 3
   Custom start=0x0006e249 end=0x0008284e (size=0x00014605) ".debug_info"
   Custom start=0x00082850 end=0x00082861 (size=0x00000011) ".debug_macinfo"
   Custom start=0x00082865 end=0x00089b4f (size=0x000072ea) ".debug_pubtypes"
   Custom start=0x00089b53 end=0x0008e531 (size=0x000049de) ".debug_ranges"
   Custom start=0x0008e534 end=0x0008ef13 (size=0x000009df) ".debug_aranges"
   Custom start=0x0008ef16 end=0x0008f69d (size=0x00000787) ".debug_abbrev"
   Custom start=0x0008f6a0 end=0x0008f894 (size=0x000001f4) "__wasm_bindgen_unstable"
   Custom start=0x0008f898 end=0x0009f3f5 (size=0x0000fb5d) ".debug_line"
   Custom start=0x0009f3f9 end=0x000b7b31 (size=0x00018738) ".debug_str"
   Custom start=0x000b7b35 end=0x000bc543 (size=0x00004a0e) ".debug_pubnames"
   Custom start=0x000bc546 end=0x000bdd52 (size=0x0000180c) "name"
   Custom start=0x000bdd54 end=0x000bdda1 (size=0x0000004d) "producers"
(after wasm-opt)
-a---           30-Jul-20    15:24         391443 squooshhqx_bg.wasm
     Type start=0x0000000a end=0x00000075 (size=0x0000006b) count: 16
 Function start=0x00000077 end=0x000000c2 (size=0x0000004b) count: 74
    Table start=0x000000c4 end=0x000000c9 (size=0x00000005) count: 1
   Memory start=0x000000cb end=0x000000ce (size=0x00000003) count: 1
   Global start=0x000000d0 end=0x000000d9 (size=0x00000009) count: 1
   Export start=0x000000db end=0x00000114 (size=0x00000039) count: 4
     Elem start=0x00000116 end=0x00000136 (size=0x00000020) count: 1
     Code start=0x0000013a end=0x00047009 (size=0x00046ecf) count: 74
     Data start=0x0004700d end=0x0005f896 (size=0x00018889) count: 44
   Custom start=0x0005f898 end=0x0005f913 (size=0x0000007b) "producers"

1.44+:
(before wasm-opt)
-a---           30-Jul-20    15:49         547075 squooshhqx.wasm
     Type start=0x0000000a end=0x0000007d (size=0x00000073) count: 17
   Import start=0x00000080 end=0x00000132 (size=0x000000b2) count: 3
 Function start=0x00000134 end=0x00000198 (size=0x00000064) count: 99
    Table start=0x0000019a end=0x0000019f (size=0x00000005) count: 1
   Memory start=0x000001a1 end=0x000001a4 (size=0x00000003) count: 1
   Global start=0x000001a6 end=0x000001bf (size=0x00000019) count: 3
   Export start=0x000001c2 end=0x00000363 (size=0x000001a1) count: 16
     Elem start=0x00000365 end=0x00000385 (size=0x00000020) count: 1
     Code start=0x00000389 end=0x00055466 (size=0x000550dd) count: 99
     Data start=0x0005546a end=0x0006da2a (size=0x000185c0) count: 3
   Custom start=0x0006da2e end=0x00072084 (size=0x00004656) ".debug_info"
   Custom start=0x00072086 end=0x00072098 (size=0x00000012) ".debug_macinfo"
   Custom start=0x0007209a end=0x00072116 (size=0x0000007c) ".debug_pubtypes"
   Custom start=0x00072119 end=0x000741df (size=0x000020c6) ".debug_ranges"
   Custom start=0x000741e2 end=0x00074469 (size=0x00000287) ".debug_aranges"
   Custom start=0x0007446c end=0x0007483b (size=0x000003cf) ".debug_abbrev"
   Custom start=0x0007483e end=0x00074a32 (size=0x000001f4) "__wasm_bindgen_unstable"
   Custom start=0x00074a35 end=0x00077f18 (size=0x000034e3) ".debug_line"
   Custom start=0x00077f1c end=0x000810cf (size=0x000091b3) ".debug_str"
   Custom start=0x000810d2 end=0x00083fd7 (size=0x00002f05) ".debug_pubnames"
   Custom start=0x00083fda end=0x000858b4 (size=0x000018da) "name"
   Custom start=0x000858b6 end=0x00085903 (size=0x0000004d) "producers"
(after wasm-opt)
-a---           30-Jul-20    15:50         389871 squooshhqx_bg.wasm
     Type start=0x0000000a end=0x0000007d (size=0x00000073) count: 17
 Function start=0x0000007f end=0x000000cb (size=0x0000004c) count: 75
    Table start=0x000000cd end=0x000000d2 (size=0x00000005) count: 1
   Memory start=0x000000d4 end=0x000000d7 (size=0x00000003) count: 1
   Global start=0x000000d9 end=0x000000e2 (size=0x00000009) count: 1
   Export start=0x000000e4 end=0x0000011d (size=0x00000039) count: 4
     Elem start=0x0000011f end=0x0000013f (size=0x00000020) count: 1
     Code start=0x00000143 end=0x00047111 (size=0x00046fce) count: 75
     Data start=0x00047115 end=0x0005f272 (size=0x0001815d) count: 2
   Custom start=0x0005f274 end=0x0005f2ef (size=0x0000007b) "producers"
```
</details>

The TL;DR of our build config is `opt-level = "s"` and `lto = true`, and then using `wasm-pack` to also optimise for size & strip debug info. In order to build this particular codec, you need to go to the [`codecs/hqx`](https://github.com/GoogleChromeLabs/squoosh/tree/dev/codecs/hqx) folder and run `npm run build` inside. It will take care of downloading the latest Rust Docker image and then building the codec with `wasm-pack build`. Alternatively, you can use `wasm-pack` or even `cargo build` directly in the folder, assuming you've set correct Rust versions to reproduce the issue.

The logs above can be a bit verbose, and raw file sizes reflect changes also in size of debug sections and such, which are not very interesting in this context. Where I use `1.41+` or `1.44+`, it means that following versions exhibit pretty much same sizes par the normal fluctuation, and only versions with significant increase are kept.

To make changes a bit easier to analyse, I've split out only code and data section sizes in the following spreadsheet: https://docs.google.com/spreadsheets/d/1ToE7Th7fp_VuQwws45ZgwBV1Pg09U061na0yFDaLwpk/edit?usp=sharing

Here is the graph showing the code and data increase between those version groups:

![Chart](https://user-images.githubusercontent.com/557590/88943989-12bb4400-d284-11ea-99af-65bcf8369e39.png)

As you can see from raw logs, 1.44+ produces smaller raw file but it has comparable code and data sections sizes, and remains at the 1.41+ level after wasm-opt, which suggests the decrease is mainly around debug info, and not very interesting to us.

However, the change between 1.40 and 1.41 is more radical: the data section has increased from 12KB to 100KB (by 88KB or 8.3x of the original), and, while the code section almost hasn't changed, it can't be optimised by wasm-opt as well anymore.

I don't have enough insight and didn't dig deeper into Wasm, but suspect this is not a separate issue, but related to the data section increase - probably some data sections kept by Rust / LLVM, consequently, don't allow wasm-opt to DCE out some unused code that could be removed before.

Would appreciate if someone on the Rust side could take over further investigation and happy to help out with build instructions to reproduce. Although we use Dockerfiles, so it should be fairly straightforward to build.

Thanks!