Live data from Hacker News

My Go executable files are still getting larger

cockroachlabs.com

141–150 of 174 posts

Re: My Go executable files are still getting larger

#141
post #93

Earlier quoted context omitted.

You can see the true size of the Go pclntab in ELF binaries using "readelf -S" and in Mac binaries using "otool -l". Its not zero. One thing that did change from Go 1.15 to Go 1.16 is that we broke up the pclntab into a few different pieces. Again, it's all in the section headers. But the pieces are not in the actual binary's symbol table anymore, because they don't need to be. And since the format is different, we w…

> OK, the pclntab is large. Why is it large? What are the specific things in it that are large? Is it reasonably easy to attribute individual entries in pclntab to specific symbols? If so I'd love to add this capability to https://github.com/google/bloaty which already tries to do per-symbol analysis of many other sections (eh_frame, rela.dyn, etc).

It's reasonably easy for a specific Go release, but the details can and often do change from release to release. At some point we may write a more detailed, general-purpose binary size analysis tool that could dump JSON for bloaty to import, but today that tool does not exist.

Re: My Go executable files are still getting larger

#142
post #49

Earlier quoted context omitted.

Go uses DWARF.

Not for unwinding or line programs.

Go includes support for introspection. If Go used DWARF for introspection, and someone stripped DWARF, their code would break. That's not something that should happen with stripping. As such, the Go authors have made the tradeoff to have two "copies" of the data.

Re: My Go executable files are still getting larger

#143
post #34

> starting in Go 1.16, the pclntab is not present any more, and instead is re-computed from other data in the executable file. Does anyone have a source for this? As it still appears to be there - Go 1.15 https://i.imgur.com/3YlZGOk.png - Go 1.16 https://i.imgur.com/gGYsj32.png

No source needed -- you're right. The author's looking in the symbol table, and in 1.16 the Go linker set the size of runtime.pclntab to 0. If the OP used nm to look at their binary, they'd have seen that pclntab is still there. They author has apparently revised their article to address some of this (yet still draw some incorrect conclusions).

(This is derived from Russ' discussion above.)

Re: My Go executable files are still getting larger

#144

I always wonder if this is the flip side of the fast compilation? It would be nice to be able to decide on those trade-offs ourselves. I mostly write web servers in Go, which (as the article says) are executed rarely, so init time really doesn't matter to me. But I've been looking at writing some desktop apps in Go, and then init time will matter.

No. The two are mostly orthogonal. Sure, you can take a longer time to compile small binaries, but that's not what Go does. OP is talking about internal data structures Go uses for introspection and GC. The amount of time time spent compiling would have a marginal effect on the size of those structures.

Re: My Go executable files are still getting larger

#145
After looking into the size of the CockroachDB binary, the magnitude of the plank in the author's eye becomes clear. This iceberg is ridiculously bloated. Much of the space is coming from the static data of geographic projections that, I assume, basically nobody needs. This includes a single init function that is 1.4MB of machine code from 6MB of auto-generated source code. Then there's the entire AWS SDK, with a static definition of every service AWS offers, by name, and in what regions, by name. Nevermind the Azure SDK. There are three implementations of protocol buffers in here: gogo in Go and Google's in both Go and C++. There are at least four SQL parsers in here, including vitess's and another one for crdb in Go.

Last but by no means least there are in total 13MB of autogenerated functions of the colexec package, each of which is over 100KB long, which are autogenerated and share virtually all of their code. These are an obscene waste of code space and undoubtedly de-deuplicating this code would not just reduce code size but also speed up the program, due to icache trashing.

Re: My Go executable files are still getting larger

#146
post #52

It's time for debug info like this to be sent to "onlinesymbolserver.com", encrypted with a hash of the binary. Then, whenever a debugger connects to a binary, it can simply download the symbols as required. And for the 99.9% who don't need debug info, it isn't needlessly shipped. Microsoft invented this in the 90's...

I don't think this information in Go is used for debugging alone. It's also used by mallocgc and other parts of the runtime. This is why you will see "gentraceback" in the profiles of busy Go servers. It's not because your program is printing a lot of stack traces, it's because stack walking is a core part of the GC, and because some logic in the runtime refers to the names of functions to branch around special cases…

I assume those bits of runtime could be modified to have other special markers on the functions they need to special case...

Re: My Go executable files are still getting larger

#147
post #79

Earlier quoted context omitted.

Here is a question: imagine you could double performance of cockroa hDB by making the executable 2000MB - every db admin would make that choice

This is effectively what is happening btw; the crdb binary went from 80MB to 200MB in the same time it took to make it twice as fast. The % growth in size is not a problem on its own; it's more the % size attributed to the program vs. the % size attributed to unclear purposes, that's a problem.

What's the use case where a 200MB binary size is a problem?

Re: My Go executable files are still getting larger

#148
post #147
post #79

Earlier quoted context omitted.

This is effectively what is happening btw; the crdb binary went from 80MB to 200MB in the same time it took to make it twice as fast. The % growth in size is not a problem on its own; it's more the % size attributed to the program vs. the % size attributed to unclear purposes, that's a problem.

What's the use case where a 200MB binary size is a problem?

The use case where said binary is shipped to GCE instances hundreds/thousands times per day, for stress testing and unit testing of cockroachdb.

Re: My Go executable files are still getting larger

#149
post #136
post #131

Earlier quoted context omitted.

In env without swap, the binary size should/might block relative amount of ram. Might it be possible to stream binaries or to detect junks which could be unloaded like an json parser which is only needed when reading json

Without swap, you mean without virtual memory or without a swap partition/file? Because even without a swap partition/file, the whole executable will not block physical memory, but will page in/out as needed. And whole sections of it will never be loaded at all.

Without swap. You have to disable it for k8s

Re: My Go executable files are still getting larger

#150
post #52

Earlier quoted context omitted.

I don't think this information in Go is used for debugging alone. It's also used by mallocgc and other parts of the runtime. This is why you will see "gentraceback" in the profiles of busy Go servers. It's not because your program is printing a lot of stack traces, it's because stack walking is a core part of the GC, and because some logic in the runtime refers to the names of functions to branch around special cases…

I assume those bits of runtime could be modified to have other special markers on the functions they need to special case...

Yeah, that a function's name begins with "runtime." is 1 bit of information at most. But now we're talking about the optimal representation, not whether this information should exist.
Post reply on HN