I've been experimenting with gc and gccgo, and I've encountered some odd behaviour.
Using a program I once wrote to test some theorem, I got these results: (I removed unnecessary information for readablitity)
$ 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 can see the following patterns:
- Binaries built with
gccgo
are radically smaller in size (and stripping doesn't help to change this difference) - Binaries built with
gc
are faster to execute - It takes a bit more time to build with
gccgo
than withgc
I also tested some other go programs (while not that extensively) and all of them exhibit the same behavior.
This seems to contradict what this answer states:
In short: gccgo: more optimization, more processors.
I'd think that more optimization means faster binaries, while needing more time to compile...
What's the reason these three patterns?
There are a bunch of differences--bradfitz talked about some of them in a May 2014 talk:
gccgo
can produce a binary that dynamically links inlibgo
, which makes the output smaller but means the relevant library to be installed on the target machine. Go binaries withoutcgo
don't have that requirement.gccgo
does more low-level optimizations 'cause it can usegcc
's code generator and optimizer. Writing some data-compression code, gccgo ran it noticeably faster thangc
. Those same optimizations make the compiler slower: it's doing more work.gccgo
supports the target processors thatgcc
does, so it's the only way to get on some architectures like SPARC, ARMv8 (64-bit) or POWER. (Canonical uses it to compile their Juju service orchestration tool for arm64 and ppc64.)gccgo
andgc
both support ARMv7 (32-bit), but according to bradfitz's talkgc
does not generate the most efficient ARM code.gc
has.new(T)
may not heap-allocate if its return value doesn't escape.) This reduces how often garbage collection needs to run..s
assembler files in the standard library are only linked in bygc
, so some stuff like Intel hardware CRC32C isn't used bygccgo
by default (you'd have to provide an implementation specifically for gccgo).gc
implements new language features first and has generally been a minor Go version or two ahead of the latestgccgo
.