Comments:"Go 1.1 performance improvements, part 2 | Dave Cheney"
URL:http://dave.cheney.net/2013/05/25/go-11-performance-improvements-part-2
This is the second in a three part series exploring the performance improvements in the recent Go 1.1 release.
In part 1 I explored the improvements on amd64
platforms, as well as general improvements available to all via runtime and compiler frontend improvements.
In this article I will focus on the performance of Go 1.1 on 386
machines. The results in this article are taken from linux-386-d5666bad617d-vs-e570c2daeaca.txt.
Go 1 benchmarks on linux/386
When it comes to performance, the 8g
compiler is at a disadvantage. The small number of general purpose registers available in the 386
programming model, and the weird restrictions on their use place a heavy burden on the compiler and optimiser. However that did not stop Rémy Oudompheng making several significant contributions to 8g
during the 1.1 cycle.
Firstly the odd 387
floating point model was deprecated (it’s still there if you are running very old hardware with the GO386=387
switch) in favor of SSE2 instructions.
Secondly, Rémy put significant effort into porting code generation improvements from 6g
into 8g
(and 5g
, the arm
compiler). Where possible code was moved into the compiler frontend, gc
, including introducing a framework to rewrite division as simpler shift and multiply operations.
In general the results for linux/386
on this host show improvements that are as good, or in some cases, better than linux/amd64
. Unlike linux/amd64,
there is no slowdown in the Gzip
or Gob
benchmarks.
The two small regressions, BinaryTree17
and Fannkuch11,
are assumed to be attributable to the garbage collector becoming more precise. This involves some additional bookkeeping to track the size and type of objects allocated on the heap, which shows up in these benchmarks.
net/http benchmarks
The improvements in the net
package previously demonstrated in the linux/amd64
article carry over to linux/386.
The improvements in the ClientServer
benchmarks are not as marked as its amd64
cousin, but nonetheless show a significant improvement overall due to the tighter integration between the runtime
and net
package.
Runtime microbenchmarks
Like the amd64
benchmarks in part 1, the runtime
microbenchmarks show a mixture of results. Some low level operations got a bit slower, while other operations, like map
have improved significantly.
The final two benchmarks, which appear truncated, are actually so large they do not fit on the screen. The improvement is mostly due to this change which introduced a faster low level Equals
operation for the strings
, bytes
and runtime
packages. The results speak for themselves.
benchmark old MB/s new MB/s speedup BenchmarkCompareStringBigUnaligned 29.08 1145.48 39.39x BenchmarkCompareStringBig 29.09 1253.48 43.09x
Conclusion
Although 8g
is not the leading compiler of the gc suite, Ken Thompson himself has said that there are essentially no free registers available on 386
, linux/386
shows that it easily meets the 30-40% performance improvement claim. In some benchmarks, compared to Go 1.0, linux/386
beats linux/amd64
.
Additionally, due to reductions in memory usage, all the compilers now use around half as much memory when compiling, and as a direct consequence, compile up to 30% faster than their 1.0 predecessors.
I encourage you to review the benchmark data in the autobench repository and if you are able, submit your own results.
In the final article in this series I will investigate the performance improvement Go 1.1 brings to arm
platforms. I assure you, I’ve saved the best til last.
Update: thanks to @ajstarks who provided me with higher quality benchviz images.