This document discusses escape analysis in the Go compiler. It provides an overview of the Go language and compiler, including the main phases of parsing, type checking and AST transformations, SSA form, and generating machine code. It notes that the type checking phase contains several sub-phases, including escape analysis, which determines if local variables can be allocated to the stack instead of the heap. The document then delves into how escape analysis is implemented in the Go compiler.
Grokking Techtalk #38: Escape Analysis in Go compiler
1. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 1/57
Escape analysis in the Go compilerEscape analysis in the Go compiler
Cuong Manh LeCuong Manh Le
2020-09-262020-09-26
Software EngineerSoftware Engineer
2. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 2/57
AgendaAgenda
Go overviewGo overview
Go compiler overviewGo compiler overview
Escape Analysis overviewEscape Analysis overview
How Go compiler implements escape analysisHow Go compiler implements escape analysis 22
3. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 3/57
Warm upWarm up
This talk assumes you did know fundamental concepts of a compiler.This talk assumes you did know fundamental concepts of a compiler.
The termThe term gcgc in this talk stands forin this talk stands for go compilergo compiler, not, not garbage collectorgarbage collector..
There are some compilers for Go: gc, gccgo,There are some compilers for Go: gc, gccgo, tinygotinygo(https://github.com/tinygo-org/tinygo)(https://github.com/tinygo-org/tinygo)... This talk is about... This talk is about
gcgc, the official Go compiler., the official Go compiler.
This talk use go version 1.15This talk use go version 1.15
I recommendI recommend this coursethis course(https://online.stanford.edu/courses/soe-ycscs1-compilers)(https://online.stanford.edu/courses/soe-ycscs1-compilers)for anyone interested in learning aboutfor anyone interested in learning about
compilers.compilers. 33
4. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 4/57
Let's goLet's go
44
5. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 5/57
Go overviewGo overview
55
6. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 6/57
GoGo
Go is an open source programming language that makes it easy to build simple, reliable, andGo is an open source programming language that makes it easy to build simple, reliable, and
efficient software.efficient software.
package mainpackage main
import "fmt"import "fmt"
func main() {func main() {
fmt.Println("Hello, 世界")fmt.Println("Hello, 世界")
}} Run
66
7. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 7/57
Why is Go great for modern distributed computing?Why is Go great for modern distributed computing?
First class concurrency primitivesFirst class concurrency primitives
All inclusive networking librariesAll inclusive networking libraries
Statically Typed languageStatically Typed language
Simple language to learnSimple language to learn
Statically linked binariesStatically linked binaries
Fast build timesFast build times
Many more…Many more… 77
8. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 8/57
Go was built to solve problems at Google:Go was built to solve problems at Google:
Multicore processorsMulticore processors
Networked systemsNetworked systems
Massive computation clustersMassive computation clusters
......
See more detailsSee more details herehere(https://talks.golang.org/2013/distsys.slide#1)(https://talks.golang.org/2013/distsys.slide#1) 88
9. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 9/57
Go Compiler OverviewGo Compiler Overview
99
10. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 10/57
What's compilerWhat's compiler
A compiler is a computer program that translates high level human written computer codeA compiler is a computer program that translates high level human written computer code
into machine executable code.into machine executable code.
$ file main.go$ file main.go
main.go: C source, UTF-8 Unicode textmain.go: C source, UTF-8 Unicode text
$ go tool compile main.go$ go tool compile main.go
$ ls$ ls
main.go main.omain.go main.o
$ file main.o$ file main.o
main.o: current ar archivemain.o: current ar archive
$ ar x main.o$ ar x main.o
$ ls$ ls
_go_.o main.go main.o __.PKGDEF_go_.o main.go main.o __.PKGDEF
$ file _go_.o$ file _go_.o
_go_.o: data_go_.o: data
1010
11. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 11/57
Go compiler (gc)Go compiler (gc)
Translate go source code to machine code.Translate go source code to machine code.
$ go tool compile main.go$ go tool compile main.go
Actually, "gc" is a separate executable, invoked by the "go" command:Actually, "gc" is a separate executable, invoked by the "go" command:
$ go tool -n compile$ go tool -n compile
/home/cuonglm/sources/go/pkg/tool/linux_amd64/compile/home/cuonglm/sources/go/pkg/tool/linux_amd64/compile
1111
12. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 12/57
How does gc do itHow does gc do it
Through many steps or phases, logically, there'reThrough many steps or phases, logically, there're fourfour phases:phases:
ParsingParsing
Type-checking and AST transformationsType-checking and AST transformations
SSASSA
Generate machine codeGenerate machine code 1212
13. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 13/57
How does gc do itHow does gc do it
SourceSource(https://www.slideshare.net/moriyoshi/hacking-go-compiler-internals-gocon-2014-autumn)(https://www.slideshare.net/moriyoshi/hacking-go-compiler-internals-gocon-2014-autumn) 1313
14. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 14/57
1 - Parsing1 - Parsing
Includes bothIncludes both lexinglexing(https://en.wikipedia.org/wiki/Lexical_analysis)(https://en.wikipedia.org/wiki/Lexical_analysis)andand parsingparsing(https://en.wikipedia.org/wiki/Parsing)(https://en.wikipedia.org/wiki/Parsing) 1414
15. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 15/57
Lexer comes from lexical analysis which means converting a sequence ofLexer comes from lexical analysis which means converting a sequence of
characters into a sequence of tokens/stringscharacters into a sequence of tokens/strings
SourceSource(https://www.slideshare.net/moriyoshi/hacking-go-compiler-internals-gocon-2014-autumn)(https://www.slideshare.net/moriyoshi/hacking-go-compiler-internals-gocon-2014-autumn) 1515
16. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 16/57
SourceSource(https://www.slideshare.net/moriyoshi/hacking-go-compiler-internals-gocon-2014-autumn)(https://www.slideshare.net/moriyoshi/hacking-go-compiler-internals-gocon-2014-autumn) 1616
17. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 17/57
ExampleExample
a := 1a := 1
will be parsed/lexed and produce:will be parsed/lexed and produce:
[]ast.Stmt {[]ast.Stmt {
&ast.AssignStmt {&ast.AssignStmt {
Lhs: []ast.Expr {Lhs: []ast.Expr {
&ast.Ident {Name: "a"},&ast.Ident {Name: "a"},
},},
Tok: :=,Tok: :=,
Rhs: []ast.Expr {Rhs: []ast.Expr {
&ast.BasicLit {&ast.BasicLit {
ValuePos: 32,ValuePos: 32,
Kind: INT,Kind: INT,
Value: "1",Value: "1",
},},
},},
},},
}}
This uses "go/ast", compiler uses another parser in "cmd/compile/internal/syntax", but it'sThis uses "go/ast", compiler uses another parser in "cmd/compile/internal/syntax", but it's
similar.similar. 1717
18. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 18/57
2 - Type-checking and AST transformations2 - Type-checking and AST transformations
Type checking means to confirm that declared variables correctly store data with theType checking means to confirm that declared variables correctly store data with the
types they are declared with.types they are declared with.
To perform type checking, this pass is presented with what's called anTo perform type checking, this pass is presented with what's called an Abstract syntaxAbstract syntax
treetree(https://en.wikipedia.org/wiki/Abstract_syntax_tree)(https://en.wikipedia.org/wiki/Abstract_syntax_tree)
The intermediate representation (The intermediate representation (IRIR(https://en.wikipedia.org/wiki/Intermediate_representation)(https://en.wikipedia.org/wiki/Intermediate_representation)) of source code in another) of source code in another
form, specifically, it's aform, specifically, it's a treetree..
package mainpackage main
func main() {func main() {
var x stringvar x string
x = 1x = 1
println(x)println(x)
}} Run
1818
19. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 19/57
3 - SSA3 - SSA
Static single assignment formStatic single assignment form(https://en.wikipedia.org/wiki/Static_single_assignment_form)(https://en.wikipedia.org/wiki/Static_single_assignment_form)is another IR of the source codeis another IR of the source code
(not a(not a treetree):):
variable is assignedvariable is assigned exactly onceexactly once
variable isvariable is defineddefined before it is usedbefore it is used
b1:b1:
v1 = InitMem <mem>v1 = InitMem <mem>
v2 = SP <uintptr>v2 = SP <uintptr>
v3 = SB <uintptr>v3 = SB <uintptr>
v4 = Addr <*uint8> {type.string} v3v4 = Addr <*uint8> {type.string} v3
v5 = Addr <*string> {""..stmp_0} v3v5 = Addr <*string> {""..stmp_0} v3
v6 = IMake <interface {}> v4 v5 (~arg0[interface {}])v6 = IMake <interface {}> v4 v5 (~arg0[interface {}])
v7 = ConstInterface <interface {}>v7 = ConstInterface <interface {}>
v8 = ArrayMake1 <[1]interface {}> v7v8 = ArrayMake1 <[1]interface {}> v7
v9 = VarDef <mem> {.autotmp_11} v1v9 = VarDef <mem> {.autotmp_11} v1
......
v25 = ConstInterface <error> (fmt..autotmp_4[error], fmt.err[error]) DEADv25 = ConstInterface <error> (fmt..autotmp_4[error], fmt.err[error]) DEAD
v28 = OffPtr <*io.Writer> [0] v2v28 = OffPtr <*io.Writer> [0] v2
v29 = Addr <*uint8> {go.itab.*os.File,io.Writer} v3v29 = Addr <*uint8> {go.itab.*os.File,io.Writer} v3
v30 = Addr <**os.File> {os.Stdout} v3v30 = Addr <**os.File> {os.Stdout} v3
......
1919
20. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 20/57
SSA helps avoiding unnecessary operations that don't affect the final form of a variable's use:SSA helps avoiding unnecessary operations that don't affect the final form of a variable's use:
nil-check, bound check ...nil-check, bound check ... 2020
22. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 22/57
That's 4 logical phases of go compilerThat's 4 logical phases of go compiler
2222
23. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 23/57
But ...But ...
The second phase contains moreThe second phase contains more sub-phasessub-phases
Type Check const, type, and names and types of funcsType Check const, type, and names and types of funcs
Type Check variable assignmentsType Check variable assignments
Type check function bodiesType check function bodies
Capture closure variablesCapture closure variables
InliningInlining
Escape analysisEscape analysis
Transform closure bodiesTransform closure bodies 2323
24. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 24/57
But ...But ...
The second phase contains moreThe second phase contains more sub-phasessub-phases
Type Check const, type, and names and types of funcsType Check const, type, and names and types of funcs
Type Check variable assignmentsType Check variable assignments
Type check function bodiesType check function bodies
Capture closure variablesCapture closure variables
InliningInlining
Escape analysisEscape analysis
Transform closure bodiesTransform closure bodies
Escape Analysis is important to help the compiler decide if it should allocate variables on theEscape Analysis is important to help the compiler decide if it should allocate variables on the
heap or on the stack or how to store the associated data.heap or on the stack or how to store the associated data. 2424
25. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 25/57
What is Escape AnalysisWhat is Escape Analysis
Escape Analysis is a method for determining the dynamic scope of pointers – where in theEscape Analysis is a method for determining the dynamic scope of pointers – where in the
program a pointer can be accessed. It is related to pointer analysis and shape analysis.program a pointer can be accessed. It is related to pointer analysis and shape analysis.
From https://en.wikipedia.org/wiki/Escape_analysisFrom https://en.wikipedia.org/wiki/Escape_analysis 2525
26. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 26/57
What is Escape AnalysisWhat is Escape Analysis
Escape Analysis is a method for determining the dynamic scope of pointers –Escape Analysis is a method for determining the dynamic scope of pointers – wherewhere in thein the
program a pointer can be accessed. It is related to pointer analysis and shape analysis.program a pointer can be accessed. It is related to pointer analysis and shape analysis.
"where" means"where" means stackstack oror heapheap 2626
27. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 27/57
Stack vs HeapStack vs Heap
This is traditional way heap/stack work.This is traditional way heap/stack work.
Within Go runtime:Within Go runtime:
Stacks are allocated within heap memoryStacks are allocated within heap memory
There can be more than one stack, and stacks might grow/shrink/move over time.There can be more than one stack, and stacks might grow/shrink/move over time. 2727
28. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 28/57
Why is Escape Analysis necessaryWhy is Escape Analysis necessary
The most benefit is helping convert heap allocation → stack allocationThe most benefit is helping convert heap allocation → stack allocation 2828
29. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 29/57
Why is Escape Analysis necessaryWhy is Escape Analysis necessary
That means:That means:
Faster execution time: stack allocation is much faster than heap allocationFaster execution time: stack allocation is much faster than heap allocation
Reduce garbage collector pressureReduce garbage collector pressure 2929
30. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 30/57
ExampleExample
StackStack
package mainpackage main
import "testing"import "testing"
type s struct {type s struct {
f *intf *int
}}
func stack() {func stack() {
x := s{}x := s{}
x.f = new(int)x.f = new(int)
}}
func BenchmarkAlloc(b *testing.B) {func BenchmarkAlloc(b *testing.B) {
b.ReportAllocs()b.ReportAllocs()
for i := 0; i <= b.N; i++ {for i := 0; i <= b.N; i++ {
stack()stack()
}}
}}
3030
34. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 34/57
ExampleExample
$ benchstat stack.txt heap.txt$ benchstat stack.txt heap.txt
name old time/op new time/op deltaname old time/op new time/op delta
Alloc-8 0.24ns ± 1% 11.25ns ± 7% +4591.41% (p=0.000 n=10+10)Alloc-8 0.24ns ± 1% 11.25ns ± 7% +4591.41% (p=0.000 n=10+10)
name old alloc/op new alloc/op deltaname old alloc/op new alloc/op delta
Alloc-8 0.00B 8.00B ± 0% +Inf% (p=0.000 n=10+10)Alloc-8 0.00B 8.00B ± 0% +Inf% (p=0.000 n=10+10)
name old allocs/op new allocs/op deltaname old allocs/op new allocs/op delta
Alloc-8 0.00 1.00 ± 0% +Inf% (p=0.000 n=10+10)Alloc-8 0.00 1.00 ± 0% +Inf% (p=0.000 n=10+10)
3434
35. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 35/57
How is escape analysis implemented in the GoHow is escape analysis implemented in the Go
compiler?compiler?
3535
36. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 36/57
Building a directed weighted graphBuilding a directed weighted graph
With some rules:With some rules:
Vertices (termed "location") represent variables.Vertices (termed "location") represent variables.
Edges represent assignments between variables.Edges represent assignments between variables.
Compound variables (struct, slice, array, map ...) is lowered to simplest representation.Compound variables (struct, slice, array, map ...) is lowered to simplest representation. 3636
37. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 37/57
That meansThat means
var x struct { f, g *int }var x struct { f, g *int }
var u []*intvar u []*int
x.f = u[0]x.f = u[0]
is modeled simply as:is modeled simply as:
x = *ux = *u
3737
38. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 38/57
Building a directed weighted graphBuilding a directed weighted graph
With some rules:With some rules:
Vertices (termed "location") represents variables.Vertices (termed "location") represents variables.
Edges represents assignments between variables.Edges represents assignments between variables.
Compound variables is lowered to simplest representation.Compound variables is lowered to simplest representation.
Number of dereference operations minus the number of addressing operations is theNumber of dereference operations minus the number of addressing operations is the
edge's weightedge's weight
p = &q // -1p = &q // -1
p = q // 0p = q // 0
p = *q // 1p = *q // 1
p = **q // 2p = **q // 2
p = **&**&q // 2p = **&**&q // 2
3838
39. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 39/57
Run Bellman-Ford shortest path algorithmRun Bellman-Ford shortest path algorithm
To calculate the minimal number of dereferences from a "location" to others.To calculate the minimal number of dereferences from a "location" to others.
Bellman-FordBellman-Ford(https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm)(https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm)is slower thanis slower than DijkstraDijkstra(https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm)(https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm),,
but it can handle negative weight (from addressing operations).but it can handle negative weight (from addressing operations).
Also do not have to worry about negative cycles, because the compiler does not allowAlso do not have to worry about negative cycles, because the compiler does not allow
"distances" to go below 0."distances" to go below 0.
var x intvar x int
_ = &(&x) // invalid_ = &(&x) // invalid
3939
40. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 40/57
ExampleExample
With following code:With following code:
package ppackage p
var px *intvar px *int
func foo() {func foo() {
var i intvar i int
p := &ip := &i
q := pq := p
px = qpx = q
}}
ii has no edgeshas no edges
pp has edge to i ( weight -1 )has edge to i ( weight -1 )
qq has edge to p ( weight 0 )has edge to p ( weight 0 )
heap has edge to q ( weight 0 )heap has edge to q ( weight 0 ) 4040
42. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 42/57
Static data-flow analysisStatic data-flow analysis
To determine whether a locationTo determine whether a location outlivesoutlives others, that means it may survive beyond other'sothers, that means it may survive beyond other's
lifetime if stack allocated.lifetime if stack allocated.
A location outlives other if ...A location outlives other if ... 4242
43. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 43/57
Returned valuesReturned values
We don't know what the caller will do with the returned values.We don't know what the caller will do with the returned values.
Except for directly called closures:Except for directly called closures:
var u intvar u int
p := func() *int { return &u }()p := func() *int { return &u }()
*p = 42*p = 42
4343
44. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 44/57
Higher loop scopeHigher loop scope
in the same function:in the same function:
var l *intvar l *int
for {for {
l = new(int)l = new(int)
}}
4444
45. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 45/57
Other is declared within a child closureOther is declared within a child closure
var l *intvar l *int
func() {func() {
l = new(int)l = new(int)
}}
4545
46. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 46/57
Escape analysis also records information about whether a function's parameters will escape.Escape analysis also records information about whether a function's parameters will escape.
var global *intvar global *int
func f(p *int) { *p = 42 }func f(p *int) { *p = 42 }
func g(p *int) { global = p }func g(p *int) { global = p }
func h() {func h() {
f(new(int)) // does not escapef(new(int)) // does not escape
g(new(int)) // does escapeg(new(int)) // does escape
}}
That is because escape analysis firstly analyzes justThat is because escape analysis firstly analyzes just ff, then analyzes just *, then analyzes just *gg, then just, then just hh, but it, but it
uses the results of previously analyzinguses the results of previously analyzing ff andand gg.. 4646
47. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 47/57
That's the theoryThat's the theory
4747
48. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 48/57
In practiceIn practice
Go compiler provides tools for us to diagnose all of those things.Go compiler provides tools for us to diagnose all of those things.
usage: compile [options] file.go...usage: compile [options] file.go...
......
version,destination for JSON compiler/optimizer loggingversion,destination for JSON compiler/optimizer logging
-l disable inlining-l disable inlining
-lang string-lang string
release to compile forrelease to compile for
-linkobj file-linkobj file
write linker-specific object to filewrite linker-specific object to file
-linkshared-linkshared
generate code that will be linked against Go shared librariesgenerate code that will be linked against Go shared libraries
-live-live
debug liveness analysisdebug liveness analysis
-m print optimization decisions-m print optimization decisions
-memprofile file-memprofile file
write memory profile to filewrite memory profile to file
-memprofilerate rate-memprofilerate rate
set runtime.MemProfileRate to rateset runtime.MemProfileRate to rate
......
4848
49. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 49/57
ExampleExample
10 func stack() {10 func stack() {
11 x := s{}11 x := s{}
12 x.f = new(int)12 x.f = new(int)
13 }13 }
1414
15 func heap() {15 func heap() {
16 x := &s{}16 x := &s{}
17 x.f = new(int)17 x.f = new(int)
18 }18 }
$ go tool compile -l -m stack_vs_heap_test.go$ go tool compile -l -m stack_vs_heap_test.go
stack_vs_heap_test.go:12:11: new(int) does not escapestack_vs_heap_test.go:12:11: new(int) does not escape
stack_vs_heap_test.go:16:7: &s{} does not escapestack_vs_heap_test.go:16:7: &s{} does not escape
stack_vs_heap_test.go:17:11: new(int) escapes to heapstack_vs_heap_test.go:17:11: new(int) escapes to heap
4949
50. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 50/57
ExampleExample
$ go tool compile -l -m=2 stack_vs_heap_test.go$ go tool compile -l -m=2 stack_vs_heap_test.go
stack_vs_heap_test.go:12:11: new(int) does not escapestack_vs_heap_test.go:12:11: new(int) does not escape
stack_vs_heap_test.go:17:11: new(int) escapes to heap:stack_vs_heap_test.go:17:11: new(int) escapes to heap:
stack_vs_heap_test.go:17:11: flow: {heap} = &{storage for new(int)}:stack_vs_heap_test.go:17:11: flow: {heap} = &{storage for new(int)}:
stack_vs_heap_test.go:17:11: from new(int) (spill) at stack_vs_heap_test.go:17:11stack_vs_heap_test.go:17:11: from new(int) (spill) at stack_vs_heap_test.go:17:11
stack_vs_heap_test.go:17:11: from x.f = new(int) (assign) at stack_vs_heap_test.go:17:6stack_vs_heap_test.go:17:11: from x.f = new(int) (assign) at stack_vs_heap_test.go:17:6
stack_vs_heap_test.go:16:7: &s{} does not escapestack_vs_heap_test.go:16:7: &s{} does not escape
stack_vs_heap_test.go:17:11: new(int) escapes to heapstack_vs_heap_test.go:17:11: new(int) escapes to heap
5050
51. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 51/57
ExampleExample
$ go tool compile -l -m=3 stack_vs_heap_test.go$ go tool compile -l -m=3 stack_vs_heap_test.go
stack_vs_heap_test.go:11:4:[1] stack stmt: x := s{}stack_vs_heap_test.go:11:4:[1] stack stmt: x := s{}
stack_vs_heap_test.go:11:2:[1] stack stmt: var x sstack_vs_heap_test.go:11:2:[1] stack stmt: var x s
stack_vs_heap_test.go:12:6:[1] stack stmt: x.f = new(int)stack_vs_heap_test.go:12:6:[1] stack stmt: x.f = new(int)
stack_vs_heap_test.go:12:11: new(int) does not escapestack_vs_heap_test.go:12:11: new(int) does not escape
stack_vs_heap_test.go:16:4:[1] heap stmt: x := &s{}stack_vs_heap_test.go:16:4:[1] heap stmt: x := &s{}
stack_vs_heap_test.go:16:2:[1] heap stmt: var x *sstack_vs_heap_test.go:16:2:[1] heap stmt: var x *s
stack_vs_heap_test.go:17:6:[1] heap stmt: x.f = new(int)stack_vs_heap_test.go:17:6:[1] heap stmt: x.f = new(int)
stack_vs_heap_test.go:17:11: new(int) escapes to heap:stack_vs_heap_test.go:17:11: new(int) escapes to heap:
stack_vs_heap_test.go:17:11: flow: {heap} = &{storage for new(int)}:stack_vs_heap_test.go:17:11: flow: {heap} = &{storage for new(int)}:
stack_vs_heap_test.go:17:11: from new(int) (spill) at stack_vs_heap_test.go:17:11stack_vs_heap_test.go:17:11: from new(int) (spill) at stack_vs_heap_test.go:17:11
stack_vs_heap_test.go:17:11: from x.f = new(int) (assign) at stack_vs_heap_test.go:17:6stack_vs_heap_test.go:17:11: from x.f = new(int) (assign) at stack_vs_heap_test.go:17:6
stack_vs_heap_test.go:16:7: &s{} does not escapestack_vs_heap_test.go:16:7: &s{} does not escape
stack_vs_heap_test.go:17:11: new(int) escapes to heapstack_vs_heap_test.go:17:11: new(int) escapes to heap
5151
52. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 52/57
There's plenty of short-comingsThere's plenty of short-comings
var global *intvar global *int
func f(x bool, p *int) { if x { global = p } }func f(x bool, p *int) { if x { global = p } }
func g() {func g() {
f(false, new(int)) // BAD: new(int) is heap allocated, but would be safe to stack allocate heref(false, new(int)) // BAD: new(int) is heap allocated, but would be safe to stack allocate here
}}
Or assigment through a pointer is conservatively treated as a store to the heap.Or assigment through a pointer is conservatively treated as a store to the heap.
func heap() {func heap() {
x := &s{}x := &s{}
x.f = new(int)x.f = new(int)
}}
5252
53. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 53/57
Further readingFurther reading
https://github.com/golang/go/blob/release-https://github.com/golang/go/blob/release-
branch.go1.15/src/cmd/compile/internal/gc/escape.gobranch.go1.15/src/cmd/compile/internal/gc/escape.go
https://www.cc.gatech.edu/~harrold/6340/cs6340_fall2009/Readings/choi99escape.pdfhttps://www.cc.gatech.edu/~harrold/6340/cs6340_fall2009/Readings/choi99escape.pdf5353
54. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 54/57
Q&AQ&A
5454
55. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 55/57
Special thanks (listing order by reviewing date)Special thanks (listing order by reviewing date)
@huydx@huydx(https://github.com/huydx)(https://github.com/huydx)
@favadi@favadi(https://github.com/favadi)(https://github.com/favadi)
@mdempsky@mdempsky(https://github.com/mdempsky)(https://github.com/mdempsky)
@odeke-em@odeke-em(https://github.com/odeke-em)(https://github.com/odeke-em)
These folks have helped me review many things like parts of this talk and code.These folks have helped me review many things like parts of this talk and code. 5555
56. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 56/57
Thank youThank you
Cuong Manh LeCuong Manh Le
2020-09-262020-09-26
Software EngineerSoftware Engineer
cuong.manhle.vn@gmail.comcuong.manhle.vn@gmail.com(mailto:cuong.manhle.vn@gmail.com)(mailto:cuong.manhle.vn@gmail.com)
https://cuonglm.xyzhttps://cuonglm.xyz(https://cuonglm.xyz)(https://cuonglm.xyz)
@cuonglm_@cuonglm_(http://twitter.com/cuonglm_)(http://twitter.com/cuonglm_)
57. 10/15/2020 Escape analysis in the Go compiler
https://talks.cuonglm.xyz/escape-analysis-in-go-compiler.slide#1 57/57