1// Copyright 2013 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5//lint:file-ignore SA1019 go/ssa's test suite is built around the deprecated go/loader. We'll leave fixing that to upstream. 6 7// Incomplete source tree on Android. 8 9// +build !android 10 11package ir_test 12 13// This file runs the IR builder in sanity-checking mode on all 14// packages beneath $GOROOT and prints some summary information. 15// 16// Run with "go test -cpu=8 to" set GOMAXPROCS. 17 18import ( 19 "go/ast" 20 "go/token" 21 "runtime" 22 "testing" 23 "time" 24 25 "golang.org/x/tools/go/packages" 26 "honnef.co/go/tools/ir" 27 "honnef.co/go/tools/ir/irutil" 28) 29 30func bytesAllocated() uint64 { 31 runtime.GC() 32 var stats runtime.MemStats 33 runtime.ReadMemStats(&stats) 34 return stats.TotalAlloc 35} 36 37func TestStdlib(t *testing.T) { 38 if testing.Short() { 39 t.Skip("skipping in short mode; too slow (golang.org/issue/14113)") 40 } 41 42 var ( 43 numFuncs int 44 numInstrs int 45 46 dLoad time.Duration 47 dCreate time.Duration 48 dBuild time.Duration 49 50 allocLoad uint64 51 allocBuild uint64 52 ) 53 54 // Load, parse and type-check the program. 55 t0 := time.Now() 56 alloc0 := bytesAllocated() 57 58 cfg := &packages.Config{ 59 Mode: packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles | packages.NeedImports | packages.NeedDeps | packages.NeedTypes | packages.NeedSyntax | packages.NeedTypesInfo | packages.NeedTypesSizes, 60 } 61 pkgs, err := packages.Load(cfg, "std") 62 if err != nil { 63 t.Fatalf("Load failed: %v", err) 64 } 65 allocLoad = bytesAllocated() - alloc0 66 dLoad = time.Since(t0) 67 68 alloc0 = bytesAllocated() 69 for _, pkg := range pkgs { 70 if len(pkg.Errors) != 0 { 71 t.Fatalf("Load failed: %v", pkg.Errors) 72 } 73 74 var mode ir.BuilderMode 75 // Comment out these lines during benchmarking. Approx IR build costs are noted. 76 mode |= ir.SanityCheckFunctions // + 2% space, + 4% time 77 mode |= ir.GlobalDebug // +30% space, +18% time 78 prog := ir.NewProgram(pkg.Fset, mode) 79 80 t0 := time.Now() 81 var irpkg *ir.Package 82 for _, pkg2 := range pkgs { 83 r := prog.CreatePackage(pkg2.Types, pkg2.Syntax, pkg2.TypesInfo, true) 84 if pkg2 == pkg { 85 irpkg = r 86 } 87 } 88 dCreate += time.Since(t0) 89 90 t0 = time.Now() 91 irpkg.Build() 92 dBuild += time.Since(t0) 93 94 allFuncs := irutil.AllFunctions(prog) 95 numFuncs += len(allFuncs) 96 97 // Check that all non-synthetic functions have distinct names. 98 // Synthetic wrappers for exported methods should be distinct too, 99 // except for unexported ones (explained at (*Function).RelString). 100 byName := make(map[string]*ir.Function) 101 for fn := range allFuncs { 102 if fn.Synthetic == "" || ast.IsExported(fn.Name()) { 103 str := fn.String() 104 prev := byName[str] 105 byName[str] = fn 106 if prev != nil { 107 t.Errorf("%s: duplicate function named %s", 108 prog.Fset.Position(fn.Pos()), str) 109 t.Errorf("%s: (previously defined here)", 110 prog.Fset.Position(prev.Pos())) 111 } 112 } 113 } 114 115 // Dump some statistics. 116 var numInstrs int 117 for fn := range allFuncs { 118 for _, b := range fn.Blocks { 119 numInstrs += len(b.Instrs) 120 } 121 } 122 } 123 allocBuild = bytesAllocated() - alloc0 124 125 // determine line count 126 var lineCount int 127 pkgs[0].Fset.Iterate(func(f *token.File) bool { 128 lineCount += f.LineCount() 129 return true 130 }) 131 132 // NB: when benchmarking, don't forget to clear the debug + 133 // sanity builder flags for better performance. 134 135 t.Log("GOMAXPROCS: ", runtime.GOMAXPROCS(0)) 136 t.Log("#Source lines: ", lineCount) 137 t.Log("Load/parse/typecheck: ", dLoad) 138 t.Log("IR create: ", dCreate) 139 t.Log("IR build: ", dBuild) 140 141 // IR stats: 142 t.Log("#Packages: ", len(pkgs)) 143 t.Log("#Functions: ", numFuncs) 144 t.Log("#Instructions: ", numInstrs) 145 t.Log("#MB AST+types: ", allocLoad/1e6) 146 t.Log("#MB IR: ", allocBuild/1e6) 147} 148