Home | History | Annotate | Download | only in garbage
      1 // Copyright 2010 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 // Garbage collection benchmark: parse Go packages repeatedly.
      6 
      7 package main
      8 
      9 import (
     10 	"flag"
     11 	"fmt"
     12 	"go/ast"
     13 	"go/parser"
     14 	"go/token"
     15 	"log"
     16 	"net/http"
     17 	_ "net/http/pprof"
     18 	"os"
     19 	"path"
     20 	"runtime"
     21 	"strings"
     22 	"time"
     23 )
     24 
     25 var serve = flag.String("serve", "", "serve http on this address at end")
     26 
     27 func isGoFile(dir os.FileInfo) bool {
     28 	return !dir.IsDir() &&
     29 		!strings.HasPrefix(dir.Name(), ".") && // ignore .files
     30 		path.Ext(dir.Name()) == ".go"
     31 }
     32 
     33 func isPkgFile(dir os.FileInfo) bool {
     34 	return isGoFile(dir) &&
     35 		!strings.HasSuffix(dir.Name(), "_test.go") // ignore test files
     36 }
     37 
     38 func pkgName(filename string) string {
     39 	file, err := parser.ParseFile(token.NewFileSet(), filename, nil, parser.PackageClauseOnly)
     40 	if err != nil || file == nil {
     41 		return ""
     42 	}
     43 	return file.Name.Name
     44 }
     45 
     46 func parseDir(dirpath string) map[string]*ast.Package {
     47 	// the package name is the directory name within its parent
     48 	// (use dirname instead of path because dirname is clean; i.e. has no trailing '/')
     49 	_, pkgname := path.Split(dirpath)
     50 
     51 	// filter function to select the desired .go files
     52 	filter := func(d os.FileInfo) bool {
     53 		if isPkgFile(d) {
     54 			// Some directories contain main packages: Only accept
     55 			// files that belong to the expected package so that
     56 			// parser.ParsePackage doesn't return "multiple packages
     57 			// found" errors.
     58 			// Additionally, accept the special package name
     59 			// fakePkgName if we are looking at cmd documentation.
     60 			name := pkgName(dirpath + "/" + d.Name())
     61 			return name == pkgname
     62 		}
     63 		return false
     64 	}
     65 
     66 	// get package AST
     67 	pkgs, err := parser.ParseDir(token.NewFileSet(), dirpath, filter, parser.ParseComments)
     68 	if err != nil {
     69 		println("parse", dirpath, err.Error())
     70 		panic("fail")
     71 	}
     72 	return pkgs
     73 }
     74 
     75 func main() {
     76 	st := new(runtime.MemStats)
     77 	packages = append(packages, packages...)
     78 	packages = append(packages, packages...)
     79 	n := flag.Int("n", 4, "iterations")
     80 	p := flag.Int("p", len(packages), "# of packages to keep in memory")
     81 	flag.BoolVar(&st.DebugGC, "d", st.DebugGC, "print GC debugging info (pause times)")
     82 	flag.Parse()
     83 
     84 	var lastParsed []map[string]*ast.Package
     85 	var t0 time.Time
     86 	var numGC uint32
     87 	var pauseTotalNs uint64
     88 	pkgroot := runtime.GOROOT() + "/src/"
     89 	for pass := 0; pass < 2; pass++ {
     90 		// Once the heap is grown to full size, reset counters.
     91 		// This hides the start-up pauses, which are much smaller
     92 		// than the normal pauses and would otherwise make
     93 		// the average look much better than it actually is.
     94 		runtime.ReadMemStats(st)
     95 		numGC = st.NumGC
     96 		pauseTotalNs = st.PauseTotalNs
     97 		t0 = time.Now()
     98 
     99 		for i := 0; i < *n; i++ {
    100 			parsed := make([]map[string]*ast.Package, *p)
    101 			for j := range parsed {
    102 				parsed[j] = parseDir(pkgroot + packages[j%len(packages)])
    103 			}
    104 			if i+1 == *n && *serve != "" {
    105 				lastParsed = parsed
    106 			}
    107 		}
    108 		runtime.GC()
    109 		runtime.GC()
    110 	}
    111 	t1 := time.Now()
    112 
    113 	runtime.ReadMemStats(st)
    114 	st.NumGC -= numGC
    115 	st.PauseTotalNs -= pauseTotalNs
    116 	fmt.Printf("Alloc=%d/%d Heap=%d Mallocs=%d PauseTime=%.3f/%d = %.3f\n",
    117 		st.Alloc, st.TotalAlloc,
    118 		st.Sys,
    119 		st.Mallocs, float64(st.PauseTotalNs)/1e9,
    120 		st.NumGC, float64(st.PauseTotalNs)/1e9/float64(st.NumGC))
    121 
    122 	/*
    123 		fmt.Printf("%10s %10s %10s\n", "size", "#alloc", "#free")
    124 		for _, s := range st.BySize {
    125 			fmt.Printf("%10d %10d %10d\n", s.Size, s.Mallocs, s.Frees)
    126 		}
    127 	*/
    128 	// Standard gotest benchmark output, collected by build dashboard.
    129 	gcstats("BenchmarkParser", *n, t1.Sub(t0))
    130 
    131 	if *serve != "" {
    132 		log.Fatal(http.ListenAndServe(*serve, nil))
    133 		println(lastParsed)
    134 	}
    135 }
    136 
    137 // find . -type d -not -path "./exp" -not -path "./exp/*" -printf "\t\"%p\",\n" | sort | sed "s/\.\///" | grep -v testdata
    138 var packages = []string{
    139 	"archive",
    140 	"archive/tar",
    141 	"archive/zip",
    142 	"bufio",
    143 	"builtin",
    144 	"bytes",
    145 	"compress",
    146 	"compress/bzip2",
    147 	"compress/flate",
    148 	"compress/gzip",
    149 	"compress/lzw",
    150 	"compress/zlib",
    151 	"container",
    152 	"container/heap",
    153 	"container/list",
    154 	"container/ring",
    155 	"crypto",
    156 	"crypto/aes",
    157 	"crypto/cipher",
    158 	"crypto/des",
    159 	"crypto/dsa",
    160 	"crypto/ecdsa",
    161 	"crypto/elliptic",
    162 	"crypto/hmac",
    163 	"crypto/md5",
    164 	"crypto/rand",
    165 	"crypto/rc4",
    166 	"crypto/rsa",
    167 	"crypto/sha1",
    168 	"crypto/sha256",
    169 	"crypto/sha512",
    170 	"crypto/subtle",
    171 	"crypto/tls",
    172 	"crypto/x509",
    173 	"crypto/x509/pkix",
    174 	"database",
    175 	"database/sql",
    176 	"database/sql/driver",
    177 	"debug",
    178 	"debug/dwarf",
    179 	"debug/elf",
    180 	"debug/gosym",
    181 	"debug/macho",
    182 	"debug/pe",
    183 	"encoding",
    184 	"encoding/ascii85",
    185 	"encoding/asn1",
    186 	"encoding/base32",
    187 	"encoding/base64",
    188 	"encoding/binary",
    189 	"encoding/csv",
    190 	"encoding/gob",
    191 	"encoding/hex",
    192 	"encoding/json",
    193 	"encoding/pem",
    194 	"encoding/xml",
    195 	"errors",
    196 	"expvar",
    197 	"flag",
    198 	"fmt",
    199 	"go",
    200 	"go/ast",
    201 	"go/build",
    202 	"go/doc",
    203 	"go/format",
    204 	"go/parser",
    205 	"go/printer",
    206 	"go/scanner",
    207 	"go/token",
    208 	"hash",
    209 	"hash/adler32",
    210 	"hash/crc32",
    211 	"hash/crc64",
    212 	"hash/fnv",
    213 	"html",
    214 	"html/template",
    215 	"image",
    216 	"image/color",
    217 	"image/draw",
    218 	"image/gif",
    219 	"image/jpeg",
    220 	"image/png",
    221 	"index",
    222 	"index/suffixarray",
    223 	"io",
    224 	"io/ioutil",
    225 	"log",
    226 	"log/syslog",
    227 	"math",
    228 	"math/big",
    229 	"math/cmplx",
    230 	"math/rand",
    231 	"mime",
    232 	"mime/multipart",
    233 	"net",
    234 	"net/http",
    235 	"net/http/cgi",
    236 	"net/http/cookiejar",
    237 	"net/http/fcgi",
    238 	"net/http/httptest",
    239 	"net/http/httputil",
    240 	"net/http/pprof",
    241 	"net/mail",
    242 	"net/rpc",
    243 	"net/rpc/jsonrpc",
    244 	"net/smtp",
    245 	"net/textproto",
    246 	"net/url",
    247 	"os",
    248 	"os/exec",
    249 	"os/signal",
    250 	"os/user",
    251 	"path",
    252 	"path/filepath",
    253 	"reflect",
    254 	"regexp",
    255 	"regexp/syntax",
    256 	"runtime",
    257 	"runtime/cgo",
    258 	"runtime/debug",
    259 	"runtime/pprof",
    260 	"runtime/race",
    261 	"sort",
    262 	"strconv",
    263 	"strings",
    264 	"sync",
    265 	"sync/atomic",
    266 	"syscall",
    267 	"testing",
    268 	"testing/iotest",
    269 	"testing/quick",
    270 	"text",
    271 	"text/scanner",
    272 	"text/tabwriter",
    273 	"text/template",
    274 	"text/template/parse",
    275 	"time",
    276 	"unicode",
    277 	"unicode/utf16",
    278 	"unicode/utf8",
    279 	"unsafe",
    280 }
    281