Skip to content

Commit 118dd1d

Browse files
committed
Add first talk.
0 parents  commit 118dd1d

13 files changed

+760
-0
lines changed

.gitignore

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Compiled Object files, Static and Dynamic libs (Shared Objects)
2+
*.o
3+
*.a
4+
*.so
5+
6+
# Folders
7+
_obj
8+
_test
9+
10+
# Architecture specific extensions/prefixes
11+
*.[568vq]
12+
[568vq].out
13+
14+
*.cgo1.go
15+
*.cgo2.c
16+
_cgo_defun.c
17+
_cgo_gotypes.go
18+
_cgo_export.*
19+
20+
_testmain.go
21+
22+
*.exe
23+
*.test
24+
*.prof
25+
present

2016/go17-compiler.slide

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
Utilizing the Go 1.7 SSA Compiler
2+
3+
Copenhagen Gophers Meetup
4+
20 Sep 2016
5+
6+
Klaus Post
7+
Vivino, Senior Backend Engineer
8+
9+
10+
11+
* Go SSA Compiler
12+
13+
Main feature of the compiler in Go 1.7 is a "Static Single Assignment" compiler.
14+
15+
Used by some of our favorite tools:
16+
17+
- go vet
18+
- gorename
19+
- Go Guru (former Go Oracle)
20+
- safesql
21+
22+
NOW:
23+
24+
- go build
25+
26+
* What does SSA do?
27+
28+
(stolen from: [[https://talks.golang.org/2014/static-analysis.slide#10][Static analysis tools talks]] by Alan Donovan)
29+
30+
Extremely simplified:
31+
32+
Programs are lowered into Static Single-Assignment form (SSA):
33+
34+
- simplifies dataflow analyses since _reaching_ _definitions_ are implicit
35+
- invented 1991, now mainstream (gcc, llvm)
36+
37+
All Go programs can be expressed using only ~30 basic instructions
38+
39+
Simple, explicit, high-level, high source fidelity
40+
41+
.link http://godoc.org/golang.org/x/tools/go/ssa golang.org/x/tools/go/ssa
42+
43+
44+
* SSA Example
45+
46+
func fib(x int) int {
47+
if x < 2 {
48+
return x
49+
}
50+
return fib(x-1) + fib(x-2)
51+
}
52+
53+
54+
55+
func fib(x int) int:
56+
0: entry P:0 S:2
57+
t0 = x < 2:int bool
58+
if t0 goto 1 else 2
59+
1: if.then P:1 S:0
60+
return x
61+
2: if.done P:1 S:0
62+
t1 = x - 1:int int
63+
t2 = fib(t1) int
64+
t3 = x - 2:int int
65+
t4 = fib(t3) int
66+
t5 = t2 + t4 int
67+
return t5
68+
69+
* More Information on SSA
70+
71+
Go Static Analysis Tools by Alan Donovan
72+
73+
.image go17-compiler/donovan-talk.png
74+
75+
.link http://vimeo.com/114736889 Watch the talk on Vimeo
76+
77+
.link https://talks.golang.org/2014/static-analysis.slide#1 Slides
78+
79+
* What does it mean?
80+
81+
- Better code generation
82+
- Easy optimizations
83+
- Cross platform optimizations
84+
85+
= Faster Go programs. AMD64 for now, others already shaping up.
86+
87+
.image go17-compiler/pixel-gopher-256.png
88+
89+
* SSA "rules"
90+
91+
SSA rules allows to specify optimizations in a relatively simple syntax which is converted into code.
92+
93+
Example: "b = a * -1"
94+
95+
// Convert x * -1 to -x. The front-end catches some but not all of these.
96+
(Mul8 (Const8 [-1]) x) -> (Neg8 x)
97+
(Mul16 (Const16 [-1]) x) -> (Neg16 x)
98+
99+
.link https://github.com/golang/go/blob/master/src/cmd/compile/internal/ssa/rewritegeneric.go#L5760 Generated Code
100+
101+
.link https://github.com/golang/go/tree/master/src/cmd/compile/internal/ssa/gen Current SSA Rewrite Rules
102+
103+
* Bound Check Elimination
104+
105+
GC and Bounds Checks are the reason for most of the performance difference between C and Go.
106+
107+
SSA only helps GC to a smaller degree through "escape analysis".
108+
109+
However, SSA helps eliminating bounds checks, by having an easier path for tracing values.
110+
111+
Go 1.7 is now eliminating way more bounds checks, since it is easier to analyze program flow.
112+
113+
* Bounds Check Elimination Example
114+
115+
116+
Simple, by type:
117+
118+
var a [256]int
119+
120+
// byte can never be > 255
121+
for i := 0; i < 50000; i++ {
122+
_ = a[byte(i)]
123+
}
124+
125+
126+
By masking lookup:
127+
128+
var b [4096]int
129+
130+
// Mask 11 lower bits
131+
for i := 0; i < 50000; i++ {
132+
_ = b[i&4095]
133+
}
134+
135+
136+
137+
* Bounds Check Elimination Example
138+
139+
What about slices and not arrays?
140+
141+
Help the compiler!
142+
143+
Example from compress/flate:
144+
145+
// matchLen returns the number of matching bytes in a and b
146+
// up to length 'max'. Both slices must be at least 'max'
147+
// bytes in size.
148+
func matchLen(a, b []byte, max int) int {
149+
a = a[:max]
150+
b = b[:len(a)]
151+
for i, av := range a {
152+
if b[i] != av {
153+
return i
154+
}
155+
}
156+
return max
157+
}
158+
159+
* Identifying Bounds Checks
160+
161+
.code go17-compiler/bounds.go
162+
163+
* Make the compiler tell us
164+
165+
.code go17-compiler/bounds_hl.go
166+
167+
$ go build -gcflags="-d=ssa/check_bce/debug=1" bounds.go
168+
# command-line-arguments
169+
.\bounds.go:7: Found IsInBounds
170+
171+
Signifies one or more bounds check in the loop.
172+
173+
* Let's fix it
174+
175+
.code go17-compiler/bounds_fix.go
176+
177+
$ go build -gcflags="-d=ssa/check_bce/debug=1" bounds.go
178+
# command-line-arguments
179+
.\bounds.go:5: Found IsSliceInBounds
180+
.\bounds.go:8: Found IsInBounds
181+
182+
Hmmm... Have we just made it worse?
183+
184+
Guess Go isn't perfect (yet).
185+
186+
* Let's fix it (again)
187+
188+
.code go17-compiler/bounds_fixed.go
189+
190+
$ go build -gcflags="-d=ssa/check_bce/debug=1" bounds.go
191+
# command-line-arguments
192+
.\bounds.go:5: Found IsSliceInBounds
193+
.\bounds.go:7: Found IsSliceInBounds
194+
195+
Success - we now only check bounds outside the loop.
196+
197+
198+
* Real world performance
199+
200+
From [[https://github.com/klauspost/dedup][dedup package]]:
201+
202+
var c1 byte // last byte
203+
var h uint32 // rolling hash for finding fragment boundaries
204+
var o1 [256]byte // Order 1 prediction table
205+
206+
// Split b based on order 1 predictions.
207+
func Split(b []byte) int
208+
for i, c := range b {
209+
if c == o1[c1] {
210+
h = (h + uint32(c) + 1) * 314159265
211+
} else {
212+
h = (h + uint32(c) + 1) * 271828182
213+
}
214+
o1[c1] = c
215+
c1 = c
216+
if condition { return i }
217+
}
218+
}
219+
220+
* Numbers
221+
222+
https://github.com/klauspost/dedup
223+
224+
$ go test -bench=DynamicFragments
225+
226+
Go 1.6.3:
227+
228+
BenchmarkDynamicFragments64K-8 20 59823050 ns/op 175.28 MB/s
229+
230+
Go 1.7.1:
231+
232+
BenchmarkDynamicFragments64K-8 30 37100610 ns/op 282.63 MB/s
233+
234+
* "Mind == Blown" bonus
235+
236+
237+
y := x[1]
238+
z := x[0]
239+
240+
faster than
241+
242+
y := x[0]
243+
z := x[1]
244+
245+
.image go17-compiler/brad-gopher.jpg
246+
.caption Brad Fitzpatrick: [[https://twitter.com/bradfitz/status/335213285815226369][Evil, possessed gopher]].
247+
248+
* Conclusion
249+
250+
- Help the compiler in time critical loops
251+
- Enjoy the free speedups
252+
- Check and Benchmark your code
253+
254+
.image go17-compiler/pixel-gopher-256.png
255+
256+
* Questions
257+
258+
.image go17-compiler/questions.png
259+
260+
Feel free to ask questions, or ask later.
261+
262+

2016/go17-compiler/bounds.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package add
2+
3+
// Add a and b. len(b) must be >= len(a)
4+
func Add(a, b []float64) []float64 {
5+
c := make([]float64, len(a))
6+
for i := range a {
7+
c[i] = a[i] + b[i]
8+
}
9+
return c
10+
}

2016/go17-compiler/bounds_fix.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
1 package add
2+
2
3+
3 // Add a and b. len(b) must be >= len(a)
4+
4 func Add(a, b []byte) []float64 {
5+
5 b = b[:len(a)] // HL
6+
6 c := make([]float64, len(a))
7+
7 for i := range a {
8+
8 c[i] = a[i] + b[i]
9+
9 }
10+
10 return c
11+
11 }

2016/go17-compiler/bounds_fixed.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
1 package add
2+
2
3+
3 // Add a and b. len(b) must be >= len(a)
4+
4 func Add(a, b []float64) []float64 {
5+
5 b = b[:len(a)] // HL
6+
6 c := make([]float64, len(a))
7+
7 c = c[:len(a)] // HL
8+
8 for i := range a {
9+
9 c[i] = a[i] + b[i]
10+
10 }
11+
11 return c
12+
12 }

2016/go17-compiler/bounds_hl.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
1 package add
2+
2
3+
3 // Add a and b. len(b) must be >= len(a)
4+
4 func Add(a, b []float64) []float64 {
5+
5 c := make([]float64, len(a))
6+
6 for i := range a {
7+
7 c[i] = a[i] + b[i] // HL
8+
8 }
9+
9 return c
10+
10 }

2016/go17-compiler/brad-gopher.jpg

12.4 KB
Loading

2016/go17-compiler/donovan-talk.png

118 KB
Loading
359 Bytes
Loading

2016/go17-compiler/questions.png

25.9 KB
Loading

0 commit comments

Comments
 (0)