github.com/jgbaldwinbrown/perf@v0.1.1/benchstat/html.go (about)

     1  // Copyright 2017 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 benchstat
     6  
     7  import (
     8  	"bytes"
     9  	"strings"
    10  
    11  	"github.com/google/safehtml"
    12  	"github.com/google/safehtml/template"
    13  )
    14  
    15  var htmlTemplate = template.Must(template.New("").Funcs(htmlFuncs).Parse(`
    16  {{- if . -}}
    17  {{with index . 0}}
    18  <table class='benchstat {{if .OldNewDelta}}oldnew{{end}}'>
    19  {{if eq (len .Configs) 1}}
    20  {{- else -}}
    21  <tr class='configs'><th>{{range .Configs}}<th>{{.}}{{end}}
    22  {{end}}
    23  {{end}}
    24  {{- range $i, $table := .}}
    25  <tbody>
    26  {{if eq (len .Configs) 1}}
    27  <tr><th><th>{{.Metric}}
    28  {{else -}}
    29  <tr><th><th colspan='{{len .Configs}}' class='metric'>{{.Metric}}{{if .OldNewDelta}}<th>delta{{end}}
    30  {{end}}{{range $group := group $table.Rows -}}
    31  {{if and (gt (len $table.Groups) 1) (len (index . 0).Group)}}<tr class='group'><th colspan='{{colspan (len $table.Configs) $table.OldNewDelta}}'>{{(index . 0).Group}}{{end}}
    32  {{- range $row := . -}}
    33  {{if $table.OldNewDelta -}}
    34  <tr class='{{if eq .Change 1}}better{{else if eq .Change -1}}worse{{else}}unchanged{{end}}'>
    35  {{- else -}}
    36  <tr>
    37  {{- end -}}
    38  <td>{{.Benchmark}}{{range .Metrics}}<td>{{.Format $row.Scaler}}{{end}}{{if $table.OldNewDelta}}<td class='{{if eq .Delta "~"}}nodelta{{else}}delta{{end}}'>{{replace .Delta "-" "−" -1}}<td class='note'>{{.Note}}{{end}}
    39  {{end -}}
    40  {{- end -}}
    41  <tr><td>&nbsp;
    42  </tbody>
    43  {{end}}
    44  </table>
    45  {{end -}}
    46  `))
    47  
    48  var htmlFuncs = template.FuncMap{
    49  	"replace": strings.Replace,
    50  	"group":   htmlGroup,
    51  	"colspan": htmlColspan,
    52  }
    53  
    54  func htmlColspan(configs int, delta bool) int {
    55  	if delta {
    56  		configs++
    57  	}
    58  	return configs + 1
    59  }
    60  
    61  func htmlGroup(rows []*Row) (out [][]*Row) {
    62  	var group string
    63  	var cur []*Row
    64  	for _, r := range rows {
    65  		if r.Group != group {
    66  			group = r.Group
    67  			if len(cur) > 0 {
    68  				out = append(out, cur)
    69  				cur = nil
    70  			}
    71  		}
    72  		cur = append(cur, r)
    73  	}
    74  	if len(cur) > 0 {
    75  		out = append(out, cur)
    76  	}
    77  	return
    78  }
    79  
    80  // SafeFormatHTML returns the HTML formatting of the tables.
    81  func SafeFormatHTML(tables []*Table) safehtml.HTML {
    82  	h, err := htmlTemplate.ExecuteToHTML(tables)
    83  	if err != nil {
    84  		// Only possible errors here are template not matching data structure.
    85  		// Don't make caller check - it's our fault.
    86  		panic(err)
    87  	}
    88  	return h
    89  }
    90  
    91  // FormatHTML appends an HTML formatting of the tables to buf.
    92  func FormatHTML(buf *bytes.Buffer, tables []*Table) {
    93  	err := htmlTemplate.Execute(buf, tables)
    94  	if err != nil {
    95  		// Only possible errors here are template not matching data structure.
    96  		// Don't make caller check - it's our fault.
    97  		panic(err)
    98  	}
    99  }