1
0
mirror of https://github.com/golang/go synced 2024-09-24 23:20:12 -06:00
go/test/garbage/parser.go
Russ Cox d324f2143b runtime: parallelize garbage collector mark + sweep
Running test/garbage/parser.out.

On a 4-core Lenovo X201s (Linux):
31.12u 0.60s 31.74r 	 1 cpu, no atomics
32.27u 0.58s 32.86r 	 1 cpu, atomic instructions
33.04u 0.83s 27.47r 	 2 cpu

On a 16-core Xeon (Linux):
33.08u 0.65s 33.80r 	 1 cpu, no atomics
34.87u 1.12s 29.60r 	 2 cpu
36.00u 1.87s 28.43r 	 3 cpu
36.46u 2.34s 27.10r 	 4 cpu
38.28u 3.85s 26.92r 	 5 cpu
37.72u 5.25s 26.73r	 6 cpu
39.63u 7.11s 26.95r	 7 cpu
39.67u 8.10s 26.68r	 8 cpu

On a 2-core MacBook Pro Core 2 Duo 2.26 (circa 2009, MacBookPro5,5):
39.43u 1.45s 41.27r 	 1 cpu, no atomics
43.98u 2.95s 38.69r 	 2 cpu

On a 2-core Mac Mini Core 2 Duo 1.83 (circa 2008; Macmini2,1):
48.81u 2.12s 51.76r 	 1 cpu, no atomics
57.15u 4.72s 51.54r 	 2 cpu

The handoff algorithm is really only good for two cores.
Beyond that we will need to so something more sophisticated,
like have each core hand off to the next one, around a circle.
Even so, the code is a good checkpoint; for now we'll limit the
number of gc procs to at most 2.

R=dvyukov
CC=golang-dev
https://golang.org/cl/4641082
2011-09-30 09:40:01 -04:00

228 lines
4.7 KiB
Go

// 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"
"os"
"path"
"runtime"
"strings"
"time"
"http"
_ "http/pprof"
"log"
)
var serve = flag.String("serve", "", "serve http on this address at end")
func isGoFile(dir *os.FileInfo) bool {
return dir.IsRegular() &&
!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.String())
panic("fail")
}
return pkgs
}
func main() {
st := &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 int64
pkgroot := runtime.GOROOT() + "/src/pkg/"
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
st.PauseTotalNs = 0
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)])
}
if i+1 == *n && *serve != "" {
lastParsed = parsed
}
}
runtime.GC()
runtime.GC()
}
t1 := time.Nanoseconds()
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-t0)
if *serve != "" {
log.Fatal(http.ListenAndServe(*serve, nil))
println(lastParsed)
}
}
var packages = []string{
"archive/tar",
"asn1",
"big",
"bufio",
"bytes",
"cmath",
"compress/flate",
"compress/gzip",
"compress/zlib",
"container/heap",
"container/list",
"container/ring",
"container/vector",
"crypto/aes",
"crypto/blowfish",
"crypto/hmac",
"crypto/md4",
"crypto/md5",
"crypto/rand",
"crypto/rc4",
"crypto/rsa",
"crypto/sha1",
"crypto/sha256",
"crypto/sha512",
"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",
"hash/crc64",
"http",
"image",
"image/jpeg",
"image/png",
"io",
"io/ioutil",
"json",
"log",
"math",
"mime",
"net",
"os",
"os/signal",
"patch",
"path",
"rand",
"reflect",
"regexp",
"rpc",
"runtime",
"scanner",
"sort",
"smtp",
"strconv",
"strings",
"sync",
"syscall",
"syslog",
"tabwriter",
"template",
"testing",
"testing/iotest",
"testing/quick",
"testing/script",
"time",
"unicode",
"utf8",
"utf16",
"websocket",
"xml",
}