2010-02-08 15:32:22 -07:00
|
|
|
// 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"
|
2011-01-19 11:41:42 -07:00
|
|
|
"go/token"
|
2010-02-08 15:32:22 -07:00
|
|
|
"os"
|
|
|
|
"path"
|
|
|
|
"runtime"
|
|
|
|
"strings"
|
2010-02-09 14:33:00 -07:00
|
|
|
"time"
|
2011-01-19 11:41:42 -07:00
|
|
|
"http"
|
|
|
|
_ "http/pprof"
|
|
|
|
"log"
|
2010-02-08 15:32:22 -07:00
|
|
|
)
|
|
|
|
|
2011-01-19 11:41:42 -07:00
|
|
|
var serve = flag.String("serve", "", "serve http on this address at end")
|
|
|
|
|
2010-04-12 19:10:29 -06:00
|
|
|
func isGoFile(dir *os.FileInfo) bool {
|
2010-02-08 15:32:22 -07:00
|
|
|
return dir.IsRegular() &&
|
|
|
|
!strings.HasPrefix(dir.Name, ".") && // ignore .files
|
|
|
|
path.Ext(dir.Name) == ".go"
|
|
|
|
}
|
|
|
|
|
2010-04-12 19:10:29 -06:00
|
|
|
func isPkgFile(dir *os.FileInfo) bool {
|
2010-02-08 15:32:22 -07:00
|
|
|
return isGoFile(dir) &&
|
|
|
|
!strings.HasSuffix(dir.Name, "_test.go") // ignore test files
|
|
|
|
}
|
|
|
|
|
|
|
|
func pkgName(filename string) string {
|
2011-01-19 11:41:42 -07:00
|
|
|
file, err := parser.ParseFile(token.NewFileSet(), filename, nil, parser.PackageClauseOnly)
|
2010-02-08 15:32:22 -07:00
|
|
|
if err != nil || file == nil {
|
|
|
|
return ""
|
|
|
|
}
|
2010-09-07 07:55:05 -06:00
|
|
|
return file.Name.Name
|
2010-02-08 15:32:22 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2010-04-12 19:10:29 -06:00
|
|
|
filter := func(d *os.FileInfo) bool {
|
2010-02-08 15:32:22 -07:00
|
|
|
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
|
2011-01-19 11:41:42 -07:00
|
|
|
pkgs, err := parser.ParseDir(token.NewFileSet(), dirpath, filter, parser.ParseComments)
|
2010-02-08 15:32:22 -07:00
|
|
|
if err != nil {
|
2011-11-01 20:06:05 -06:00
|
|
|
println("parse", dirpath, err.Error())
|
2010-03-24 17:46:53 -06:00
|
|
|
panic("fail")
|
2010-02-08 15:32:22 -07:00
|
|
|
}
|
|
|
|
return pkgs
|
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
st := &runtime.MemStats
|
2011-01-19 11:41:42 -07:00
|
|
|
packages = append(packages, packages...)
|
|
|
|
packages = append(packages, packages...)
|
2010-02-09 14:33:00 -07:00
|
|
|
n := flag.Int("n", 4, "iterations")
|
2010-02-08 15:32:22 -07:00
|
|
|
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()
|
|
|
|
|
2011-01-19 11:41:42 -07:00
|
|
|
var lastParsed []map[string]*ast.Package
|
2010-02-09 14:33:00 -07:00
|
|
|
var t0 int64
|
2010-08-18 08:08:49 -06:00
|
|
|
pkgroot := runtime.GOROOT() + "/src/pkg/"
|
2010-02-09 14:33:00 -07:00
|
|
|
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.
|
|
|
|
st.NumGC = 0
|
2011-01-19 11:41:42 -07:00
|
|
|
st.PauseTotalNs = 0
|
2010-02-09 14:33:00 -07:00
|
|
|
t0 = time.Nanoseconds()
|
|
|
|
|
|
|
|
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)])
|
|
|
|
}
|
2011-01-19 11:41:42 -07:00
|
|
|
if i+1 == *n && *serve != "" {
|
|
|
|
lastParsed = parsed
|
|
|
|
}
|
2010-02-08 15:32:22 -07:00
|
|
|
}
|
2010-02-09 14:33:00 -07:00
|
|
|
runtime.GC()
|
2011-01-19 11:41:42 -07:00
|
|
|
runtime.GC()
|
2010-02-08 15:32:22 -07:00
|
|
|
}
|
2010-02-09 14:33:00 -07:00
|
|
|
t1 := time.Nanoseconds()
|
2010-02-08 15:32:22 -07:00
|
|
|
|
2010-04-12 19:10:29 -06:00
|
|
|
fmt.Printf("Alloc=%d/%d Heap=%d Mallocs=%d PauseTime=%.3f/%d = %.3f\n",
|
2010-02-08 15:32:22 -07:00
|
|
|
st.Alloc, st.TotalAlloc,
|
2010-04-12 19:10:29 -06:00
|
|
|
st.Sys,
|
2011-01-19 11:41:42 -07:00
|
|
|
st.Mallocs, float64(st.PauseTotalNs)/1e9,
|
|
|
|
st.NumGC, float64(st.PauseTotalNs)/1e9/float64(st.NumGC))
|
2010-02-09 14:33:00 -07:00
|
|
|
|
2011-01-19 11:41:42 -07:00
|
|
|
/*
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
*/
|
2010-02-09 14:33:00 -07:00
|
|
|
// Standard gotest benchmark output, collected by build dashboard.
|
2011-01-19 11:41:42 -07:00
|
|
|
gcstats("BenchmarkParser", *n, t1-t0)
|
|
|
|
|
|
|
|
if *serve != "" {
|
2011-02-01 13:47:35 -07:00
|
|
|
log.Fatal(http.ListenAndServe(*serve, nil))
|
2011-01-19 11:41:42 -07:00
|
|
|
println(lastParsed)
|
|
|
|
}
|
2010-02-08 15:32:22 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
var packages = []string{
|
|
|
|
"archive/tar",
|
|
|
|
"asn1",
|
|
|
|
"big",
|
|
|
|
"bufio",
|
|
|
|
"bytes",
|
2010-04-19 16:41:40 -06:00
|
|
|
"cmath",
|
2010-02-08 15:32:22 -07:00
|
|
|
"compress/flate",
|
|
|
|
"compress/gzip",
|
|
|
|
"compress/zlib",
|
|
|
|
"container/heap",
|
|
|
|
"container/list",
|
|
|
|
"container/ring",
|
|
|
|
"container/vector",
|
|
|
|
"crypto/aes",
|
2010-04-19 16:41:40 -06:00
|
|
|
"crypto/blowfish",
|
2010-02-08 15:32:22 -07:00
|
|
|
"crypto/hmac",
|
|
|
|
"crypto/md4",
|
|
|
|
"crypto/md5",
|
2010-04-19 16:41:40 -06:00
|
|
|
"crypto/rand",
|
2010-02-08 15:32:22 -07:00
|
|
|
"crypto/rc4",
|
|
|
|
"crypto/rsa",
|
|
|
|
"crypto/sha1",
|
|
|
|
"crypto/sha256",
|
2010-04-19 16:41:40 -06:00
|
|
|
"crypto/sha512",
|
2010-02-08 15:32:22 -07:00
|
|
|
"crypto/subtle",
|
|
|
|
"crypto/tls",
|
|
|
|
"crypto/x509",
|
|
|
|
"crypto/xtea",
|
|
|
|
"debug/dwarf",
|
|
|
|
"debug/macho",
|
|
|
|
"debug/elf",
|
|
|
|
"debug/gosym",
|
|
|
|
"ebnf",
|
|
|
|
"encoding/ascii85",
|
|
|
|
"encoding/base64",
|
|
|
|
"encoding/binary",
|
|
|
|
"encoding/git85",
|
|
|
|
"encoding/hex",
|
|
|
|
"encoding/pem",
|
|
|
|
"exec",
|
|
|
|
"exp/datafmt",
|
|
|
|
"expvar",
|
|
|
|
"flag",
|
|
|
|
"fmt",
|
|
|
|
"go/ast",
|
|
|
|
"go/doc",
|
|
|
|
"go/parser",
|
|
|
|
"go/printer",
|
|
|
|
"go/scanner",
|
|
|
|
"go/token",
|
|
|
|
"gob",
|
|
|
|
"hash",
|
|
|
|
"hash/adler32",
|
|
|
|
"hash/crc32",
|
2010-04-19 16:41:40 -06:00
|
|
|
"hash/crc64",
|
2010-02-08 15:32:22 -07:00
|
|
|
"http",
|
|
|
|
"image",
|
|
|
|
"image/jpeg",
|
|
|
|
"image/png",
|
|
|
|
"io",
|
|
|
|
"io/ioutil",
|
|
|
|
"json",
|
|
|
|
"log",
|
|
|
|
"math",
|
2010-04-19 16:41:40 -06:00
|
|
|
"mime",
|
2010-02-08 15:32:22 -07:00
|
|
|
"net",
|
|
|
|
"os",
|
|
|
|
"os/signal",
|
|
|
|
"patch",
|
|
|
|
"path",
|
|
|
|
"rand",
|
|
|
|
"reflect",
|
|
|
|
"regexp",
|
|
|
|
"rpc",
|
|
|
|
"runtime",
|
|
|
|
"scanner",
|
|
|
|
"sort",
|
2011-01-19 11:41:42 -07:00
|
|
|
"smtp",
|
2010-02-08 15:32:22 -07:00
|
|
|
"strconv",
|
|
|
|
"strings",
|
|
|
|
"sync",
|
|
|
|
"syscall",
|
|
|
|
"syslog",
|
|
|
|
"tabwriter",
|
|
|
|
"template",
|
|
|
|
"testing",
|
|
|
|
"testing/iotest",
|
|
|
|
"testing/quick",
|
|
|
|
"testing/script",
|
|
|
|
"time",
|
|
|
|
"unicode",
|
|
|
|
"utf8",
|
2010-04-19 16:41:40 -06:00
|
|
|
"utf16",
|
2010-02-08 15:32:22 -07:00
|
|
|
"websocket",
|
|
|
|
"xml",
|
|
|
|
}
|