github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/dashboard/app/build/perf_learn.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  	"sort"
    15  
    16  	"appengine"
    17  	"appengine/datastore"
    18  )
    19  
    20  func init() {
    21  	handleFunc("/perflearn", perfLearnHandler)
    22  }
    23  
    24  const (
    25  	learnPercentile       = 0.95
    26  	learnSignalMultiplier = 1.1
    27  	learnMinSignal        = 0.5
    28  )
    29  
    30  func perfLearnHandler(w http.ResponseWriter, r *http.Request) {
    31  	d := dashboardForRequest(r)
    32  	c := d.Context(appengine.NewContext(r))
    33  
    34  	pc, err := GetPerfConfig(c, r)
    35  	if err != nil {
    36  		logErr(w, r, err)
    37  		return
    38  	}
    39  
    40  	p, err := GetPackage(c, "")
    41  	if err != nil {
    42  		logErr(w, r, err)
    43  		return
    44  	}
    45  
    46  	update := r.FormValue("update") != ""
    47  	noise := make(map[string]string)
    48  
    49  	data := &perfLearnData{}
    50  
    51  	commits, err := GetCommits(c, 0, p.NextNum)
    52  	if err != nil {
    53  		logErr(w, r, err)
    54  		return
    55  	}
    56  
    57  	for _, builder := range pc.BuildersForBenchmark("") {
    58  		for _, benchmark := range pc.BenchmarksForBuilder(builder) {
    59  			for _, metric := range pc.MetricsForBenchmark(benchmark) {
    60  				for _, procs := range pc.ProcList(builder) {
    61  					values, err := GetPerfMetricsForCommits(c, builder, fmt.Sprintf("%v-%v", benchmark, procs), metric, 0, p.NextNum)
    62  					if err != nil {
    63  						logErr(w, r, err)
    64  						return
    65  					}
    66  					var dd []float64
    67  					last := uint64(0)
    68  					for i, v := range values {
    69  						if v == 0 {
    70  							if com := commits[i]; com == nil || com.NeedsBenchmarking {
    71  								last = 0
    72  							}
    73  							continue
    74  						}
    75  						if last != 0 {
    76  							v1 := v
    77  							if v1 < last {
    78  								v1, last = last, v1
    79  							}
    80  							diff := float64(v1)/float64(last)*100 - 100
    81  							dd = append(dd, diff)
    82  						}
    83  						last = v
    84  					}
    85  					if len(dd) == 0 {
    86  						continue
    87  					}
    88  					sort.Float64s(dd)
    89  
    90  					baseIdx := int(float64(len(dd)) * learnPercentile)
    91  					baseVal := dd[baseIdx]
    92  					signalVal := baseVal * learnSignalMultiplier
    93  					if signalVal < learnMinSignal {
    94  						signalVal = learnMinSignal
    95  					}
    96  					signalIdx := -1
    97  					noiseNum := 0
    98  					signalNum := 0
    99  
   100  					var diffs []*perfLearnDiff
   101  					for i, d := range dd {
   102  						if d > 3*signalVal {
   103  							d = 3 * signalVal
   104  						}
   105  						diffs = append(diffs, &perfLearnDiff{Num: i, Val: d})
   106  						if signalIdx == -1 && d >= signalVal {
   107  							signalIdx = i
   108  						}
   109  						if d < signalVal {
   110  							noiseNum++
   111  						} else {
   112  							signalNum++
   113  						}
   114  					}
   115  					diffs[baseIdx].Hint = "95%"
   116  					if signalIdx != -1 {
   117  						diffs[signalIdx].Hint = "signal"
   118  					}
   119  					diffs = diffs[len(diffs)*4/5:]
   120  					name := fmt.Sprintf("%v/%v-%v/%v", builder, benchmark, procs, metric)
   121  					data.Entries = append(data.Entries, &perfLearnEntry{len(data.Entries), name, baseVal, noiseNum, signalVal, signalNum, diffs})
   122  
   123  					if len(dd) >= 100 || r.FormValue("force") != "" {
   124  						nname := fmt.Sprintf("%v|%v-%v", builder, benchmark, procs)
   125  						n := noise[nname] + fmt.Sprintf("|%v=%.2f", metric, signalVal)
   126  						noise[nname] = n
   127  					}
   128  				}
   129  			}
   130  		}
   131  	}
   132  
   133  	if update {
   134  		var noiseLevels []string
   135  		for k, v := range noise {
   136  			noiseLevels = append(noiseLevels, k+v)
   137  		}
   138  		tx := func(c appengine.Context) error {
   139  			pc, err := GetPerfConfig(c, r)
   140  			if err != nil {
   141  				return err
   142  			}
   143  			pc.NoiseLevels = noiseLevels
   144  			if _, err := datastore.Put(c, PerfConfigKey(c), pc); err != nil {
   145  				return fmt.Errorf("putting PerfConfig: %v", err)
   146  			}
   147  			return nil
   148  		}
   149  		if err := datastore.RunInTransaction(c, tx, nil); err != nil {
   150  			logErr(w, r, err)
   151  			return
   152  		}
   153  	}
   154  
   155  	var buf bytes.Buffer
   156  	if err := perfLearnTemplate.Execute(&buf, data); err != nil {
   157  		logErr(w, r, err)
   158  		return
   159  	}
   160  
   161  	buf.WriteTo(w)
   162  }
   163  
   164  var perfLearnTemplate = template.Must(
   165  	template.New("perf_learn.html").Funcs(tmplFuncs).ParseFiles("build/perf_learn.html"),
   166  )
   167  
   168  type perfLearnData struct {
   169  	Entries []*perfLearnEntry
   170  }
   171  
   172  type perfLearnEntry struct {
   173  	Num       int
   174  	Name      string
   175  	BaseVal   float64
   176  	NoiseNum  int
   177  	SignalVal float64
   178  	SignalNum int
   179  	Diffs     []*perfLearnDiff
   180  }
   181  
   182  type perfLearnDiff struct {
   183  	Num  int
   184  	Val  float64
   185  	Hint string
   186  }