github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/dashboard/app/build/perf_graph.go (about)

     1  // Copyright 2013 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  // +build appengine
     6  
     7  package build
     8  
     9  import (
    10  	"bytes"
    11  	"fmt"
    12  	"html/template"
    13  	"net/http"
    14  	"strconv"
    15  
    16  	"appengine"
    17  	"appengine/datastore"
    18  )
    19  
    20  func init() {
    21  	handleFunc("/perfgraph", perfGraphHandler)
    22  }
    23  
    24  func perfGraphHandler(w http.ResponseWriter, r *http.Request) {
    25  	d := dashboardForRequest(r)
    26  	c := d.Context(appengine.NewContext(r))
    27  	pc, err := GetPerfConfig(c, r)
    28  	if err != nil {
    29  		logErr(w, r, err)
    30  		return
    31  	}
    32  	allBuilders := pc.BuildersForBenchmark("")
    33  	allBenchmarks := pc.BenchmarksForBuilder("")
    34  	allMetrics := pc.MetricsForBenchmark("")
    35  	allProcs := pc.ProcList("")
    36  	r.ParseForm()
    37  	selBuilders := r.Form["builder"]
    38  	selBenchmarks := r.Form["benchmark"]
    39  	selMetrics := r.Form["metric"]
    40  	selProcs := r.Form["procs"]
    41  	if len(selBuilders) == 0 {
    42  		selBuilders = append(selBuilders, allBuilders[0])
    43  	}
    44  	if len(selBenchmarks) == 0 {
    45  		selBenchmarks = append(selBenchmarks, "json")
    46  	}
    47  	if len(selMetrics) == 0 {
    48  		selMetrics = append(selMetrics, "time")
    49  	}
    50  	if len(selProcs) == 0 {
    51  		selProcs = append(selProcs, "1")
    52  	}
    53  	commitFrom := r.FormValue("commit-from")
    54  	if commitFrom == "" {
    55  		commitFrom = lastRelease
    56  	}
    57  	commitTo := r.FormValue("commit-to")
    58  	if commitTo == "" {
    59  		commitTo = "tip"
    60  	}
    61  	// TODO(dvyukov): validate input
    62  
    63  	// Figure out start and end commit from commitFrom/commitTo.
    64  	startCommitNum := 0
    65  	endCommitNum := 0
    66  	{
    67  		comFrom := &Commit{Hash: knownTags[commitFrom]}
    68  		if err := datastore.Get(c, comFrom.Key(c), comFrom); err != nil {
    69  			logErr(w, r, err)
    70  			return
    71  		}
    72  		startCommitNum = comFrom.Num
    73  
    74  	retry:
    75  		if commitTo == "tip" {
    76  			p, err := GetPackage(c, "")
    77  			if err != nil {
    78  				logErr(w, r, err)
    79  				return
    80  			}
    81  			endCommitNum = p.NextNum
    82  		} else {
    83  			comTo := &Commit{Hash: knownTags[commitTo]}
    84  			if err := datastore.Get(c, comTo.Key(c), comTo); err != nil {
    85  				logErr(w, r, err)
    86  				return
    87  			}
    88  			endCommitNum = comTo.Num + 1
    89  		}
    90  		if endCommitNum <= startCommitNum {
    91  			// User probably selected from:go1.3 to:go1.2. Fix go1.2 to tip.
    92  			if commitTo == "tip" {
    93  				logErr(w, r, fmt.Errorf("no commits to display (%v-%v)", commitFrom, commitTo))
    94  				return
    95  			}
    96  			commitTo = "tip"
    97  			goto retry
    98  		}
    99  	}
   100  	commitsToDisplay := endCommitNum - startCommitNum
   101  
   102  	present := func(set []string, s string) bool {
   103  		for _, s1 := range set {
   104  			if s1 == s {
   105  				return true
   106  			}
   107  		}
   108  		return false
   109  	}
   110  
   111  	cfg := &uiPerfConfig{}
   112  	for _, v := range allBuilders {
   113  		cfg.Builders = append(cfg.Builders, uiPerfConfigElem{v, present(selBuilders, v)})
   114  	}
   115  	for _, v := range allBenchmarks {
   116  		cfg.Benchmarks = append(cfg.Benchmarks, uiPerfConfigElem{v, present(selBenchmarks, v)})
   117  	}
   118  	for _, v := range allMetrics {
   119  		cfg.Metrics = append(cfg.Metrics, uiPerfConfigElem{v, present(selMetrics, v)})
   120  	}
   121  	for _, v := range allProcs {
   122  		cfg.Procs = append(cfg.Procs, uiPerfConfigElem{strconv.Itoa(v), present(selProcs, strconv.Itoa(v))})
   123  	}
   124  	for k := range knownTags {
   125  		cfg.CommitsFrom = append(cfg.CommitsFrom, uiPerfConfigElem{k, commitFrom == k})
   126  	}
   127  	for k := range knownTags {
   128  		cfg.CommitsTo = append(cfg.CommitsTo, uiPerfConfigElem{k, commitTo == k})
   129  	}
   130  	cfg.CommitsTo = append(cfg.CommitsTo, uiPerfConfigElem{"tip", commitTo == "tip"})
   131  
   132  	var vals [][]float64
   133  	var hints [][]string
   134  	var annotations [][]string
   135  	var certainty [][]bool
   136  	var headers []string
   137  	commits2, err := GetCommits(c, startCommitNum, commitsToDisplay)
   138  	if err != nil {
   139  		logErr(w, r, err)
   140  		return
   141  	}
   142  	for _, builder := range selBuilders {
   143  		for _, metric := range selMetrics {
   144  			for _, benchmark := range selBenchmarks {
   145  				for _, procs := range selProcs {
   146  					benchProcs := fmt.Sprintf("%v-%v", benchmark, procs)
   147  					vv, err := GetPerfMetricsForCommits(c, builder, benchProcs, metric, startCommitNum, commitsToDisplay)
   148  					if err != nil {
   149  						logErr(w, r, err)
   150  						return
   151  					}
   152  					hasdata := false
   153  					for _, v := range vv {
   154  						if v != 0 {
   155  							hasdata = true
   156  						}
   157  					}
   158  					if hasdata {
   159  						noise := pc.NoiseLevel(builder, benchProcs, metric)
   160  						descBuilder := "/" + builder
   161  						descBenchmark := "/" + benchProcs
   162  						descMetric := "/" + metric
   163  						if len(selBuilders) == 1 {
   164  							descBuilder = ""
   165  						}
   166  						if len(selBenchmarks) == 1 && len(selProcs) == 1 {
   167  							descBenchmark = ""
   168  						}
   169  						if len(selMetrics) == 1 && (len(selBuilders) > 1 || len(selBenchmarks) > 1 || len(selProcs) > 1) {
   170  							descMetric = ""
   171  						}
   172  						desc := fmt.Sprintf("%v%v%v", descBuilder, descBenchmark, descMetric)[1:]
   173  						hh := make([]string, commitsToDisplay)
   174  						ann := make([]string, commitsToDisplay)
   175  						valf := make([]float64, commitsToDisplay)
   176  						cert := make([]bool, commitsToDisplay)
   177  						firstval := uint64(0)
   178  						lastval := uint64(0)
   179  						for i, v := range vv {
   180  							cert[i] = true
   181  							if v == 0 {
   182  								if lastval == 0 {
   183  									continue
   184  								}
   185  								cert[i] = false
   186  								v = lastval
   187  							}
   188  							if firstval == 0 {
   189  								firstval = v
   190  							}
   191  							valf[i] = float64(v) / float64(firstval)
   192  							if cert[i] {
   193  								d := ""
   194  								if lastval != 0 {
   195  									diff := perfDiff(lastval, v)
   196  									d = fmt.Sprintf(" (%+.02f%%)", diff)
   197  									if !isNoise(diff, noise) {
   198  										ann[i] = fmt.Sprintf("%+.02f%%", diff)
   199  									}
   200  								}
   201  								hh[i] = fmt.Sprintf("%v%v", v, d)
   202  							} else {
   203  								hh[i] = "NO DATA"
   204  							}
   205  							lastval = v
   206  						}
   207  						vals = append(vals, valf)
   208  						hints = append(hints, hh)
   209  						annotations = append(annotations, ann)
   210  						certainty = append(certainty, cert)
   211  						headers = append(headers, desc)
   212  					}
   213  				}
   214  			}
   215  		}
   216  	}
   217  
   218  	var commits []perfGraphCommit
   219  	if len(vals) != 0 && len(vals[0]) != 0 {
   220  		idx := 0
   221  		for i := range vals[0] {
   222  			com := commits2[i]
   223  			if com == nil || !com.NeedsBenchmarking {
   224  				continue
   225  			}
   226  			c := perfGraphCommit{Id: idx, Name: fmt.Sprintf("%v (%v)", com.Desc, com.Time.Format("Jan 2, 2006 1:04"))}
   227  			idx++
   228  			for j := range vals {
   229  				c.Vals = append(c.Vals, perfGraphValue{float64(vals[j][i]), certainty[j][i], hints[j][i], annotations[j][i]})
   230  			}
   231  			commits = append(commits, c)
   232  		}
   233  	}
   234  
   235  	data := &perfGraphData{d, cfg, headers, commits}
   236  
   237  	var buf bytes.Buffer
   238  	if err := perfGraphTemplate.Execute(&buf, data); err != nil {
   239  		logErr(w, r, err)
   240  		return
   241  	}
   242  
   243  	buf.WriteTo(w)
   244  }
   245  
   246  var perfGraphTemplate = template.Must(
   247  	template.New("perf_graph.html").ParseFiles("build/perf_graph.html"),
   248  )
   249  
   250  type perfGraphData struct {
   251  	Dashboard *Dashboard
   252  	Config    *uiPerfConfig
   253  	Headers   []string
   254  	Commits   []perfGraphCommit
   255  }
   256  
   257  type perfGraphCommit struct {
   258  	Id   int
   259  	Name string
   260  	Vals []perfGraphValue
   261  }
   262  
   263  type perfGraphValue struct {
   264  	Val       float64
   265  	Certainty bool
   266  	Hint      string
   267  	Ann       string
   268  }