Showing posts with label golang_compiler. Show all posts
Showing posts with label golang_compiler. Show all posts

Feb 23, 2020

[Go] runtime bounds check elimination

Reference:
https://go101.org/article/bounds-check-elimination.html
https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!msg/golang-nuts/TItWw4srDgg/HwGy7JmbBQAJ
https://github.com/golang/exp/tree/master/shiny/driver/internal/swizzle

Since Go SDK 1.7, the standard Go compiler has used a new compiler backend, which based on SSA (static single-assignment form, simply put, i.e versioning the expression).

SSA helps Go compilers effectively use optimizations like BCE (bounds check elimination) and CSE (common subexpression elimination).

Check which code line still using bound check:
$ go build -gcflags="-d=ssa/check_bce/debug=1"


Sometimes, we can make some hints to help the compiler eliminate some unnecessary bounds checks:
// example from https://go101.org/article/bounds-check-elimination.html
// example5.go
package main

func fd(is []int, bs []byte) {
 if len(is) >= 256 {
  for _, n := range bs {
   _ = is[n] // line 8: bounds check
  }
 }
}

func fd2(is []int, bs []byte) {
 if len(is) >= 256 {
  is = is[:256] // line 15: a hint
  for _, n := range bs {
   _ = is[n] // line 17: BCEed!
  }
 }
}

func fe(isa []int, isb []int) {
 if len(isa) > 0xFFF {
  for _, n := range isb {
   _ = isa[n & 0xFFF] // line 25: bounds check
  }
 }
}

func fe2(isa []int, isb []int) {
 if len(isa) > 0xFFF {
  isa = isa[:0xFFF+1] // line 32: a hint
  for _, n := range isb {
   _ = isa[n & 0xFFF] // line 34: BCEed!
  }
 }
}

func main() {}

[Go] tooling update (compile time optimization, linker, compiler)

Reference:
https://rakyll.org/go-tool-flags/
https://golang.org/cmd/go/
https://github.com/golang/go/wiki/CompilerOptimizations
https://www.alexedwards.net/blog/an-overview-of-go-tooling#building-an-executable



Lists all the commands go build invokes
$ go build -x

Show flags that can be passed to compiler
$ go tool compile -help

e.g. to disable compiler optimizations and inlining, you can use the following the gcflags.
$ go build -gcflags="-N -l"


Disable bounds checking
$ go build -gcflags="-B"

Show compiler debug list:
$ go tool compile -d help 2>&1|bat

Show compiler -d ssa list:
compile: PhaseOptions usage:
$ go tool compile -d=ssa/<phase>/<flag>[=<value>|<function_name>]
$ go tool compile -d ssa/help 2>&1|bat

e.g If we want to check which line has the  "Bounds Check Elimination"
applied:
https://golang.org/src/cmd/compile/internal/ssa/checkbce.go
$ go build -gcflags="-d=ssa/check_bce/debug=1"



Linker help:
$ go tool link -help

"burn in" a (string) value to a specific variable in your application:
$ go build -ldflags="-X main.version=1.2.3" -o=/tmp/foo .

Strip debugging information from the binary.
$ go build -ldflags="-s -w" -o=/tmp/foo .  # Strip debug information from the binary



Escape analysis:
Gc compiler does global escape analysis across function and package boundaries. However, there are lots of cases where it gives up.
For example, anything assigned to any kind of indirection (*p = ...) is considered escaped.
Other things that can inhibit analysis are: function calls, package boundaries, slice literals, sub-slicing and indexing, etc.
Full rules are too complex to describe, so check the -m output.
$ go build -gcflags -m


Function Inlining:
Only short and simple functions are inlined.
To be inlined a function must contain less than ~40 expressions and does not contain complex things like loops, labels, closures, panic's, recover's, select's, switch'es, etc.


Non-scannable objects:
Garbage collector does not scan underlying buffers of slices, channels and maps when element type does not contain pointers (both key and value for maps)(this is called tracing).

This allows to hold large data sets in memory without paying high price during garbage collection.

For example, the following map won't visibly affect GC time:
type Key [64]byte // SHA-512 hash
type Value struct {
 Name      [32]byte
 Balance   uint64
 Timestamp int64
}
m := make(map[Key]Value, 1e8)