Skip to content

Binary size impact of enabling -Zshare-generics for opt-level=z #142164

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

Open
Noratrieb opened this issue Jun 7, 2025 · 1 comment
Open

Binary size impact of enabling -Zshare-generics for opt-level=z #142164

Noratrieb opened this issue Jun 7, 2025 · 1 comment
Labels
C-discussion Category: Discussion or questions that doesn't represent real issues. E-needs-investigation Call for partcipation: This issues needs some investigation to determine current status I-heavy Issue: Problems and improvements with respect to binary size of generated code. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@Noratrieb
Copy link
Member

Noratrieb commented Jun 7, 2025

opt-level=z and opt-level=s implicitly enable -Zshare-generics. While this can have positive binary size impacts, it can also have negative binary size impacts because it reduces LLVMs ability to inline functions.

I have done some analysis on a bunch of projects, comparing the output from size for different opt levels.

Script

#!/usr/bin/env bash

set -euxo pipefail

bins=$(cargo metadata --format-version 1 | jq '.packages.[].targets.[] | select(.crate_types == ["bin"]) | select(.src_path | contains("index.crates.io") | not) | .name' -r)

echo checking "$bins"

projdir=$(basename "$(realpath .)")

truncate -s 0 results.csv

build() {
  type="$1"
  rustflags="$2"

  wrapper=$(mktemp)
  {
    echo '#!/usr/bin/env bash'
    echo 'r=$1'
    echo "shift"
    echo exec '$r' '"$@"' "$rustflags" 
  } > "$wrapper"

  chmod +x "$wrapper"

  echo "meow"
  cat "$wrapper"

  cargo clean
  bins=$(RUSTC_WRAPPER="$wrapper" cargo build --release --message-format=json-render-diagnostics | jq 'select(.reason == "compiler-artifact") | select(.executable != null) | .executable' -r)

  IFS=$'\n'
  for bin in $bins; do
    echo "$bin"
    s=$(size "$bin" | python3 -c 'import sys;x=sys.stdin.read();print(x.split("\n")[1].split()[0])')

    echo "$projdir,$(basename "$bin"),$type,$s" >> results.csv
  done

  rm "$wrapper"
}

build "2" "-Copt-level=2"
build "3" "-Copt-level=3"
build "s" "-Copt-level=s"
build "s-no-share" "-Copt-level=s -Zshare-generics=false"
build "z" "-Copt-level=z"
build "z-no-share" "-Copt-level=z -Zshare-generics=false"

I got the following results:

Results CSV

project,binary,opt-level,text size
rustc-perf,bootstrap-rustc,2,401390
rustc-perf,bootstrap-rustc,3,401518
rustc-perf,bootstrap-rustc,s,401454
rustc-perf,bootstrap-rustc,s-no-share,400286
rustc-perf,bootstrap-rustc,z,402450
rustc-perf,bootstrap-rustc,z-no-share,401562
nextest,build-seed-archive,2,928761
nextest,build-seed-archive,3,928241
nextest,build-seed-archive,s,906783
nextest,build-seed-archive,s-no-share,877006
nextest,build-seed-archive,z,939734
nextest,build-seed-archive,z-no-share,896072
cargo,cargo,2,26769308
cargo,cargo,3,27035766
cargo,cargo,s,23441682
cargo,cargo,s-no-share,22941899
cargo,cargo,z,23003221
cargo,cargo,z-no-share,21949429
nextest,cargo-nextest,2,15327059
nextest,cargo-nextest,3,15331428
nextest,cargo-nextest,s,13378951
nextest,cargo-nextest,s-no-share,13151176
nextest,cargo-nextest,z,13347017
nextest,cargo-nextest,z-no-share,12840776
nextest,cargo-nextest-dup,2,15327071
nextest,cargo-nextest-dup,3,15331440
nextest,cargo-nextest-dup,s,13378951
nextest,cargo-nextest-dup,s-no-share,13151176
nextest,cargo-nextest-dup,z,13347017
nextest,cargo-nextest-dup,z-no-share,12840776
cluelessh,cluelessh,2,3639610
cluelessh,cluelessh,3,3637618
cluelessh,cluelessh,s,3230404
cluelessh,cluelessh,s-no-share,3137054
cluelessh,cluelessh,z,3298182
cluelessh,cluelessh,z-no-share,3160263
cluelessh,cluelessh-agentctl,2,3081768
cluelessh,cluelessh-agentctl,3,3090680
cluelessh,cluelessh-agentctl,s,2752168
cluelessh,cluelessh-agentctl,s-no-share,2668998
cluelessh,cluelessh-agentctl,z,2812587
cluelessh,cluelessh-agentctl,z-no-share,2692805
cluelessh,cluelessh-dos,2,3363901
cluelessh,cluelessh-dos,3,3374685
cluelessh,cluelessh-dos,s,3006511
cluelessh,cluelessh-dos,s-no-share,2909317
cluelessh,cluelessh-dos,z,3069389
cluelessh,cluelessh-dos,z-no-share,2936446
cluelessh,cluelessh-faked,2,3307574
cluelessh,cluelessh-faked,3,3300062
cluelessh,cluelessh-faked,s,2953214
cluelessh,cluelessh-faked,s-no-share,2889345
cluelessh,cluelessh-faked,z,3030640
cluelessh,cluelessh-faked,z-no-share,2939401
cluelessh,cluelessh-key,2,1138744
cluelessh,cluelessh-key,3,1156436
cluelessh,cluelessh-key,s,1031633
cluelessh,cluelessh-key,s-no-share,1003059
cluelessh,cluelessh-key,z,1028888
cluelessh,cluelessh-key,z-no-share,985054
cluelessh,cluelesshd,2,4675529
cluelessh,cluelesshd,3,4666229
cluelessh,cluelesshd,s,4138714
cluelessh,cluelesshd,s-no-share,3995755
cluelessh,cluelesshd,z,4208701
cluelessh,cluelesshd,z-no-share,4024121
cluelessh,cluelesshd-sftp-server,2,2481705
cluelessh,cluelesshd-sftp-server,3,2489701
cluelessh,cluelesshd-sftp-server,s,2244369
cluelessh,cluelesshd-sftp-server,s-no-share,2193279
cluelessh,cluelesshd-sftp-server,z,2304838
cluelessh,cluelesshd-sftp-server,z-no-share,2229436
rustc-perf,collector,2,11333776
rustc-perf,collector,3,11340184
rustc-perf,collector,s,10138920
rustc-perf,collector,s-no-share,9960872
rustc-perf,collector,z,10061628
rustc-perf,collector,z-no-share,9756252
rustc-perf,fetch-latest,2,3041314
rustc-perf,fetch-latest,3,3070746
rustc-perf,fetch-latest,s,2775574
rustc-perf,fetch-latest,s-no-share,2720170
rustc-perf,fetch-latest,z,2766783
rustc-perf,fetch-latest,z-no-share,2687495
hello-world,hello-world,2,344751
hello-world,hello-world,3,344751
hello-world,hello-world,s,344719
hello-world,hello-world,s-no-share,344719
hello-world,hello-world,z,344767
hello-world,hello-world,z-no-share,344767
rustc-perf,import-sqlite,2,7313831
rustc-perf,import-sqlite,3,7395099
rustc-perf,import-sqlite,s,6774471
rustc-perf,import-sqlite,s-no-share,6693379
rustc-perf,import-sqlite,z,6778407
rustc-perf,import-sqlite,z-no-share,6649119
nextest,internal-test,2,339532
nextest,internal-test,3,339532
nextest,internal-test,s,339500
nextest,internal-test,s-no-share,339500
nextest,internal-test,z,339540
nextest,internal-test,z-no-share,339540
Neotron-Pico-BIOS,neotron-pico-bios,2,69320
Neotron-Pico-BIOS,neotron-pico-bios,3,73996
Neotron-Pico-BIOS,neotron-pico-bios,s,52860
Neotron-Pico-BIOS,neotron-pico-bios,s-no-share,52840
Neotron-Pico-BIOS,neotron-pico-bios,z,51192
Neotron-Pico-BIOS,neotron-pico-bios,z-no-share,50960
nextest,passthrough,2,411770
nextest,passthrough,3,411294
nextest,passthrough,s,411125
nextest,passthrough,s-no-share,409746
nextest,passthrough,z,411123
nextest,passthrough,z-no-share,410024
rustc-perf,postgres-to-sqlite,2,7461386
rustc-perf,postgres-to-sqlite,3,7532230
rustc-perf,postgres-to-sqlite,s,6841686
rustc-perf,postgres-to-sqlite,s-no-share,6751134
rustc-perf,postgres-to-sqlite,z,6813466
rustc-perf,postgres-to-sqlite,z-no-share,6664510
ripgrep,rg,2,4378977
ripgrep,rg,3,4435131
ripgrep,rg,s,4013053
ripgrep,rg,s-no-share,3962587
ripgrep,rg,z,3993959
ripgrep,rg,z-no-share,3913056
rust-analyzer,rust-analyzer,2,36815675
rust-analyzer,rust-analyzer,3,36845571
rust-analyzer,rust-analyzer,s,29047888
rust-analyzer,rust-analyzer,s-no-share,30842033
rust-analyzer,rust-analyzer,z,27646232
rust-analyzer,rust-analyzer,z-no-share,28589921
rust-analyzer,rust-analyzer-proc-macro-srv,2,350694
rust-analyzer,rust-analyzer-proc-macro-srv,3,350690
rust-analyzer,rust-analyzer-proc-macro-srv,s,350690
rust-analyzer,rust-analyzer-proc-macro-srv,s-no-share,350550
rust-analyzer,rust-analyzer-proc-macro-srv,z,350610
rust-analyzer,rust-analyzer-proc-macro-srv,z-no-share,350490
rustc-perf,rustc-fake,2,455290
rustc-perf,rustc-fake,3,456474
rustc-perf,rustc-fake,s,452790
rustc-perf,rustc-fake,s-no-share,452150
rustc-perf,rustc-fake,z,453770
rustc-perf,rustc-fake,z-no-share,451770
nextest,rustc-shim,2,398876
nextest,rustc-shim,3,398928
nextest,rustc-shim,s,397635
nextest,rustc-shim,s-no-share,397828
nextest,rustc-shim,z,397343
nextest,rustc-shim,z-no-share,397944
rusty-clock,rusty-clock,2,49052
rusty-clock,rusty-clock,3,51764
rusty-clock,rusty-clock,s,37468
rusty-clock,rusty-clock,s-no-share,37664
rusty-clock,rusty-clock,z,35320
rusty-clock,rusty-clock,z-no-share,35476
rustc-perf,site,2,15569433
rustc-perf,site,3,15585737
rustc-perf,site,s,13880257
rustc-perf,site,s-no-share,13747097
rustc-perf,site,z,13614909
rustc-perf,site,z-no-share,13353497
rustc-perf,sqlite-to-postgres,2,7937442
rustc-perf,sqlite-to-postgres,3,8016754
rustc-perf,sqlite-to-postgres,s,7192830
rustc-perf,sqlite-to-postgres,s-no-share,7104766
rustc-perf,sqlite-to-postgres,z,7154074
rustc-perf,sqlite-to-postgres,z-no-share,6998258
rust-analyzer,xtask,2,1685422
rust-analyzer,xtask,3,1671190
rust-analyzer,xtask,s,1535085
rust-analyzer,xtask,s-no-share,1502505
rust-analyzer,xtask,z,1527938
rust-analyzer,xtask,z-no-share,1479014

Results Table
project binary opt-level text size
rustc-perf bootstrap-rustc 2 401390
rustc-perf bootstrap-rustc 3 401518
rustc-perf bootstrap-rustc s 401454
rustc-perf bootstrap-rustc s-no-share 400286
rustc-perf bootstrap-rustc z 402450
rustc-perf bootstrap-rustc z-no-share 401562
nextest build-seed-archive 2 928761
nextest build-seed-archive 3 928241
nextest build-seed-archive s 906783
nextest build-seed-archive s-no-share 877006
nextest build-seed-archive z 939734
nextest build-seed-archive z-no-share 896072
cargo cargo 2 26769308
cargo cargo 3 27035766
cargo cargo s 23441682
cargo cargo s-no-share 22941899
cargo cargo z 23003221
cargo cargo z-no-share 21949429
nextest cargo-nextest 2 15327059
nextest cargo-nextest 3 15331428
nextest cargo-nextest s 13378951
nextest cargo-nextest s-no-share 13151176
nextest cargo-nextest z 13347017
nextest cargo-nextest z-no-share 12840776
nextest cargo-nextest-dup 2 15327071
nextest cargo-nextest-dup 3 15331440
nextest cargo-nextest-dup s 13378951
nextest cargo-nextest-dup s-no-share 13151176
nextest cargo-nextest-dup z 13347017
nextest cargo-nextest-dup z-no-share 12840776
cluelessh cluelessh 2 3639610
cluelessh cluelessh 3 3637618
cluelessh cluelessh s 3230404
cluelessh cluelessh s-no-share 3137054
cluelessh cluelessh z 3298182
cluelessh cluelessh z-no-share 3160263
cluelessh cluelessh-agentctl 2 3081768
cluelessh cluelessh-agentctl 3 3090680
cluelessh cluelessh-agentctl s 2752168
cluelessh cluelessh-agentctl s-no-share 2668998
cluelessh cluelessh-agentctl z 2812587
cluelessh cluelessh-agentctl z-no-share 2692805
cluelessh cluelessh-dos 2 3363901
cluelessh cluelessh-dos 3 3374685
cluelessh cluelessh-dos s 3006511
cluelessh cluelessh-dos s-no-share 2909317
cluelessh cluelessh-dos z 3069389
cluelessh cluelessh-dos z-no-share 2936446
cluelessh cluelessh-faked 2 3307574
cluelessh cluelessh-faked 3 3300062
cluelessh cluelessh-faked s 2953214
cluelessh cluelessh-faked s-no-share 2889345
cluelessh cluelessh-faked z 3030640
cluelessh cluelessh-faked z-no-share 2939401
cluelessh cluelessh-key 2 1138744
cluelessh cluelessh-key 3 1156436
cluelessh cluelessh-key s 1031633
cluelessh cluelessh-key s-no-share 1003059
cluelessh cluelessh-key z 1028888
cluelessh cluelessh-key z-no-share 985054
cluelessh cluelesshd 2 4675529
cluelessh cluelesshd 3 4666229
cluelessh cluelesshd s 4138714
cluelessh cluelesshd s-no-share 3995755
cluelessh cluelesshd z 4208701
cluelessh cluelesshd z-no-share 4024121
cluelessh cluelesshd-sftp-server 2 2481705
cluelessh cluelesshd-sftp-server 3 2489701
cluelessh cluelesshd-sftp-server s 2244369
cluelessh cluelesshd-sftp-server s-no-share 2193279
cluelessh cluelesshd-sftp-server z 2304838
cluelessh cluelesshd-sftp-server z-no-share 2229436
rustc-perf collector 2 11333776
rustc-perf collector 3 11340184
rustc-perf collector s 10138920
rustc-perf collector s-no-share 9960872
rustc-perf collector z 10061628
rustc-perf collector z-no-share 9756252
rustc-perf fetch-latest 2 3041314
rustc-perf fetch-latest 3 3070746
rustc-perf fetch-latest s 2775574
rustc-perf fetch-latest s-no-share 2720170
rustc-perf fetch-latest z 2766783
rustc-perf fetch-latest z-no-share 2687495
hello-world hello-world 2 344751
hello-world hello-world 3 344751
hello-world hello-world s 344719
hello-world hello-world s-no-share 344719
hello-world hello-world z 344767
hello-world hello-world z-no-share 344767
rustc-perf import-sqlite 2 7313831
rustc-perf import-sqlite 3 7395099
rustc-perf import-sqlite s 6774471
rustc-perf import-sqlite s-no-share 6693379
rustc-perf import-sqlite z 6778407
rustc-perf import-sqlite z-no-share 6649119
nextest internal-test 2 339532
nextest internal-test 3 339532
nextest internal-test s 339500
nextest internal-test s-no-share 339500
nextest internal-test z 339540
nextest internal-test z-no-share 339540
Neotron-Pico-BIOS neotron-pico-bios 2 69320
Neotron-Pico-BIOS neotron-pico-bios 3 73996
Neotron-Pico-BIOS neotron-pico-bios s 52860
Neotron-Pico-BIOS neotron-pico-bios s-no-share 52840
Neotron-Pico-BIOS neotron-pico-bios z 51192
Neotron-Pico-BIOS neotron-pico-bios z-no-share 50960
nextest passthrough 2 411770
nextest passthrough 3 411294
nextest passthrough s 411125
nextest passthrough s-no-share 409746
nextest passthrough z 411123
nextest passthrough z-no-share 410024
rustc-perf postgres-to-sqlite 2 7461386
rustc-perf postgres-to-sqlite 3 7532230
rustc-perf postgres-to-sqlite s 6841686
rustc-perf postgres-to-sqlite s-no-share 6751134
rustc-perf postgres-to-sqlite z 6813466
rustc-perf postgres-to-sqlite z-no-share 6664510
ripgrep rg 2 4378977
ripgrep rg 3 4435131
ripgrep rg s 4013053
ripgrep rg s-no-share 3962587
ripgrep rg z 3993959
ripgrep rg z-no-share 3913056
rust-analyzer rust-analyzer 2 36815675
rust-analyzer rust-analyzer 3 36845571
rust-analyzer rust-analyzer s 29047888
rust-analyzer rust-analyzer s-no-share 30842033
rust-analyzer rust-analyzer z 27646232
rust-analyzer rust-analyzer z-no-share 28589921
rust-analyzer rust-analyzer-proc-macro-srv 2 350694
rust-analyzer rust-analyzer-proc-macro-srv 3 350690
rust-analyzer rust-analyzer-proc-macro-srv s 350690
rust-analyzer rust-analyzer-proc-macro-srv s-no-share 350550
rust-analyzer rust-analyzer-proc-macro-srv z 350610
rust-analyzer rust-analyzer-proc-macro-srv z-no-share 350490
rustc-perf rustc-fake 2 455290
rustc-perf rustc-fake 3 456474
rustc-perf rustc-fake s 452790
rustc-perf rustc-fake s-no-share 452150
rustc-perf rustc-fake z 453770
rustc-perf rustc-fake z-no-share 451770
nextest rustc-shim 2 398876
nextest rustc-shim 3 398928
nextest rustc-shim s 397635
nextest rustc-shim s-no-share 397828
nextest rustc-shim z 397343
nextest rustc-shim z-no-share 397944
rusty-clock rusty-clock 2 49052
rusty-clock rusty-clock 3 51764
rusty-clock rusty-clock s 37468
rusty-clock rusty-clock s-no-share 37664
rusty-clock rusty-clock z 35320
rusty-clock rusty-clock z-no-share 35476
rustc-perf site 2 15569433
rustc-perf site 3 15585737
rustc-perf site s 13880257
rustc-perf site s-no-share 13747097
rustc-perf site z 13614909
rustc-perf site z-no-share 13353497
rustc-perf sqlite-to-postgres 2 7937442
rustc-perf sqlite-to-postgres 3 8016754
rustc-perf sqlite-to-postgres s 7192830
rustc-perf sqlite-to-postgres s-no-share 7104766
rustc-perf sqlite-to-postgres z 7154074
rustc-perf sqlite-to-postgres z-no-share 6998258
rust-analyzer xtask 2 1685422
rust-analyzer xtask 3 1671190
rust-analyzer xtask s 1535085
rust-analyzer xtask s-no-share 1502505
rust-analyzer xtask z 1527938
rust-analyzer xtask z-no-share 1479014

It looks like -Zshare-generics is sometimes an improvement and sometimes a regression. It is not immediately clear to me whether enabling it as currently is the right tradeoff of whether it would make more sense to disable it by default.

@Noratrieb Noratrieb added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. I-heavy Issue: Problems and improvements with respect to binary size of generated code. E-needs-investigation Call for partcipation: This issues needs some investigation to determine current status labels Jun 7, 2025
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Jun 7, 2025
@Noratrieb Noratrieb removed the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Jun 7, 2025
@Noratrieb Noratrieb added the C-discussion Category: Discussion or questions that doesn't represent real issues. label Jun 7, 2025
rust-bors bot added a commit that referenced this issue Jun 7, 2025
Test binary size of share generics

cc #142164

r? ghost
@nikic
Copy link
Contributor

nikic commented Jun 7, 2025

See also #123610 for a possible way to get the best of both worlds.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-discussion Category: Discussion or questions that doesn't represent real issues. E-needs-investigation Call for partcipation: This issues needs some investigation to determine current status I-heavy Issue: Problems and improvements with respect to binary size of generated code. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

3 participants