go.tools/cmd/gotype: parse in parallel

Performance increase is much smaller than expected;
need to investigate. Possibly, repeatedly (for each
line) accessing file sets from multiple goroutines
(in the scanner) is a bottle neck; or perhaps i/o.

R=adonovan
CC=golang-dev
https://golang.org/cl/23090043
This commit is contained in:
Robert Griesemer 2013-11-07 13:32:02 -08:00
parent f1e5b03c6e
commit 0c141425f6
2 changed files with 47 additions and 12 deletions

View File

@ -29,10 +29,12 @@ The flags are:
verbose mode verbose mode
Debugging flags: Debugging flags:
-seq
parse sequentially, rather than in parallel
-ast -ast
print AST print AST (forces -seq)
-trace -trace
print parse trace print parse trace (forces -seq)
-comments -comments
parse comments (ignored unless -ast or -trace is provided) parse comments (ignored unless -ast or -trace is provided)

View File

@ -15,6 +15,7 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"runtime"
"time" "time"
"code.google.com/p/go.tools/go/types" "code.google.com/p/go.tools/go/types"
@ -27,8 +28,9 @@ var (
verbose = flag.Bool("v", false, "verbose mode") verbose = flag.Bool("v", false, "verbose mode")
// debugging support // debugging support
printAST = flag.Bool("ast", false, "print AST") sequential = flag.Bool("seq", false, "parse sequentially, rather than in parallel")
printTrace = flag.Bool("trace", false, "print parse trace") printAST = flag.Bool("ast", false, "print AST (forces -seq)")
printTrace = flag.Bool("trace", false, "print parse trace (forces -seq)")
parseComments = flag.Bool("comments", false, "parse comments (ignored unless -ast or -trace is provided)") parseComments = flag.Bool("comments", false, "parse comments (ignored unless -ast or -trace is provided)")
) )
@ -78,11 +80,12 @@ func report(err error) {
errorCount++ errorCount++
} }
// parse may be called concurrently
func parse(filename string, src interface{}) (*ast.File, error) { func parse(filename string, src interface{}) (*ast.File, error) {
if *verbose { if *verbose {
fmt.Println(filename) fmt.Println(filename)
} }
file, err := parser.ParseFile(fset, filename, src, parserMode) file, err := parser.ParseFile(fset, filename, src, parserMode) // ok to access fset concurrently
if *printAST { if *printAST {
ast.Print(fset, file) ast.Print(fset, file)
} }
@ -98,14 +101,39 @@ func parseStdin() (*ast.File, error) {
} }
func parseFiles(filenames []string) ([]*ast.File, error) { func parseFiles(filenames []string) ([]*ast.File, error) {
var files []*ast.File files := make([]*ast.File, len(filenames))
for _, filename := range filenames {
file, err := parse(filename, nil) if *sequential {
for i, filename := range filenames {
var err error
files[i], err = parse(filename, nil)
if err != nil { if err != nil {
return nil, err return nil, err // leave unfinished goroutines hanging
} }
files = append(files, file)
} }
} else {
type parseResult struct {
file *ast.File
err error
}
out := make(chan parseResult)
for _, filename := range filenames {
go func(filename string) {
file, err := parse(filename, nil)
out <- parseResult{file, err}
}(filename)
}
for i := range filenames {
res := <-out
if res.err != nil {
return nil, res.err // leave unfinished goroutines hanging
}
files[i] = res.file
}
}
return files, nil return files, nil
} }
@ -131,7 +159,6 @@ func parseDir(dirname string) ([]*ast.File, error) {
func getPkgFiles(args []string) ([]*ast.File, error) { func getPkgFiles(args []string) ([]*ast.File, error) {
if len(args) == 0 { if len(args) == 0 {
// stdin // stdin
var file *ast.File
file, err := parseStdin() file, err := parseStdin()
if err != nil { if err != nil {
return nil, err return nil, err
@ -196,10 +223,16 @@ func printStats(d time.Duration) {
} }
func main() { func main() {
runtime.GOMAXPROCS(runtime.NumCPU()) // remove this once runtime is smarter
flag.Usage = usage flag.Usage = usage
flag.Parse() flag.Parse()
if *printAST || *printTrace {
*sequential = true
}
initParserMode() initParserMode()
initSizes() initSizes()
start := time.Now() start := time.Now()
files, err := getPkgFiles(flag.Args()) files, err := getPkgFiles(flag.Args())