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

Significant binary size increase between rc10 -> rc92 #2589

Open
cpuguy83 opened this issue Sep 15, 2020 · 13 comments
Open

Significant binary size increase between rc10 -> rc92 #2589

cpuguy83 opened this issue Sep 15, 2020 · 13 comments

Comments

@cpuguy83
Copy link
Contributor

cpuguy83 commented Sep 15, 2020

Running some tests between rc10 and rc92 I'm finding the binary size has increased significantly between the two versions.

version dynamic static Diff Bytes
1.0.0-rc10 13MB (12912880 B) 9.2 MB (9596744 B) 0 (baseline)
1.0.0-rc90 13MB (12912880 B) 9.2 MB (9596744 B) 0 / 0
1.0.0-rc91 16MB (16086704 B) 12 MB (11637664 B) +3,173,824 / +2,040,920
1.0.0-rc92 18MB (18293008 B) 13 MB (13112072 B) +2,206,304 / +1,474,408

This is with BUILDTAGS='seccomp apparmor selinux' in all cases.
Compiled with go1.13.15.

The reason I'm investigating this is because we've had a report of users having to increase their memory limits after updating versions.
I have not yet determined what the difference in actual memory consumption is between versions.
If you have an idea on how to instrument this, let me know.

@thaJeztah
Copy link
Member

@kolyshkin

@mrunalp
Copy link
Contributor

mrunalp commented Sep 15, 2020

I think at least selinux and apparmor should be exclusive.

@cpuguy83
Copy link
Contributor Author

Sure it doesn't make sense to include all, but these aren't new tags.

@tianon
Copy link
Member

tianon commented Sep 15, 2020

I don't think they reasonably can be exclusive, right? At runtime they would be, but a given binary will end up needing support for both compiled in the same binary because the kernel is a runtime choice (for example, Debian / Ubuntu are in the AppArmor camp but can be ran with SELinux instead by swapping the kernel).

There are also cases like static binaries that are expected to work regardless of the host kernel's configuration.

@tianon
Copy link
Member

tianon commented Sep 15, 2020

I'm not sure golang/go#6853 is the actual cause here (since you're likely compiling all versions against the same Go 1.13 you referenced), but I think it's worth noting/linking anyhow.

@cyphar
Copy link
Member

cyphar commented Sep 16, 2020

I noticed that we're missing -s from -ldflags -- what happens to the sizes if you do that?

I think at least selinux and apparmor should be exclusive.

No, you should build with both unless you're sure it will only ever be used on one distribution with one configuration. We do checks at runtime anyway... (ah, @tianon already said that.)

I have not yet determined what the difference in actual memory consumption is between versions. If you have an idea on how to instrument this, let me know.

Depending on the configuration, runc will make a copy of the binary into a memfd -- meaning that an increase in binary size results in increased memory usage. However, these days runc tries to do a read-only bind-mount first -- which shouldn't increase memory usage...

@kolyshkin
Copy link
Contributor

kolyshkin commented Nov 20, 2020

Did some measurements too, with make BUILDTAGS=seccomp and same golang 1.14.10 (except for the last line where i used go 1.15.4). Those are dynamic binaries.

[kir@kir-rhat runc]$ size runc-* | column --table
text     data     bss     dec       hex     filename
5805435  3433092  190640  9429167   8fe0af  runc-rc90
7382557  4222527  191664  11796748  b4010c  runc-rc91
8369589  4845690  195216  13410495  cca0bf  runc-rc92
8712333  5039659  195248  13947240  d4d168  runc-rc93pre
7673677  3935004  221264  11829945  b482b9  runc-rc93pre-go115

So, for one thing, using go 1.15 helps (and I heard that go 1.16 will be even better).

I guess I'll compile each commit to find out which ones to blame.

@kolyshkin
Copy link
Contributor

Found two steps between rc90 and rc92:

5547427  2804452  216688  8568567   82bef7  runc-v1.0.0-rc90-107-gf1eea905
6273675  3159528  217136  9650339   9340a3  runc-v1.0.0-rc90-110-g8df45c89
...
6436397  3247128  217712  9901237   9714b5  runc-v1.0.0-rc91-48-g67169a9d
7345981  3770500  221232  11337713  acfff1  runc-v1.0.0-rc91-50-g97b02cf9

@kolyshkin
Copy link
Contributor

5547427  2804452  216688  8568567   82bef7  runc-v1.0.0-rc90-107-gf1eea905
6273675  3159528  217136  9650339   9340a3  runc-v1.0.0-rc90-110-g8df45c89

This one is #2268 (update vendor)

6436397  3247128  217712  9901237   9714b5  runc-v1.0.0-rc91-48-g67169a9d
7345981  3770500  221232  11337713  acfff1  runc-v1.0.0-rc91-50-g97b02cf9

This one is #2531 (update go.mod)

So, it is third-party packages that we use. I guess a smarter linker would help fight this.

It was the same before, e.g. for rc8:

5198803  2678050  216400  8093253  7b7e45  runc-v1.0.0-rc8-68-g0fd4342a
5314483  2761561  216464  8292508  7e889c  runc-v1.0.0-rc8-79-ga6606a7a

This is #2029 ("Update dependencies")

And the only non-deps one which resulted is a slight but visible increase is:

5321235  2765345  216464  8303044  7eb1c4  runc-v1.0.0-rc9-24-ge57a7740
5453955  2840323  216688  8510966  81ddf6  runc-v1.0.0-rc9-26-gb133feae

which is #2145 ("cgroup2: port over eBPF device controller from crun")

@kolyshkin
Copy link
Contributor

Since rc92 up to current HEAD, this was the peak:

7406581  3805235  221264  11433080  ae7478  runc-v1.0.0-rc92-238-gfb59e6f7
7673549  3934948  221264  11829761  b48201  runc-v1.0.0-rc92-240-g30233a7a

#2675 ("update vendor")

@kolyshkin
Copy link
Contributor

What I did was run something like this:

FROM=origin/master
TO=v1.0.0-rc90
OUT=./sz2/

rm -rf $OUT/
mkdir $OUT
git checkout $FROM

while :; do
        # v1.0.0-rc90-467-g1b94395c
        VER=$(git describe --tags HEAD)
        echo $VER
        if [ "$VER" == "$TO"* ]; then
                echo DONE DONE DONE
                exit 0
        fi
        time make BUILDTAGS="seccomp" GO=go1.15.4 runc
        cp runc $OUT/runc-$VER
        git reset --hard HEAD~1
done

and then something like this

cd sz2
ls -c -1 runc-v1.0.0-rc92-* | xargs size | column --table

and just looked at the numbers in the first and second columns (text and data).

@kolyshkin
Copy link
Contributor

Just got an idea -- we can have a job to compare before/after binary sizes for each PR.

@thaJeztah
Copy link
Member

@kolyshkin this article might be interesting for you https://medium.com/@jondot/a-story-of-a-fat-go-binary-20edc6549b97

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

6 participants