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