Why are gccgo binaries smaller (among other differences?)

I experimented with gc and gccgo, and I came across some odd behavior.

Using the program Once I wrote to test some theorem, I got the following results: (I deleted unnecessary information for readability)

$ time go build -compiler gc -o checkprog_gc checkprog.go (x 3) go build <...> 0.13s user 0.02s system 100% cpu 0.149 total go build <...> 0.13s user 0.01s system 99% cpu 0.148 total go build <...> 0.14s user 0.03s system 100% cpu 0.162 total --> average: 0.13s user 0.02s system 100% cpu 0.153 total $ time go build -compiler gccgo -o checkprog_gccgo checkprog.go (x 3) go build <...> 0.10s user 0.03s system 96% cpu 0.135 total go build <...> 0.12s user 0.01s system 96% cpu 0.131 total go build <...> 0.10s user 0.01s system 92% cpu 0.123 total --> average: 0.11s user 0.02s system 95% cpu 0.130 total $ strip -s -o checkprog_gc_stripped checkprog_gc $ strip -s -o checkprog_gccgo_stripped checkprog_gccgo $ ls -l 1834504 checkprog_gc* 1336992 checkprog_gc_stripped* 35072 checkprog_gccgo* 24192 checkprog_gccgo_stripped* $ time ./checkprog_gc ./checkprog_gc 6.68s user 0.01s system 100% cpu 6.674 total ./checkprog_gc 6.75s user 0.01s system 100% cpu 6.741 total ./checkprog_gc 6.66s user 0.00s system 100% cpu 6.643 total --> average: 6.70s user 0.01s system 100% cpu 6.686 total $ time ./checkprog_gccgo ./checkprog_gccgo 10.95s user 0.02s system 100% cpu 10.949 total ./checkprog_gccgo 10.98s user 0.01s system 100% cpu 10.964 total ./checkprog_gccgo 10.94s user 0.01s system 100% cpu 10.929 total --> average 10.96s user 0.01s system 100% cpu 10.947 total 

I see the following patterns:

  • Binaries built with gccgo are much smaller (and deleting does not help change this difference).
  • Binaries created with gc run faster
  • Building with gccgo takes longer than using gc

I also tested some other go programs (although not as widely), and they all exhibit the same behavior.

This seems to contradict what this answer reads:

In short: gccgo: more optimization, more processors.

I would think that more optimization means faster binaries, while it takes more time to compile ...

What is the reason for these three patterns?

+5
source share
2 answers

There are a lot of differences - Bradfitz talked about some of them in a May conversation in 2014 :

  • gccgo can generate a binary file that is dynamically linked in libgo , which makes the output smaller, but means that the corresponding library will be installed on the target machine. Go binaries without cgo do not have this requirement.
  • gccgo does lower level optimizations because it can use the code generator and gcc optimizer. After writing some data compression code, gccgo ran it noticeably faster than gc . The same optimizations make the compiler slower: it does more work.
  • gccgo supports the target processors that gcc does, so this is the only way to access some architectures such as SPARC, ARMv8 (64-bit), or POWER. (Canonical uses it to compile the Juju service orchestration tool for arm64 and ppc64.)
  • gccgo and gc supported by ARMv7 (32-bit), but, according to bradfitz, gc does not generate the most efficient ARM code.
  • There are certain optimizations only gc .
    • A big escape analysis , in which the compiler determines that some variables will never "escape" from the function in which they are allocated, and therefore can be pushed onto the stack. (Thus, it is surprising that new(T) cannot allocate a heap if its return value does not disappear.) This reduces the frequency of garbage collection.
    • Another is that the .s assembler files in the standard library are linked only with gc , so some things, such as Intel CRC32C hardware, are not used by gccgo by default (you will need to provide an implementation specifically for gccgo).
  • gc first implements new language features and, as a rule, is a minor version of Go or precedes the latest version of gccgo .
+7
source

The size is different from what gc creates static binaries and gccgo links in libgo. This means that the code for the entire runtime (scheduler, garbage collector, cards, channels) is not in the final binary created by gccgo.

Compilation speed, of course, will favor gc. GC was built with compilation speed in mind. It also usually does less optimized code and has less work to do.

Now about why gc is still faster. The truth is that not one of them is always faster than the other. For example, try the md5 file and GCCGO will be an order of magnitude faster. Try to implement something with a lot of channels, and gc will surely win. You cannot always say in advance what will be successful. GC tends to be more efficient concurrency, and gccgo tends to be better at math. However, this is what you need to check on an individual basis. Test benchmarking is preferred over time.

+6
source

Source: https://habr.com/ru/post/1207427/


All Articles