github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/talks/2014/taste/histop.go (about) 1 // +build OMIT 2 3 package main 4 5 import ( 6 "fmt" 7 "go/ast" 8 "go/parser" 9 "go/token" 10 "io/ioutil" 11 "path/filepath" 12 "runtime" 13 "sort" 14 "strings" 15 "time" 16 ) 17 18 func walk(dir string, f func(string) bool) bool { 19 fis, err := ioutil.ReadDir(dir) 20 if err != nil { 21 panic(err) 22 } 23 // parse all *.go files in directory; 24 // traverse subdirectories, but don't walk into testdata 25 for _, fi := range fis { 26 path := filepath.Join(dir, fi.Name()) 27 if fi.IsDir() { 28 if fi.Name() != "testdata" { 29 if !walk(path, f) { 30 return false 31 } 32 } 33 } else if strings.HasSuffix(fi.Name(), ".go") && !strings.HasPrefix(fi.Name(), ".") { 34 if !f(path) { 35 return false 36 } 37 } 38 } 39 return true 40 } 41 42 func walkStdLib(f func(filename string) bool) { 43 walk(filepath.Join(runtime.GOROOT(), "src"), f) 44 } 45 46 type histogram map[string]int 47 48 func (h histogram) add(filename string) { 49 f, err := parser.ParseFile(token.NewFileSet(), filename, nil, 0) 50 if err != nil { 51 panic(err) 52 } 53 54 ast.Inspect(f, func(n ast.Node) bool { 55 if n, ok := n.(ast.Stmt); ok { 56 h[fmt.Sprintf("%T", n)]++ 57 } 58 return true 59 }) 60 } 61 62 // merge START OMIT 63 func (h histogram) merge(h1 histogram) { 64 for key, count := range h1 { 65 h[key] = h[key] + count 66 } 67 } 68 69 // merge END OMIT 70 71 type entry struct { 72 key string 73 count int 74 } 75 76 func (h histogram) print() { 77 var list []entry 78 var total int 79 for key, count := range h { 80 list = append(list, entry{key, count}) 81 total += count 82 } 83 sort.Sort(byCount(list)) 84 85 percent := 100 / float64(total) 86 for i, e := range list { 87 fmt.Printf("%4d. %5.2f%% %5d %s\n", i, float64(e.count)*percent, e.count, e.key) 88 } 89 } 90 91 type byCount []entry 92 93 func (s byCount) Len() int { return len(s) } 94 func (s byCount) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 95 func (s byCount) Less(i, j int) bool { 96 x, y := s[i], s[j] 97 if x.count != y.count { 98 return x.count > y.count // want larger count first 99 } 100 return x.key < y.key 101 } 102 103 func init() { 104 n := runtime.NumCPU() 105 //fmt.Println(n, "cores") 106 runtime.GOMAXPROCS(n) 107 } 108 109 // main START OMIT 110 func main() { 111 start := time.Now() 112 ch := make(chan histogram) 113 count := 0 // goroutine count 114 walkStdLib(func(filename string) bool { 115 count++ 116 // mapper START OMIT 117 go func() { 118 h := make(histogram) 119 h.add(filename) 120 ch <- h 121 }() 122 // mapper END OMIT 123 return true 124 }) 125 126 // reducer START OMIT 127 h := make(histogram) 128 for count > 0 { 129 h.merge(<-ch) 130 count-- 131 } 132 // reducer END OMIT 133 134 h.print() 135 fmt.Println(time.Since(start)) 136 } 137 138 // main END OMIT