// +build ignore,OMIT package main import ( "fmt" "go/ast" "go/parser" "go/token" "io/ioutil" "path/filepath" "runtime" "sort" "strings" "time" ) func walk(dir string, f func(string) bool) bool { fis, err := ioutil.ReadDir(dir) if err != nil { panic(err) } // parse all *.go files in directory; // traverse subdirectories, but don't walk into testdata for _, fi := range fis { path := filepath.Join(dir, fi.Name()) if fi.IsDir() { if fi.Name() != "testdata" { if !walk(path, f) { return false } } } else if strings.HasSuffix(fi.Name(), ".go") && !strings.HasPrefix(fi.Name(), ".") { if !f(path) { return false } } } return true } func walkStdLib(f func(filename string) bool) { walk(filepath.Join(runtime.GOROOT(), "src"), f) } type histogram map[string]int func (h histogram) add(filename string) { f, err := parser.ParseFile(token.NewFileSet(), filename, nil, 0) if err != nil { panic(err) } ast.Inspect(f, func(n ast.Node) bool { if n, ok := n.(ast.Stmt); ok { h[fmt.Sprintf("%T", n)]++ } return true }) } // merge START OMIT func (h histogram) merge(h1 histogram) { for key, count := range h1 { h[key] = h[key] + count } } // merge END OMIT type entry struct { key string count int } func (h histogram) print() { var list []entry var total int for key, count := range h { list = append(list, entry{key, count}) total += count } sort.Sort(byCount(list)) percent := 100 / float64(total) for i, e := range list { fmt.Printf("%4d. %5.2f%% %5d %s\n", i, float64(e.count)*percent, e.count, e.key) } } type byCount []entry func (s byCount) Len() int { return len(s) } func (s byCount) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s byCount) Less(i, j int) bool { x, y := s[i], s[j] if x.count != y.count { return x.count > y.count // want larger count first } return x.key < y.key } func init() { n := runtime.NumCPU() //fmt.Println(n, "cores") runtime.GOMAXPROCS(n) } // main START OMIT func main() { start := time.Now() ch := make(chan histogram) count := 0 // goroutine count walkStdLib(func(filename string) bool { count++ // mapper START OMIT go func() { h := make(histogram) h.add(filename) ch <- h }() // mapper END OMIT return true }) // reducer START OMIT h := make(histogram) for count > 0 { h.merge(<-ch) count-- } // reducer END OMIT h.print() fmt.Println(time.Since(start)) } // main END OMIT