github.com/aclements/go-misc@v0.0.0-20240129233631-2f6ede80790c/benchplot/table.go (about) 1 // Copyright 2016 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "math" 9 "reflect" 10 "sort" 11 "strings" 12 "time" 13 14 "github.com/aclements/go-gg/table" 15 "github.com/aclements/go-misc/bench" 16 ) 17 18 func benchmarksToTable(bs []*bench.Benchmark) (t *table.Table, configCols, resultCols []string) { 19 // Gather name, config, and result columns. 20 nan := math.NaN() 21 names := make([]string, len(bs)) 22 configs, results := map[string]reflect.Value{}, map[string][]float64{} 23 for i, b := range bs { 24 names[i] = b.Name 25 26 for k, c := range b.Config { 27 seq, ok := configs[k] 28 if !ok { 29 t := reflect.SliceOf(reflect.TypeOf(c.Value)) 30 seq = reflect.MakeSlice(t, len(bs), len(bs)) 31 configs[k] = seq 32 } 33 seq.Index(i).Set(reflect.ValueOf(c.Value)) 34 } 35 36 for k, v := range b.Result { 37 seq, ok := results[k] 38 if !ok { 39 seq = make([]float64, len(bs)) 40 for i := range seq { 41 seq[i] = nan 42 } 43 results[k] = seq 44 } 45 seq[i] = v 46 } 47 } 48 49 // Build table. 50 tab := new(table.Builder).Add("name", names) 51 52 keys := make([]string, 0, len(configs)) 53 for k := range configs { 54 keys = append(keys, k) 55 } 56 sort.Strings(keys) 57 for _, key := range keys { 58 nicekey := strings.Replace(key, "-", " ", -1) 59 niceval := configs[key].Interface() 60 if n, ok := niceval.([]time.Time); ok { 61 niceval = byTime(n) 62 } 63 64 tab.Add(nicekey, niceval) 65 configCols = append(configCols, nicekey) 66 } 67 68 keys = make([]string, 0, len(results)) 69 for k := range results { 70 keys = append(keys, k) 71 } 72 sort.Strings(keys) 73 for _, key := range keys { 74 nicekey := strings.Replace(key, "-", " ", -1) 75 if nicekey == "ns/op" { 76 // TODO: Use the unit parser from benchstat. 77 nicekey = "time/op" 78 durations := make([]time.Duration, len(results[key])) 79 for i, x := range results[key] { 80 durations[i] = time.Duration(x) 81 } 82 tab.Add(nicekey, durations) 83 } else { 84 tab.Add(nicekey, results[key]) 85 } 86 resultCols = append(resultCols, nicekey) 87 } 88 89 return tab.Done(), configCols, resultCols 90 } 91 92 func commitsToTable(commits []CommitInfo) *table.Table { 93 hashCol := make([]string, len(commits)) 94 authorDateCol := make(byTime, len(commits)) 95 commitDateCol := make(byTime, len(commits)) 96 branchCol := make([]string, len(commits)) 97 j := 0 98 for i := range commits { 99 ci := &commits[i] 100 101 hashCol[j] = ci.Hash 102 authorDateCol[j] = ci.AuthorDate 103 commitDateCol[j] = ci.CommitDate 104 branchCol[j] = ci.Branch 105 j++ 106 } 107 108 return new(table.Builder). 109 Add("commit", hashCol). 110 Add("author date", authorDateCol). 111 Add("commit date", commitDateCol). 112 Add("branch", branchCol). 113 Done() 114 } 115 116 type byTime []time.Time 117 118 func (s byTime) Len() int { 119 return len(s) 120 } 121 122 func (s byTime) Less(i, j int) bool { 123 return s[i].Before(s[j]) 124 } 125 126 func (s byTime) Swap(i, j int) { 127 s[i], s[j] = s[j], s[i] 128 }