github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/dashboard/app/build/perf_detail.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  	"strconv"
    16  	"strings"
    17  
    18  	"appengine"
    19  	"appengine/datastore"
    20  )
    21  
    22  func init() {
    23  	handleFunc("/perfdetail", perfDetailUIHandler)
    24  }
    25  
    26  func perfDetailUIHandler(w http.ResponseWriter, r *http.Request) {
    27  	d := dashboardForRequest(r)
    28  	c := d.Context(appengine.NewContext(r))
    29  	pc, err := GetPerfConfig(c, r)
    30  	if err != nil {
    31  		logErr(w, r, err)
    32  		return
    33  	}
    34  
    35  	kind := r.FormValue("kind")
    36  	builder := r.FormValue("builder")
    37  	benchmark := r.FormValue("benchmark")
    38  	if kind == "" {
    39  		kind = "benchmark"
    40  	}
    41  	if kind != "benchmark" && kind != "builder" {
    42  		logErr(w, r, fmt.Errorf("unknown kind %s", kind))
    43  		return
    44  	}
    45  
    46  	// Fetch the new commit.
    47  	com1 := new(Commit)
    48  	com1.Hash = r.FormValue("commit")
    49  	if hash, ok := knownTags[com1.Hash]; ok {
    50  		com1.Hash = hash
    51  	}
    52  	if err := datastore.Get(c, com1.Key(c), com1); err != nil {
    53  		logErr(w, r, fmt.Errorf("failed to fetch commit %s: %v", com1.Hash, err))
    54  		return
    55  	}
    56  	// Fetch the associated perf result.
    57  	ress1 := &PerfResult{CommitHash: com1.Hash}
    58  	if err := datastore.Get(c, ress1.Key(c), ress1); err != nil {
    59  		logErr(w, r, fmt.Errorf("failed to fetch perf result %s: %v", com1.Hash, err))
    60  		return
    61  	}
    62  
    63  	// Fetch the old commit.
    64  	var ress0 *PerfResult
    65  	com0 := new(Commit)
    66  	com0.Hash = r.FormValue("commit0")
    67  	if hash, ok := knownTags[com0.Hash]; ok {
    68  		com0.Hash = hash
    69  	}
    70  	if com0.Hash != "" {
    71  		// Have an exact commit hash, fetch directly.
    72  		if err := datastore.Get(c, com0.Key(c), com0); err != nil {
    73  			logErr(w, r, fmt.Errorf("failed to fetch commit %s: %v", com0.Hash, err))
    74  			return
    75  		}
    76  		ress0 = &PerfResult{CommitHash: com0.Hash}
    77  		if err := datastore.Get(c, ress0.Key(c), ress0); err != nil {
    78  			logErr(w, r, fmt.Errorf("failed to fetch perf result for %s: %v", com0.Hash, err))
    79  			return
    80  		}
    81  	} else {
    82  		// Don't have the commit hash, find the previous commit to compare.
    83  		rc := MakePerfResultCache(c, com1, false)
    84  		ress0, err = rc.NextForComparison(com1.Num, "")
    85  		if err != nil {
    86  			logErr(w, r, err)
    87  			return
    88  		}
    89  		if ress0 == nil {
    90  			logErr(w, r, fmt.Errorf("no previous commit with results"))
    91  			return
    92  		}
    93  		// Now that we know the right result, fetch the commit.
    94  		com0.Hash = ress0.CommitHash
    95  		if err := datastore.Get(c, com0.Key(c), com0); err != nil {
    96  			logErr(w, r, fmt.Errorf("failed to fetch commit %s: %v", com0.Hash, err))
    97  			return
    98  		}
    99  	}
   100  
   101  	res0 := ress0.ParseData()
   102  	res1 := ress1.ParseData()
   103  	var benchmarks []*uiPerfDetailBenchmark
   104  	var list []string
   105  	if kind == "builder" {
   106  		list = pc.BenchmarksForBuilder(builder)
   107  	} else {
   108  		list = pc.BuildersForBenchmark(benchmark)
   109  	}
   110  	for _, other := range list {
   111  		if kind == "builder" {
   112  			benchmark = other
   113  		} else {
   114  			builder = other
   115  		}
   116  		var procs []*uiPerfDetailProcs
   117  		allProcs := pc.ProcList(builder)
   118  		for _, p := range allProcs {
   119  			BenchProcs := fmt.Sprintf("%v-%v", benchmark, p)
   120  			if res0[builder] == nil || res0[builder][BenchProcs] == nil {
   121  				continue
   122  			}
   123  			pp := &uiPerfDetailProcs{Procs: p}
   124  			for metric, val := range res0[builder][BenchProcs].Metrics {
   125  				var pm uiPerfDetailMetric
   126  				pm.Name = metric
   127  				pm.Val0 = fmt.Sprintf("%v", val)
   128  				val1 := uint64(0)
   129  				if res1[builder] != nil && res1[builder][BenchProcs] != nil {
   130  					val1 = res1[builder][BenchProcs].Metrics[metric]
   131  				}
   132  				pm.Val1 = fmt.Sprintf("%v", val1)
   133  				v0 := val
   134  				v1 := val1
   135  				valf := perfDiff(v0, v1)
   136  				pm.Delta = fmt.Sprintf("%+.2f%%", valf)
   137  				pm.Style = perfChangeStyle(pc, valf, builder, BenchProcs, pm.Name)
   138  				pp.Metrics = append(pp.Metrics, pm)
   139  			}
   140  			sort.Sort(pp.Metrics)
   141  			for artifact, hash := range res0[builder][BenchProcs].Artifacts {
   142  				var pm uiPerfDetailMetric
   143  				pm.Val0 = fmt.Sprintf("%v", artifact)
   144  				pm.Link0 = fmt.Sprintf("log/%v", hash)
   145  				pm.Val1 = fmt.Sprintf("%v", artifact)
   146  				if res1[builder] != nil && res1[builder][BenchProcs] != nil && res1[builder][BenchProcs].Artifacts[artifact] != "" {
   147  					pm.Link1 = fmt.Sprintf("log/%v", res1[builder][BenchProcs].Artifacts[artifact])
   148  				}
   149  				pp.Metrics = append(pp.Metrics, pm)
   150  			}
   151  			procs = append(procs, pp)
   152  		}
   153  		benchmarks = append(benchmarks, &uiPerfDetailBenchmark{other, procs})
   154  	}
   155  
   156  	cfg := new(uiPerfConfig)
   157  	for _, v := range pc.BuildersForBenchmark("") {
   158  		cfg.Builders = append(cfg.Builders, uiPerfConfigElem{v, v == builder})
   159  	}
   160  	for _, v := range pc.BenchmarksForBuilder("") {
   161  		cfg.Benchmarks = append(cfg.Benchmarks, uiPerfConfigElem{v, v == benchmark})
   162  	}
   163  
   164  	data := &uiPerfDetailTemplateData{d, cfg, kind == "builder", com0, com1, benchmarks}
   165  
   166  	var buf bytes.Buffer
   167  	if err := uiPerfDetailTemplate.Execute(&buf, data); err != nil {
   168  		logErr(w, r, err)
   169  		return
   170  	}
   171  
   172  	buf.WriteTo(w)
   173  }
   174  
   175  func perfResultSplit(s string) (builder string, benchmark string, procs int) {
   176  	s1 := strings.Split(s, "|")
   177  	s2 := strings.Split(s1[1], "-")
   178  	procs, _ = strconv.Atoi(s2[1])
   179  	return s1[0], s2[0], procs
   180  }
   181  
   182  type uiPerfDetailTemplateData struct {
   183  	Dashboard   *Dashboard
   184  	Config      *uiPerfConfig
   185  	KindBuilder bool
   186  	Commit0     *Commit
   187  	Commit1     *Commit
   188  	Benchmarks  []*uiPerfDetailBenchmark
   189  }
   190  
   191  type uiPerfDetailBenchmark struct {
   192  	Name  string
   193  	Procs []*uiPerfDetailProcs
   194  }
   195  
   196  type uiPerfDetailProcs struct {
   197  	Procs   int
   198  	Metrics uiPerfDetailMetrics
   199  }
   200  
   201  type uiPerfDetailMetric struct {
   202  	Name  string
   203  	Val0  string
   204  	Val1  string
   205  	Link0 string
   206  	Link1 string
   207  	Delta string
   208  	Style string
   209  }
   210  
   211  type uiPerfDetailMetrics []uiPerfDetailMetric
   212  
   213  func (l uiPerfDetailMetrics) Len() int           { return len(l) }
   214  func (l uiPerfDetailMetrics) Swap(i, j int)      { l[i], l[j] = l[j], l[i] }
   215  func (l uiPerfDetailMetrics) Less(i, j int) bool { return l[i].Name < l[j].Name }
   216  
   217  var uiPerfDetailTemplate = template.Must(
   218  	template.New("perf_detail.html").Funcs(tmplFuncs).ParseFiles("build/perf_detail.html"),
   219  )