...
1
2
3
4
5
6
7
8
9
10 package ssa_test
11
12
13
14
15
16
17 import (
18 "go/ast"
19 "go/token"
20 "go/types"
21 "runtime"
22 "testing"
23 "time"
24
25 "golang.org/x/tools/go/packages"
26 "golang.org/x/tools/go/ssa"
27 "golang.org/x/tools/go/ssa/ssautil"
28 "golang.org/x/tools/internal/testenv"
29 )
30
31 func bytesAllocated() uint64 {
32 runtime.GC()
33 var stats runtime.MemStats
34 runtime.ReadMemStats(&stats)
35 return stats.Alloc
36 }
37
38
39
40
41
42
43 func TestStdlib(t *testing.T) {
44 testLoad(t, 500, "std", "cmd")
45 }
46
47
48
49 func TestNetHTTP(t *testing.T) {
50 testLoad(t, 120, "net/http")
51 }
52
53 func testLoad(t *testing.T, minPkgs int, patterns ...string) {
54
55
56 if testing.Short() {
57 t.Skip("skipping in short mode; too slow (https://golang.org/issue/14113)")
58 }
59 testenv.NeedsTool(t, "go")
60
61
62 t0 := time.Now()
63 alloc0 := bytesAllocated()
64
65 cfg := &packages.Config{Mode: packages.LoadSyntax}
66 pkgs, err := packages.Load(cfg, patterns...)
67 if err != nil {
68 t.Fatal(err)
69 }
70
71 t1 := time.Now()
72 alloc1 := bytesAllocated()
73
74
75 var mode ssa.BuilderMode
76
77 mode |= ssa.SanityCheckFunctions
78 mode |= ssa.GlobalDebug
79 mode |= ssa.InstantiateGenerics
80 prog, _ := ssautil.Packages(pkgs, mode)
81
82 t2 := time.Now()
83
84
85 prog.Build()
86
87 t3 := time.Now()
88 alloc3 := bytesAllocated()
89
90
91 numPkgs := len(prog.AllPackages())
92 if numPkgs < minPkgs {
93 t.Errorf("Loaded only %d packages, want at least %d", numPkgs, minPkgs)
94 }
95
96
97 if len(pkgs) == 0 {
98 panic("unreachable")
99 }
100
101 srcFuncs := srcFunctions(prog, pkgs)
102 allFuncs := ssautil.AllFunctions(prog)
103
104
105
106
107
108
109
110
111
112
113
114
115 if false {
116
117
118
119 byName := make(map[string]*ssa.Function)
120 for fn := range allFuncs {
121 if fn.Synthetic == "" || ast.IsExported(fn.Name()) {
122 str := fn.String()
123 prev := byName[str]
124 byName[str] = fn
125 if prev != nil {
126 t.Errorf("%s: duplicate function named %s",
127 prog.Fset.Position(fn.Pos()), str)
128 t.Errorf("%s: (previously defined here)",
129 prog.Fset.Position(prev.Pos()))
130 }
131 }
132 }
133 }
134
135
136 var numInstrs int
137 for fn := range allFuncs {
138 for _, b := range fn.Blocks {
139 numInstrs += len(b.Instrs)
140 }
141 }
142
143
144 var lineCount int
145 prog.Fset.Iterate(func(f *token.File) bool {
146 lineCount += f.LineCount()
147 return true
148 })
149
150
151
152
153 t.Log("GOMAXPROCS: ", runtime.GOMAXPROCS(0))
154 t.Log("#Source lines: ", lineCount)
155 t.Log("Load/parse/typecheck: ", t1.Sub(t0))
156 t.Log("SSA create: ", t2.Sub(t1))
157 t.Log("SSA build: ", t3.Sub(t2))
158
159
160 t.Log("#Packages: ", numPkgs)
161 t.Log("#SrcFunctions: ", len(srcFuncs))
162 t.Log("#AllFunctions: ", len(allFuncs))
163 t.Log("#Instructions: ", numInstrs)
164 t.Log("#MB AST+types: ", int64(alloc1-alloc0)/1e6)
165 t.Log("#MB SSA: ", int64(alloc3-alloc1)/1e6)
166 }
167
168
169
170
171
172
173 func srcFunctions(prog *ssa.Program, pkgs []*packages.Package) (res []*ssa.Function) {
174 var addSrcFunc func(fn *ssa.Function)
175 addSrcFunc = func(fn *ssa.Function) {
176 res = append(res, fn)
177 for _, anon := range fn.AnonFuncs {
178 addSrcFunc(anon)
179 }
180 }
181 for _, pkg := range pkgs {
182 for _, file := range pkg.Syntax {
183 for _, decl := range file.Decls {
184 if decl, ok := decl.(*ast.FuncDecl); ok {
185 obj := pkg.TypesInfo.Defs[decl.Name].(*types.Func)
186 if obj == nil {
187 panic("nil *Func")
188 }
189 addSrcFunc(prog.FuncValue(obj))
190 }
191 }
192 }
193 }
194 return res
195 }
196
View as plain text