| // Copyright 2010 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| // Garbage collection benchmark: parse Go packages repeatedly. | |
| package main | |
| import ( | |
| "flag" | |
| "fmt" | |
| "go/ast" | |
| "go/parser" | |
| "go/token" | |
| "log" | |
| "net/http" | |
| _ "net/http/pprof" | |
| "os" | |
| "path" | |
| "runtime" | |
| "strings" | |
| "time" | |
| ) | |
| var serve = flag.String("serve", "", "serve http on this address at end") | |
| func isGoFile(dir os.FileInfo) bool { | |
| return !dir.IsDir() && | |
| !strings.HasPrefix(dir.Name(), ".") && // ignore .files | |
| path.Ext(dir.Name()) == ".go" | |
| } | |
| func isPkgFile(dir os.FileInfo) bool { | |
| return isGoFile(dir) && | |
| !strings.HasSuffix(dir.Name(), "_test.go") // ignore test files | |
| } | |
| func pkgName(filename string) string { | |
| file, err := parser.ParseFile(token.NewFileSet(), filename, nil, parser.PackageClauseOnly) | |
| if err != nil || file == nil { | |
| return "" | |
| } | |
| return file.Name.Name | |
| } | |
| func parseDir(dirpath string) map[string]*ast.Package { | |
| // the package name is the directory name within its parent | |
| // (use dirname instead of path because dirname is clean; i.e. has no trailing '/') | |
| _, pkgname := path.Split(dirpath) | |
| // filter function to select the desired .go files | |
| filter := func(d os.FileInfo) bool { | |
| if isPkgFile(d) { | |
| // Some directories contain main packages: Only accept | |
| // files that belong to the expected package so that | |
| // parser.ParsePackage doesn't return "multiple packages | |
| // found" errors. | |
| // Additionally, accept the special package name | |
| // fakePkgName if we are looking at cmd documentation. | |
| name := pkgName(dirpath + "/" + d.Name()) | |
| return name == pkgname | |
| } | |
| return false | |
| } | |
| // get package AST | |
| pkgs, err := parser.ParseDir(token.NewFileSet(), dirpath, filter, parser.ParseComments) | |
| if err != nil { | |
| println("parse", dirpath, err.Error()) | |
| panic("fail") | |
| } | |
| return pkgs | |
| } | |
| func main() { | |
| st := new(runtime.MemStats) | |
| packages = append(packages, packages...) | |
| packages = append(packages, packages...) | |
| n := flag.Int("n", 4, "iterations") | |
| p := flag.Int("p", len(packages), "# of packages to keep in memory") | |
| flag.BoolVar(&st.DebugGC, "d", st.DebugGC, "print GC debugging info (pause times)") | |
| flag.Parse() | |
| var lastParsed []map[string]*ast.Package | |
| var t0 time.Time | |
| var numGC uint32 | |
| var pauseTotalNs uint64 | |
| pkgroot := runtime.GOROOT() + "/src/" | |
| for pass := 0; pass < 2; pass++ { | |
| // Once the heap is grown to full size, reset counters. | |
| // This hides the start-up pauses, which are much smaller | |
| // than the normal pauses and would otherwise make | |
| // the average look much better than it actually is. | |
| runtime.ReadMemStats(st) | |
| numGC = st.NumGC | |
| pauseTotalNs = st.PauseTotalNs | |
| t0 = time.Now() | |
| for i := 0; i < *n; i++ { | |
| parsed := make([]map[string]*ast.Package, *p) | |
| for j := range parsed { | |
| parsed[j] = parseDir(pkgroot + packages[j%len(packages)]) | |
| } | |
| if i+1 == *n && *serve != "" { | |
| lastParsed = parsed | |
| } | |
| } | |
| runtime.GC() | |
| runtime.GC() | |
| } | |
| t1 := time.Now() | |
| runtime.ReadMemStats(st) | |
| st.NumGC -= numGC | |
| st.PauseTotalNs -= pauseTotalNs | |
| fmt.Printf("Alloc=%d/%d Heap=%d Mallocs=%d PauseTime=%.3f/%d = %.3f\n", | |
| st.Alloc, st.TotalAlloc, | |
| st.Sys, | |
| st.Mallocs, float64(st.PauseTotalNs)/1e9, | |
| st.NumGC, float64(st.PauseTotalNs)/1e9/float64(st.NumGC)) | |
| /* | |
| fmt.Printf("%10s %10s %10s\n", "size", "#alloc", "#free") | |
| for _, s := range st.BySize { | |
| fmt.Printf("%10d %10d %10d\n", s.Size, s.Mallocs, s.Frees) | |
| } | |
| */ | |
| // Standard gotest benchmark output, collected by build dashboard. | |
| gcstats("BenchmarkParser", *n, t1.Sub(t0)) | |
| if *serve != "" { | |
| log.Fatal(http.ListenAndServe(*serve, nil)) | |
| println(lastParsed) | |
| } | |
| } | |
| // find . -type d -not -path "./exp" -not -path "./exp/*" -printf "\t\"%p\",\n" | sort | sed "s/\.\///" | grep -v testdata | |
| var packages = []string{ | |
| "archive", | |
| "archive/tar", | |
| "archive/zip", | |
| "bufio", | |
| "builtin", | |
| "bytes", | |
| "compress", | |
| "compress/bzip2", | |
| "compress/flate", | |
| "compress/gzip", | |
| "compress/lzw", | |
| "compress/zlib", | |
| "container", | |
| "container/heap", | |
| "container/list", | |
| "container/ring", | |
| "crypto", | |
| "crypto/aes", | |
| "crypto/cipher", | |
| "crypto/des", | |
| "crypto/dsa", | |
| "crypto/ecdsa", | |
| "crypto/elliptic", | |
| "crypto/hmac", | |
| "crypto/md5", | |
| "crypto/rand", | |
| "crypto/rc4", | |
| "crypto/rsa", | |
| "crypto/sha1", | |
| "crypto/sha256", | |
| "crypto/sha512", | |
| "crypto/subtle", | |
| "crypto/tls", | |
| "crypto/x509", | |
| "crypto/x509/pkix", | |
| "database", | |
| "database/sql", | |
| "database/sql/driver", | |
| "debug", | |
| "debug/dwarf", | |
| "debug/elf", | |
| "debug/gosym", | |
| "debug/macho", | |
| "debug/pe", | |
| "encoding", | |
| "encoding/ascii85", | |
| "encoding/asn1", | |
| "encoding/base32", | |
| "encoding/base64", | |
| "encoding/binary", | |
| "encoding/csv", | |
| "encoding/gob", | |
| "encoding/hex", | |
| "encoding/json", | |
| "encoding/pem", | |
| "encoding/xml", | |
| "errors", | |
| "expvar", | |
| "flag", | |
| "fmt", | |
| "go", | |
| "go/ast", | |
| "go/build", | |
| "go/doc", | |
| "go/format", | |
| "go/parser", | |
| "go/printer", | |
| "go/scanner", | |
| "go/token", | |
| "hash", | |
| "hash/adler32", | |
| "hash/crc32", | |
| "hash/crc64", | |
| "hash/fnv", | |
| "html", | |
| "html/template", | |
| "image", | |
| "image/color", | |
| "image/draw", | |
| "image/gif", | |
| "image/jpeg", | |
| "image/png", | |
| "index", | |
| "index/suffixarray", | |
| "io", | |
| "io/ioutil", | |
| "log", | |
| "log/syslog", | |
| "math", | |
| "math/big", | |
| "math/cmplx", | |
| "math/rand", | |
| "mime", | |
| "mime/multipart", | |
| "net", | |
| "net/http", | |
| "net/http/cgi", | |
| "net/http/cookiejar", | |
| "net/http/fcgi", | |
| "net/http/httptest", | |
| "net/http/httputil", | |
| "net/http/pprof", | |
| "net/mail", | |
| "net/rpc", | |
| "net/rpc/jsonrpc", | |
| "net/smtp", | |
| "net/textproto", | |
| "net/url", | |
| "os", | |
| "os/exec", | |
| "os/signal", | |
| "os/user", | |
| "path", | |
| "path/filepath", | |
| "reflect", | |
| "regexp", | |
| "regexp/syntax", | |
| "runtime", | |
| "runtime/cgo", | |
| "runtime/debug", | |
| "runtime/pprof", | |
| "runtime/race", | |
| "sort", | |
| "strconv", | |
| "strings", | |
| "sync", | |
| "sync/atomic", | |
| "syscall", | |
| "testing", | |
| "testing/iotest", | |
| "testing/quick", | |
| "text", | |
| "text/scanner", | |
| "text/tabwriter", | |
| "text/template", | |
| "text/template/parse", | |
| "time", | |
| "unicode", | |
| "unicode/utf16", | |
| "unicode/utf8", | |
| "unsafe", | |
| } |