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  }