Showing preview only (1,199K chars total). Download the full file or copy to clipboard to get everything.
Repository: aclements/go-misc
Branch: master
Commit: 86e6001a23dd
Files: 270
Total size: 1.1 MB
Directory structure:
gitextract_zuo9c5tu/
├── LICENSE
├── abi/
│ ├── abi.go
│ ├── go.mod
│ └── go.sum
├── bench/
│ ├── parse.go
│ ├── parse_test.go
│ └── print.go
├── benchcmd/
│ ├── main.go
│ ├── rss_nounix.go
│ └── rss_unix.go
├── benchmany/
│ ├── benchmany.go
│ ├── commits.go
│ ├── readlog.go
│ ├── run.go
│ ├── run_test.go
│ ├── signal_notunix.go
│ ├── signal_unix.go
│ └── status.go
├── benchplot/
│ ├── git.go
│ ├── kza.go
│ ├── kza_test.go
│ ├── main.go
│ ├── plot.go
│ ├── table.go
│ └── vendor/
│ ├── github.com/
│ │ └── aclements/
│ │ ├── go-gg/
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ ├── generic/
│ │ │ │ ├── doc.go
│ │ │ │ ├── error.go
│ │ │ │ ├── order.go
│ │ │ │ └── slice/
│ │ │ │ ├── concat.go
│ │ │ │ ├── concat_test.go
│ │ │ │ ├── convert.go
│ │ │ │ ├── convert_test.go
│ │ │ │ ├── cycle.go
│ │ │ │ ├── doc.go
│ │ │ │ ├── find.go
│ │ │ │ ├── index.go
│ │ │ │ ├── min.go
│ │ │ │ ├── min_test.go
│ │ │ │ ├── nub.go
│ │ │ │ ├── select_test.go
│ │ │ │ ├── seq.go
│ │ │ │ ├── sort.go
│ │ │ │ └── util_test.go
│ │ │ ├── gg/
│ │ │ │ ├── example_scale_test.go
│ │ │ │ ├── facet.go
│ │ │ │ ├── group.go
│ │ │ │ ├── layer.go
│ │ │ │ ├── layout/
│ │ │ │ │ ├── grid.go
│ │ │ │ │ └── layout.go
│ │ │ │ ├── layout.go
│ │ │ │ ├── mark.go
│ │ │ │ ├── package.go
│ │ │ │ ├── plot.go
│ │ │ │ ├── render.go
│ │ │ │ ├── scale.go
│ │ │ │ ├── stepmode_string.go
│ │ │ │ ├── testmain.go
│ │ │ │ ├── text.go
│ │ │ │ └── transform.go
│ │ │ ├── ggstat/
│ │ │ │ ├── agg.go
│ │ │ │ ├── bin.go
│ │ │ │ ├── common.go
│ │ │ │ ├── density.go
│ │ │ │ ├── domain.go
│ │ │ │ ├── ecdf.go
│ │ │ │ ├── fn.go
│ │ │ │ ├── loess.go
│ │ │ │ ├── lsquares.go
│ │ │ │ └── normalize.go
│ │ │ ├── palette/
│ │ │ │ ├── blend.go
│ │ │ │ ├── brewer/
│ │ │ │ │ ├── brewer.go
│ │ │ │ │ ├── colorbrewer.json
│ │ │ │ │ ├── genbrewer.go
│ │ │ │ │ └── package.go
│ │ │ │ ├── makesrgbtab.go
│ │ │ │ ├── palette.go
│ │ │ │ ├── srgb.go
│ │ │ │ ├── srgbtab.go
│ │ │ │ └── viridis.go
│ │ │ └── table/
│ │ │ ├── concat.go
│ │ │ ├── filter.go
│ │ │ ├── group.go
│ │ │ ├── head.go
│ │ │ ├── join.go
│ │ │ ├── map.go
│ │ │ ├── new.go
│ │ │ ├── new_test.go
│ │ │ ├── pivot.go
│ │ │ ├── pivot_test.go
│ │ │ ├── print.go
│ │ │ ├── print_test.go
│ │ │ ├── sort.go
│ │ │ ├── table.go
│ │ │ └── table_test.go
│ │ └── go-moremath/
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── cmd/
│ │ │ └── dist/
│ │ │ ├── dist.go
│ │ │ └── plot.go
│ │ ├── fit/
│ │ │ ├── loess.go
│ │ │ ├── loess_test.go
│ │ │ ├── lsquares.go
│ │ │ └── package.go
│ │ ├── internal/
│ │ │ └── mathtest/
│ │ │ └── mathtest.go
│ │ ├── mathx/
│ │ │ ├── beta.go
│ │ │ ├── beta_test.go
│ │ │ ├── choose.go
│ │ │ ├── gamma.go
│ │ │ ├── gamma_test.go
│ │ │ ├── package.go
│ │ │ └── sign.go
│ │ ├── scale/
│ │ │ ├── err.go
│ │ │ ├── interface.go
│ │ │ ├── linear.go
│ │ │ ├── linear_test.go
│ │ │ ├── log.go
│ │ │ ├── log_test.go
│ │ │ ├── package.go
│ │ │ ├── ticks.go
│ │ │ ├── ticks_test.go
│ │ │ └── util.go
│ │ ├── stats/
│ │ │ ├── alg.go
│ │ │ ├── deltadist.go
│ │ │ ├── dist.go
│ │ │ ├── dist_test.go
│ │ │ ├── hist.go
│ │ │ ├── hypergdist.go
│ │ │ ├── hypergdist_test.go
│ │ │ ├── kde.go
│ │ │ ├── kde_test.go
│ │ │ ├── kdeboundarymethod_string.go
│ │ │ ├── kdekernel_string.go
│ │ │ ├── linearhist.go
│ │ │ ├── locationhypothesis_string.go
│ │ │ ├── loghist.go
│ │ │ ├── normaldist.go
│ │ │ ├── normaldist_test.go
│ │ │ ├── package.go
│ │ │ ├── sample.go
│ │ │ ├── sample_test.go
│ │ │ ├── stream.go
│ │ │ ├── tdist.go
│ │ │ ├── tdist_test.go
│ │ │ ├── ttest.go
│ │ │ ├── ttest_test.go
│ │ │ ├── udist.go
│ │ │ ├── udist_test.go
│ │ │ ├── utest.go
│ │ │ ├── utest_test.go
│ │ │ └── util_test.go
│ │ └── vec/
│ │ ├── package.go
│ │ └── vec.go
│ └── update
├── benchscripts/
│ ├── bench-many
│ ├── benchstat2
│ ├── plot-time
│ └── plot-time-2
├── buildstats/
│ ├── alg.go
│ ├── go.mod
│ ├── go.sum
│ ├── main.go
│ ├── rev.go
│ └── timeflag.go
├── cl-fetch/
│ └── main.go
├── dashquery/
│ ├── compile.go
│ ├── compile_test.go
│ ├── main.go
│ └── xdg.go
├── findflakes/
│ ├── adtest.go
│ ├── flaketest.go
│ ├── geodist.go
│ ├── html.go
│ ├── logs.go
│ ├── main.go
│ ├── paths.go
│ ├── text.go
│ └── xdg.go
├── findtypes/
│ └── main.go
├── foreachplatform/
│ ├── go.mod
│ └── main.go
├── gc-S/
│ ├── go.mod
│ └── main.go
├── gcdense/
│ └── test.py
├── git-p/
│ ├── gerrit.go
│ ├── git.go
│ ├── go.mod
│ ├── go.sum
│ ├── main.go
│ ├── pager.go
│ ├── shell.go
│ └── style.go
├── go-weave/
│ ├── amb/
│ │ ├── det.go
│ │ ├── progress.go
│ │ ├── rand.go
│ │ └── run.go
│ ├── models/
│ │ ├── cl20858.go
│ │ ├── issue16083.go
│ │ ├── markterm.go
│ │ ├── maxtree.go
│ │ ├── rescan.go
│ │ ├── rwmutex.go
│ │ └── yuasa.go
│ └── weave/
│ ├── atomic.go
│ ├── mutex.go
│ ├── sema.go
│ ├── tls.go
│ ├── trace.go
│ ├── waitgroup.go
│ └── weave.go
├── go.mod
├── go.sum
├── goi/
│ └── main.go
├── gover/
│ ├── cache.go
│ ├── gover.go
│ └── shutil.go
├── greplogs/
│ └── main.go
├── internal/
│ └── loganal/
│ ├── classify.go
│ ├── doc.go
│ ├── failure.go
│ └── matcher.go
├── minutes3/
│ ├── README.md
│ ├── gdoc.go
│ ├── gdoc_test.go
│ ├── github.go
│ ├── go.mod
│ ├── go.sum
│ ├── minutes.go
│ ├── oauth.go
│ └── tables.go
├── pcvaluetab/
│ ├── README.md
│ ├── alt.go
│ ├── alt_test.go
│ ├── bench_test.go
│ ├── dist.go
│ ├── enc.go
│ ├── go.mod
│ ├── go.sum
│ ├── main.go
│ ├── read.go
│ └── symtab.go
├── ptype/
│ └── main.go
├── rtanalysis/
│ ├── directives/
│ │ └── analysis.go
│ ├── main.go
│ └── systemstack/
│ └── analysis.go
├── scanpagemap.go
├── split/
│ ├── README.md
│ ├── bench_test.go
│ ├── example_id_test.go
│ ├── example_rwmutex_test.go
│ ├── examples_test.go
│ ├── stub.s
│ ├── value.go
│ └── vlogger_test.go
├── srgb/
│ └── main.go
├── stackmapcompress.py
├── stress2/
│ ├── cmd.go
│ ├── cmd_test.go
│ ├── go.mod
│ ├── go.sum
│ ├── main.go
│ ├── reporter.go
│ ├── signal_notunix.go
│ ├── signal_unix.go
│ ├── stress.go
│ └── stress_test.go
├── varint/
│ ├── README.md
│ ├── asm_amd64.s
│ ├── bench_test.go
│ └── varint.go
└── whichtest/
└── whichtest
================================================
FILE CONTENTS
================================================
================================================
FILE: LICENSE
================================================
Copyright (c) 2015 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: abi/abi.go
================================================
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
// To analyze kubelet:
//
// ( X=$PWD; cd -q ~/s/kubernetes && $X/abi $(go list -deps ./cmd/kubelet) )
import (
"flag"
"fmt"
"go/types"
"io"
"log"
"math"
"os"
"reflect"
"sort"
"golang.org/x/tools/go/packages"
)
const (
minIntRegs = 0
maxIntRegs = 16
// The number of floating-point registers has little
// effect. Just fix it at 8.
minFloatRegs = 8
maxFloatRegs = 8
// Comparison mode.
modeCompare = false
)
func main() {
flag.Parse()
pkgPaths := flag.Args()
// Get the package count to give the user some feedback.
cfg := &packages.Config{}
cfg.Mode = packages.NeedName
pkgs, err := packages.Load(cfg, pkgPaths...)
if err != nil {
log.Fatal(err)
}
if packages.PrintErrors(pkgs) > 0 {
os.Exit(1)
}
fmt.Fprintf(os.Stderr, "checking %d packages...\n", len(pkgs))
// Parse and type-check the packages.
cfg.Mode = packages.NeedName | packages.NeedTypes | packages.NeedTypesInfo | packages.NeedTypesSizes
pkgs, err = packages.Load(cfg, pkgPaths...)
if err != nil {
log.Fatal(err)
}
if packages.PrintErrors(pkgs) > 0 {
os.Exit(1)
}
// Extract all the functions.
var funcs []*types.Func
var sizes types.Sizes
for _, pkg := range pkgs {
sizes = pkg.TypesSizes
for _, obj := range pkg.TypesInfo.Defs {
if obj, ok := obj.(*types.Func); ok {
funcs = append(funcs, obj)
}
}
}
// Analyze.
qtiles := []float64{0.5, 0.95, 0.99}
qtileLabels := []string{"p50", "p95", "p99"}
table := [][]interface{}{
{"", "", "", "stack args", "spills", "stack total"},
{"ints", "floats", "% fit", qtileLabels, qtileLabels, qtileLabels},
}
if modeCompare {
qtiles = []float64{0.5, 0.95, 0.99, 1.0}
qtileLabels = []string{"p50", "p95", "p99", "max"}
table = [][]interface{}{
{"", "", "", "", "Δ stack bytes"},
{"ints", "floats", "Δ % fit", "diff", qtileLabels, "% bigger"},
}
}
opts := ABIOptions{
EmptyArray: true,
OneArray: true,
SplitArrays: false,
IgnoreBlank: false,
SpillRegs: false,
EmptyOnStack: true,
}
cmp := opts
cmp.ABI0 = true
const infinity = math.MaxInt32
analyze := func(opts, cmp ABIOptions) {
var stackBytes []int
var spillBytes []int
var stackTotal []int
var overheads []int // Stack bytes vs ABI0
fit := 0 // # functions that fit entirely in registers
cmpFit := 0
cmpDiff := 0 // # functions with any frame difference
cmpLarger := 0 // # functions with larger stack frames in cmp
for _, f := range funcs {
sig := f.Type().(*types.Signature)
frame := opts.Assign(sig, sizes)
stackBytes = append(stackBytes, frame.StackBytes)
spillBytes = append(spillBytes, frame.StackSpillBytes)
stackTotal = append(stackTotal, frame.StackTotal)
if frame.StackBytes == 0 {
fit++
}
if modeCompare {
// Compare to alternate options.
frameCmp := cmp.Assign(sig, sizes)
overhead := frameCmp.StackTotal - frame.StackTotal
overheads = append(overheads, overhead)
if frameCmp.StackBytes == 0 {
cmpFit++
}
if frame != frameCmp {
cmpDiff++
}
if overhead > 0 {
cmpLarger++
}
}
}
row := []interface{}{opts.IntRegs, opts.FloatRegs}
if opts.IntRegs == infinity {
row[0] = "∞"
}
if opts.FloatRegs == infinity {
row[1] = "∞"
}
if modeCompare {
pct := func(n int) string {
return fmt.Sprintf("%5.2f%%", 100*float64(n)/float64(len(funcs)))
}
row = append(row, pct(cmpFit-fit))
row = append(row, []interface{}{cmpDiff, pct(cmpDiff)})
row = append(row, intQuantiles(overheads, qtiles...))
row = append(row, pct(cmpLarger))
} else {
row = append(row, fmt.Sprintf("%4.1f%%", 100*float64(fit)/float64(len(funcs))))
row = append(row, intQuantiles(stackBytes, qtiles...))
row = append(row, intQuantiles(spillBytes, qtiles...))
row = append(row, intQuantiles(stackTotal, qtiles...))
}
table = append(table, row)
}
analyze(opts, cmp)
for opts.IntRegs = minIntRegs; opts.IntRegs <= maxIntRegs; opts.IntRegs++ {
for opts.FloatRegs = minFloatRegs; opts.FloatRegs <= maxFloatRegs; opts.FloatRegs++ {
cmp.IntRegs, cmp.FloatRegs = opts.IntRegs, opts.FloatRegs
analyze(opts, cmp)
}
}
opts.IntRegs, opts.FloatRegs = infinity, maxFloatRegs
cmp.IntRegs, cmp.FloatRegs = opts.IntRegs, opts.FloatRegs
analyze(opts, cmp)
// Print results.
printTable(os.Stdout, table)
}
type ABIOptions struct {
IntRegs, FloatRegs int
ABI0 bool // Use ABI0 (other options are ignored)
EmptyArray bool // Empty arrays don't stack-assign
OneArray bool // Size-1 arrays don't stack-assign
SplitArrays bool // Stack-assign arrays separately from rest of arg
IgnoreBlank bool // Skip assigning blank fields
SpillRegs bool // Structure spill space as register words
EmptyOnStack bool // Stack-assign zero-sized values
}
type frameBuilder struct {
opts *ABIOptions
sizes types.Sizes
ptrSize int
ints, floats int
Frame
}
type Frame struct {
ArgInts, ArgFloats int
ResInts, ResFloats int
StackBytes int // Stack bytes without spill slots
StackSpillBytes int // Stack bytes of spill slots
StackTotal int // Stack bytes for complete argument frame.
}
func (a *ABIOptions) Assign(sig *types.Signature, sizes types.Sizes) Frame {
ptrSize := int(sizes.Sizeof(types.Typ[types.Uintptr]))
f := frameBuilder{opts: a, sizes: sizes, ptrSize: ptrSize}
// Arguments
if r := sig.Recv(); r != nil {
f.AddArg(r.Type(), true)
}
ps := sig.Params()
for i := 0; i < ps.Len(); i++ {
f.AddArg(ps.At(i).Type(), true)
}
f.ArgInts, f.ArgFloats = f.ints, f.floats
f.StackBytes = align(f.StackBytes, ptrSize)
f.StackSpillBytes = align(f.StackSpillBytes, ptrSize)
// Results
f.ints, f.floats = 0, 0
rs := sig.Results()
for i := 0; i < rs.Len(); i++ {
f.AddArg(rs.At(i).Type(), false)
}
f.StackBytes = align(f.StackBytes, ptrSize)
f.ResInts, f.ResFloats = f.ints, f.floats
f.StackTotal = f.StackBytes + f.StackSpillBytes
return f.Frame
}
func (f *frameBuilder) AddArg(arg types.Type, needsSpill bool) {
if f.opts.ABI0 {
f.StackAssign(arg)
return
}
si, sf, sb := f.ints, f.floats, f.StackBytes
if f.RegAssign(arg, true) {
if needsSpill {
// Assign spill space.
if f.opts.SpillRegs {
f.StackSpillBytes += (f.ints-si)*f.ptrSize + (f.floats-sf)*8
} else {
f.StackSpillBytes = align(f.StackSpillBytes, int(f.sizes.Alignof(arg)))
f.StackSpillBytes += int(f.sizes.Sizeof(arg))
}
}
} else {
// Stack-assign the whole thing.
f.ints, f.floats, f.StackBytes = si, sf, sb
f.StackAssign(arg)
}
}
func (f *frameBuilder) RegAssign(arg types.Type, top bool) bool {
switch arg := arg.(type) {
default:
log.Fatal("unknown type: ", arg)
return false
case *types.Named:
return f.RegAssign(arg.Underlying(), top)
case *types.Array:
if f.opts.EmptyArray && arg.Len() == 0 {
// Special-case empty arrays.
return true
}
if f.opts.OneArray && arg.Len() == 1 {
// Special-case length-1 arrays.
return f.RegAssign(arg.Elem(), false)
}
if f.opts.SplitArrays {
// Arrays can go on the stack without failing
// the whole argument.
f.StackAssign(arg)
return true
} else {
// Arrays fail the whole argument.
return false
}
case *types.Struct:
for i := 0; i < arg.NumFields(); i++ {
if f.opts.IgnoreBlank && arg.Field(i).Name() == "_" {
continue
}
if !f.RegAssign(arg.Field(i).Type(), false) {
return false
}
}
case *types.Basic:
switch arg.Kind() {
case types.Bool, types.Int, types.Int8, types.Int16, types.Int32, types.Int64,
types.Uint, types.Uint8, types.Uint16, types.Uint32, types.Uint64, types.Uintptr:
// TODO: 64-bit on 32-bit arch needs two regs.
f.ints++
case types.Float32, types.Float64:
f.floats++
case types.Complex64, types.Complex128:
f.floats += 2
case types.String:
f.ints += 2
case types.UnsafePointer:
f.ints++
default:
log.Fatal("unknown basic kind: ", arg)
}
case *types.Chan, *types.Map, *types.Pointer, *types.Signature:
// These are all represented as a single pointer word.
f.ints++
case *types.Interface:
// Two pointer words.
f.ints += 2
case *types.Slice:
// One pointer word plus two scalar words.
f.ints += 3
}
// Check for out-of-registers.
return f.ints <= f.opts.IntRegs && f.floats <= f.opts.FloatRegs
}
func (f *frameBuilder) StackAssign(arg types.Type) {
f.StackBytes = align(f.StackBytes, int(f.sizes.Alignof(arg)))
f.StackBytes += int(f.sizes.Sizeof(arg))
}
func align(x, n int) int {
return (x + n - 1) &^ (n - 1)
}
func intQuantiles(xs []int, qs ...float64) []int {
sort.Ints(xs)
vs := make([]int, 0, len(qs))
for _, q := range qs {
i := int(q * float64(len(xs)))
if i < 0 {
i = 0
} else if i >= len(xs) {
i = len(xs) - 1
}
vs = append(vs, xs[i])
}
return vs
}
func floatQuantiles(xs []float64, qs ...float64) []float64 {
sort.Float64s(xs)
vs := make([]float64, 0, len(qs))
for _, q := range qs {
i := int(q * float64(len(xs)))
if i < 0 {
i = 0
} else if i >= len(xs) {
i = len(xs)
}
vs = append(vs, xs[i])
}
return vs
}
func printTable(w io.Writer, table [][]interface{}) {
type layoutNode struct {
w int
children []*layoutNode
}
type cellKey struct {
row int
col *layoutNode
}
// Stringify cells and construct layout
cells := make(map[cellKey]string)
layout := &layoutNode{}
var walk func(ri int, row reflect.Value, node *layoutNode) int
walk = func(ri int, row reflect.Value, node *layoutNode) int {
if row.Kind() == reflect.Interface {
row = row.Elem()
}
if row.Kind() != reflect.Slice {
// This is a cell.
val := fmt.Sprint(row)
if len(val) > node.w {
node.w = len(val)
}
cells[cellKey{ri, node}] = val
return node.w
}
// This is a slice.
totalW := 0
rowLen := row.Len()
for vi := 0; vi < rowLen; vi++ {
var child *layoutNode
if vi < len(node.children) {
child = node.children[vi]
} else {
child = &layoutNode{}
node.children = append(node.children, child)
}
totalW += walk(ri, row.Index(vi), child)
}
// Add in interior column spacing.
totalW += 3 * (rowLen - 1)
if totalW > node.w {
node.w = totalW
}
return node.w
}
for ri, row := range table {
walk(ri, reflect.ValueOf(row), layout)
}
// Print table
var printNode func(ri int, node *layoutNode, fillW int)
printNode = func(ri int, node *layoutNode, fillW int) {
if val, ok := cells[cellKey{ri, node}]; ok {
if fillW < node.w {
fillW = node.w
}
fmt.Fprintf(w, "| %*s ", fillW, val)
return
}
for ci, child := range node.children {
parentW := 0
if ci == len(node.children)-1 {
parentW = fillW
} else {
fillW -= child.w
}
printNode(ri, child, parentW)
}
}
for ri := range table {
printNode(ri, layout, 0)
fmt.Fprintf(w, "|\n")
}
}
================================================
FILE: abi/go.mod
================================================
module abi
go 1.15
require golang.org/x/tools v0.0.0-20200815165600-90abf76919f3
================================================
FILE: abi/go.sum
================================================
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200815165600-90abf76919f3 h1:0aScV/0rLmANzEYIhjCOi2pTvDyhZNduBUMD2q3iqs4=
golang.org/x/tools v0.0.0-20200815165600-90abf76919f3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
================================================
FILE: bench/parse.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package bench reads and writes Go benchmarks results files.
//
// This format is specified at:
// https://github.com/golang/proposal/blob/master/design/14313-benchmark-format.md
package bench
import (
"bufio"
"io"
"regexp"
"strconv"
"strings"
"time"
"unicode"
"unicode/utf8"
)
// Benchmark records the configuration and results of a single
// benchmark run (a single line of a benchmark results file).
type Benchmark struct {
// Name is the name of the benchmark, without the "Benchmark"
// prefix and without the trailing GOMAXPROCS number.
Name string
// Iterations is the number of times this benchmark executed.
Iterations int
// Config is the set of configuration pairs for this
// Benchmark. These can be specified in both configuration
// blocks and in individual benchmark lines. If the benchmark
// name is of the form "BenchmarkX-N", the N is stripped out
// and stored as "gomaxprocs" here.
Config map[string]*Config
// Result is the set of (unit, value) metrics for this
// benchmark run.
Result map[string]float64
}
// Config represents a single key/value configuration pair.
type Config struct {
// Value is the parsed value of this configuration value.
Value interface{}
// RawValue is the value of this configuration value, exactly
// as written in the original benchmark file.
RawValue string
// InBlock indicates that this configuration value was
// specified in a configuration block line. Otherwise, it was
// specified in the benchmark line.
InBlock bool
}
var configRe = regexp.MustCompile(`^(\p{Ll}[^\p{Lu}\s\x85\xa0\x{1680}\x{2000}-\x{200a}\x{2028}\x{2029}\x{202f}\x{205f}\x{3000}]*):(?:[ \t]+(.*))?$`)
// Parse parses a standard Go benchmark results file from r. It
// returns a *Benchmark for each benchmark result line in the file.
// There may be many result lines for the same benchmark name and
// configuration, indicating that the benchmark was run multiple
// times.
//
// In the returned Benchmarks, RawValue is set, but Value is always
// nil. Use ParseValues to convert raw values to structured types.
func Parse(r io.Reader) ([]*Benchmark, error) {
benchmarks := []*Benchmark{}
config := make(map[string]*Config)
scanner := bufio.NewScanner(r)
for scanner.Scan() {
line := scanner.Text()
if line == "testing: warning: no tests to run" {
continue
}
// Configuration lines.
m := configRe.FindStringSubmatch(line)
if m != nil {
config[m[1]] = &Config{RawValue: m[2], InBlock: true}
continue
}
// Benchmark lines.
if strings.HasPrefix(line, "Benchmark") {
b := parseBenchmark(line, config)
if b != nil {
benchmarks = append(benchmarks, b)
}
}
}
if err := scanner.Err(); err != nil {
return nil, err
}
return benchmarks, nil
}
func parseBenchmark(line string, gconfig map[string]*Config) *Benchmark {
// TODO: Consider using scanner to avoid the slice allocation.
f := strings.Fields(line)
if len(f) < 4 {
return nil
}
if f[0] != "Benchmark" {
next, _ := utf8.DecodeRuneInString(f[0][len("Benchmark"):])
if !unicode.IsUpper(next) {
return nil
}
}
b := &Benchmark{
Config: make(map[string]*Config),
Result: make(map[string]float64),
}
// Copy global config.
for k, v := range gconfig {
b.Config[k] = v
}
// Parse name and configuration.
name := strings.TrimPrefix(f[0], "Benchmark")
if strings.Contains(name, "/") {
parts := strings.Split(name, "/")
b.Name = parts[0]
for _, part := range parts[1:] {
if i := strings.Index(part, ":"); i >= 0 {
k, v := part[:i], part[i+1:]
b.Config[k] = &Config{RawValue: v}
}
}
} else if i := strings.LastIndex(name, "-"); i >= 0 {
_, err := strconv.Atoi(name[i+1:])
if err == nil {
b.Name = name[:i]
b.Config["gomaxprocs"] = &Config{RawValue: name[i+1:]}
} else {
b.Name = name
}
} else {
b.Name = name
}
if b.Config["gomaxprocs"] == nil {
b.Config["gomaxprocs"] = &Config{RawValue: "1"}
}
// Parse iterations.
n, err := strconv.Atoi(f[1])
if err != nil || n <= 0 {
return nil
}
b.Iterations = n
// Parse results.
for i := 2; i+2 <= len(f); i += 2 {
val, err := strconv.ParseFloat(f[i], 64)
if err != nil {
continue
}
b.Result[f[i+1]] = val
}
return b
}
// ValueParser is a function that parses a string value into a
// structured type or returns an error if the string cannot be parsed.
type ValueParser func(string) (interface{}, error)
// DefaultValueParsers is the default sequence of value parsers used
// by ParseValues if no parsers are specified.
var DefaultValueParsers = []ValueParser{
func(s string) (interface{}, error) { return strconv.Atoi(s) },
func(s string) (interface{}, error) { return strconv.ParseFloat(s, 64) },
func(s string) (interface{}, error) { return time.ParseDuration(s) },
}
// ParseValues parses the raw configuration values in benchmarks into
// structured types using best-effort pattern-based parsing.
//
// If all of the raw values for a given configuration key can be
// parsed by one of the valueParsers, ParseValues sets the parsed
// values to the results of that ValueParser. If multiple ValueParsers
// can parse all of the raw values, it uses the earliest such parser
// in the valueParsers list.
//
// If valueParsers is nil, it uses DefaultValueParsers.
func ParseValues(benchmarks []*Benchmark, valueParsers []ValueParser) {
if valueParsers == nil {
valueParsers = DefaultValueParsers
}
// Collect all configuration keys.
keys := map[string]bool{}
for _, b := range benchmarks {
for k := range b.Config {
keys[k] = true
}
}
// For each configuration key, try value parsers in priority order.
for key := range keys {
good := false
tryParsers:
for _, vp := range valueParsers {
// Clear all values. This way we can detect
// aliasing and not parse the same value
// multiple times.
for _, b := range benchmarks {
c, ok := b.Config[key]
if ok {
c.Value = nil
}
}
good = true
tryValues:
for _, b := range benchmarks {
c, ok := b.Config[key]
if !ok || c.Value != nil {
continue
}
res, err := vp(c.RawValue)
if err != nil {
// Parse error. Fail this parser.
good = false
break tryValues
}
c.Value = res
}
if good {
// This ValueParser converted all of
// the values.
break tryParsers
}
}
if !good {
// All of the value parsers failed. Fall back
// to strings.
for _, b := range benchmarks {
c, ok := b.Config[key]
if ok {
c.Value = nil
}
}
for _, b := range benchmarks {
c, ok := b.Config[key]
if ok && c.Value == nil {
c.Value = c.RawValue
}
}
}
}
}
================================================
FILE: bench/parse_test.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bench
import (
"bytes"
"reflect"
"testing"
)
func TestParse(t *testing.T) {
for _, test := range []struct {
input string
want []*Benchmark
}{
// Test basic line.
{`
BenchmarkX 1 2 ns/op 3 MB/s`,
[]*Benchmark{
{"X", 1, map[string]*Config{}, map[string]float64{"ns/op": 2, "MB/s": 3}},
},
},
// Test short name.
{`
Benchmark 1 2 ns/op`,
[]*Benchmark{
{"", 1, map[string]*Config{}, map[string]float64{"ns/op": 2}},
},
},
// Test bad names.
{`
Benchmarkx 1 2 ns/op
benchmarkx 1 2 ns/op
benchmarkX 1 2 ns/op`,
[]*Benchmark{},
},
// Test short lines.
{`
BenchmarkX
BenchmarkX 1
BenchmarkX 1 2`,
[]*Benchmark{},
},
// Test -N.
{`
BenchmarkX-4 1 2 ns/op`,
[]*Benchmark{
{"X", 1, map[string]*Config{
"gomaxprocs": &Config{"gomaxprocs", "4", "4", false},
}, map[string]float64{"ns/op": 2}},
},
},
// Test per-benchmark config.
{`
BenchmarkX/a:20/b:abc 1 2 ns/op
BenchmarkY/c:123 2 4 ns/op`,
[]*Benchmark{
{"X", 1, map[string]*Config{
"a": &Config{"a", "20", "20", false},
"b": &Config{"b", "abc", "abc", false},
}, map[string]float64{"ns/op": 2}},
{"Y", 2, map[string]*Config{
"c": &Config{"c", "123", "123", false},
}, map[string]float64{"ns/op": 4}},
},
},
// Test block config.
{`
commit: 123456
date: Jan 1
colon:colon: 42
blank:
#not-config: x
spa ce: x
funny space: x
Not-config: x
BenchmarkX 1 2 ns/op`,
[]*Benchmark{
{"X", 1, map[string]*Config{
"commit": &Config{"commit", "123456", "123456", true},
"date": &Config{"date", "Jan 1", "Jan 1", true},
"colon:colon": &Config{"colon:colon", "42", "42", true},
"blank": &Config{"blank", "", "", true},
}, map[string]float64{"ns/op": 2}},
},
},
// Test benchmark config overriding block config.
{`
commit: 123456
date: Jan 1
BenchmarkX/commit:abcdef 1 2 ns/op`,
[]*Benchmark{
{"X", 1, map[string]*Config{
"commit": &Config{"commit", "abcdef", "abcdef", false},
"date": &Config{"date", "Jan 1", "Jan 1", true},
}, map[string]float64{"ns/op": 2}},
},
},
// Test block config overriding block config.
{`
commit: 123456
commit: abcdef
date: Jan 1
BenchmarkX 1 2 ns/op`,
[]*Benchmark{
{"X", 1, map[string]*Config{
"commit": &Config{"commit", "abcdef", "abcdef", true},
"date": &Config{"date", "Jan 1", "Jan 1", true},
}, map[string]float64{"ns/op": 2}},
},
},
} {
r := bytes.NewBufferString(test.input)
bs, err := Parse(r)
if err != nil {
t.Error("unexpected Parse error", err)
continue
}
if !reflect.DeepEqual(bs, test.want) {
t.Log("want:")
for _, b := range test.want {
t.Logf("%#v", b)
}
t.Log("got:")
for _, b := range bs {
t.Logf("%#v", b)
}
t.Fail()
}
}
}
================================================
FILE: bench/print.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bench
import (
"fmt"
"io"
"os"
"sort"
"strings"
)
func Print(bs []*Benchmark) error {
return Fprint(os.Stdout, bs)
}
func Fprint(w io.Writer, bs []*Benchmark) error {
type kv struct {
k, v string
}
type block struct {
config []kv
bs []*Benchmark
}
configKeys := func(b *Benchmark, inBlock bool) []string {
var keys []string
for k, config := range b.Config {
if config.InBlock == inBlock {
keys = append(keys, k)
}
}
sort.Strings(keys)
return keys
}
// Split bs into configuration blocks.
blocks := []block{}
lastConfig := map[string]string{}
for _, b := range bs {
// Find changed block configuration.
var changed []kv
for _, k := range configKeys(b, true) {
config := b.Config[k]
lc, ok := lastConfig[k]
if ok && lc == config.RawValue {
continue
}
changed = append(changed, kv{k, config.RawValue})
lastConfig[k] = config.RawValue
}
if len(blocks) == 0 || changed != nil {
// Start a new configuration block.
blocks = append(blocks, block{changed, nil})
}
// Add benchmark to latest block.
bbs := &blocks[len(blocks)-1].bs
*bbs = append(*bbs, b)
}
// Format each configuration block.
for i, block := range blocks {
// Print configuration values.
if i > 0 {
if _, err := fmt.Fprint(w, "\n"); err != nil {
return err
}
}
for _, kv := range block.config {
// TODO: Syntax check.
if _, err := fmt.Fprintf(w, "%s: %s\n", kv.k, kv.v); err != nil {
return err
}
}
if len(block.config) > 0 {
if _, err := fmt.Fprint(w, "\n"); err != nil {
return err
}
}
// Construct benchmark lines.
lines := make([][]string, len(block.bs))
for _, b := range block.bs {
// Construct benchmark name.
name := []string{"Benchmark" + b.Name}
gomaxprocs, haveGMP := "", false
for _, k := range configKeys(b, false) {
config := b.Config[k]
if k == "gomaxprocs" {
gomaxprocs = config.RawValue
haveGMP = true
continue
}
// TODO: Syntax check.
name = append(name, fmt.Sprintf("%s:%s", k, config.RawValue))
}
if haveGMP && gomaxprocs != "1" {
if len(name) == 1 {
// Use short form.
name[0] = fmt.Sprintf("%s-%s", name[0], gomaxprocs)
} else {
name = append(name, fmt.Sprintf("gomaxprocs:%s", gomaxprocs))
}
}
// Construct results.
line := []string{
strings.Join(name, "/"),
fmt.Sprint(b.Iterations),
}
resultKeys := []string{}
for k := range b.Result {
resultKeys = append(resultKeys, k)
}
sort.Sort(resultKeySorter(resultKeys))
for _, k := range resultKeys {
result := b.Result[k]
// TODO: Syntax check.
line = append(line, fmt.Sprint(result), k)
}
lines = append(lines, line)
}
// Compute column widths.
widths := make([]int, 0)
for _, line := range lines {
for i, elt := range line {
if i >= len(widths) {
widths = append(widths, len(elt))
} else if len(elt) > widths[i] {
widths[i] = len(elt)
}
}
}
// Print lines.
for _, line := range lines {
for i, elt := range line {
var err error
p := widths[i]
if i == 1 || i >= 2 && i%2 == 0 {
// Right align.
_, err = fmt.Fprintf(w, "%*s ", p, elt)
} else if i < len(line)-1 {
// Left align and pad.
_, err = fmt.Fprintf(w, "%-*s ", p, elt)
} else {
// Left align, no pad, EOL.
_, err = fmt.Fprintf(w, "%s\n", elt)
}
if err != nil {
return err
}
}
}
}
return nil
}
var fixedKeys = map[string]int{
"ns/op": -2,
"MB/s": -1,
}
type resultKeySorter []string
func (s resultKeySorter) Len() int {
return len(s)
}
func (s resultKeySorter) Less(i, j int) bool {
if fixedKeys[s[i]] != fixedKeys[s[j]] {
return fixedKeys[s[i]] < fixedKeys[s[j]]
}
return s[i] < s[j]
}
func (s resultKeySorter) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
================================================
FILE: benchcmd/main.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Command benchcmd times a shell command using Go benchmark format.
package main
import (
"flag"
"fmt"
"os"
"os/exec"
"time"
)
func main() {
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage: %s [-n iters] benchname cmd...\n", os.Args[0])
flag.PrintDefaults()
}
n := flag.Int("n", 5, "iterations")
flag.Parse()
if flag.NArg() < 2 {
flag.Usage()
os.Exit(2)
}
benchname := flag.Arg(0)
args := flag.Args()[1:]
for i := 0; i < *n; i++ {
cmd := exec.Command(args[0], args[1:]...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
before := time.Now()
if err := cmd.Run(); err != nil {
fmt.Println(err)
os.Exit(1)
}
after := time.Now()
fmt.Printf("Benchmark%s\t", benchname)
fmt.Printf("%d\t%d ns/op", 1, after.Sub(before))
fmt.Printf("\t%d user-ns/op\t%d sys-ns/op", cmd.ProcessState.UserTime(), cmd.ProcessState.SystemTime())
if maxrss, ok := getMaxRSS(cmd.ProcessState); ok {
fmt.Printf("\t%d peak-RSS-bytes", maxrss)
}
fmt.Printf("\n")
}
}
================================================
FILE: benchcmd/rss_nounix.go
================================================
// Copyright 2025 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !unix
package main
import "os"
func getMaxRSS(ps *os.ProcessState) (bytes uint64, ok bool) {
return 0, false
}
================================================
FILE: benchcmd/rss_unix.go
================================================
// Copyright 2025 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build unix
package main
import (
"os"
"runtime"
"syscall"
)
func getMaxRSS(ps *os.ProcessState) (bytes uint64, ok bool) {
ru, ok := ps.SysUsage().(*syscall.Rusage)
if !ok {
return 0, false
}
var rssToBytes uint64
switch runtime.GOOS {
default:
return 0, false
case "aix", "android", "dragonfly", "freebsd", "linux", "netbsd", "openbsd":
rssToBytes = 1 << 10
case "darwin", "ios":
rssToBytes = 1
case "illumos", "solaris":
rssToBytes = uint64(syscall.Getpagesize())
}
return uint64(ru.Maxrss) * rssToBytes, true
}
================================================
FILE: benchmany/benchmany.go
================================================
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Benchmany runs Go benchmarks across many git commits.
//
// Usage:
//
// benchmany [-C git-dir] [-n iterations] <commit or range>...
//
// benchmany runs the benchmarks in the current directory <iterations>
// times for each commit in <commit or range> and writes the benchmark
// results to bench.log. Benchmarks may be Go testing framework
// benchmarks or benchmarks from golang.org/x/benchmarks.
//
// <commit or range>... can be either a list of individual commits or
// a revision range. For the spelling of a revision range, see
// "SPECIFYING RANGES" in gitrevisions(7). For exact details, see the
// --no-walk option to git-rev-list(1).
//
// Benchmany will check out each revision in git-dir. The current
// directory may or may not be in the same git repository as git-dir.
// If git-dir refers to a Go installation, benchmany will run
// make.bash at each revision; otherwise, it assumes go test can
// rebuild the necessary dependencies. Benchmany also supports using
// gover (https://godoc.org/github.com/aclements/go-misc/gover) to
// save and reuse Go build trees. This is useful for saving time
// across multiple benchmark runs and for benchmarks that depend on
// the Go tree itself (such as compiler benchmarks).
//
// Benchmany supports multiple ways of prioritizing the order in which
// individual iterations are run. By default, it runs in "sequential"
// mode: it runs the first iteration of all benchmarks, then the
// second, and so forth. It also supports a "spread" mode designed to
// quickly get coverage for large sets of revisions. This mode
// randomizes the order to run iterations in, but biases this order
// toward covering an evenly distributed set of revisions early and
// finishing all of the iterations of the revisions it has started on
// before moving on to new revisions. This way, if benchmany is
// interrupted, the revisions benchmarked cover the space more-or-less
// evenly. Finally, it supports a "metric" mode, which zeroes in on
// changes in a benchmark metric by selecting the commit half way
// between the pair of commits with the biggest difference in the
// metric. This is like "git bisect", but for performance.
//
// Benchmany is safe to interrupt. If it is restarted, it will parse
// the benchmark log files to recover its state.
package main
import (
"flag"
"fmt"
"os"
"os/exec"
"strings"
)
var gitDir string
var dryRun bool
// maxFails is the maximum number of benchmark run failures to
// tolerate for a commit before giving up on trying to benchmark that
// commit. Build failures always disqualify a commit.
const maxFails = 5
func main() {
flag.Parse()
doRun()
}
// git runs git subcommand subcmd and returns its stdout. If git
// fails, it prints the failure and exits.
func git(subcmd string, args ...string) string {
gitargs := []string{}
if gitDir != "" {
gitargs = append(gitargs, "-C", gitDir)
}
gitargs = append(gitargs, subcmd)
gitargs = append(gitargs, args...)
cmd := exec.Command("git", gitargs...)
cmd.Stderr = os.Stderr
if dryRun {
dryPrint(cmd)
if !(subcmd == "rev-parse" || subcmd == "rev-list" || subcmd == "show") {
return ""
}
}
out, err := cmd.Output()
if err != nil {
fmt.Fprintf(os.Stderr, "git %s failed: %s\n", shellEscapeList(gitargs), err)
os.Exit(1)
}
return string(out)
}
func dryPrint(cmd *exec.Cmd) {
out := shellEscape(cmd.Path)
for _, a := range cmd.Args[1:] {
out += " " + shellEscape(a)
}
if cmd.Dir != "" {
out = fmt.Sprintf("(cd %s && %s)", shellEscape(cmd.Dir), out)
}
fmt.Fprintln(os.Stderr, out)
}
func shellEscape(x string) string {
if len(x) == 0 {
return "''"
}
for _, r := range x {
if 'a' <= r && r <= 'z' || 'A' <= r && r <= 'Z' || '0' <= r && r <= '9' || strings.ContainsRune("@%_-+:,./", r) {
continue
}
// Unsafe character.
return "'" + strings.Replace(x, "'", "'\"'\"'", -1) + "'"
}
return x
}
func shellEscapeList(xs []string) string {
out := make([]string, len(xs))
for i, x := range xs {
out[i] = shellEscape(x)
}
return strings.Join(out, " ")
}
func exists(path string) bool {
_, err := os.Stat(path)
return !os.IsNotExist(err)
}
func trimNL(s string) string {
return strings.TrimRight(s, "\n")
}
// indent returns s with each line indented by four spaces. If s is
// non-empty, the returned string is guaranteed to end in a "\n".
func indent(s string) string {
if len(s) == 0 {
return s
}
if strings.HasSuffix(s, "\n") {
s = s[:len(s)-1]
}
return " " + strings.Replace(s, "\n", "\n ", -1) + "\n"
}
// lines splits s in to lines. It omits a final blank line, if any.
func lines(s string) []string {
l := strings.Split(s, "\n")
if len(l) > 0 && l[len(l)-1] == "" {
l = l[:len(l)-1]
}
return l
}
================================================
FILE: benchmany/commits.go
================================================
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"bufio"
"bytes"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"os/user"
"path/filepath"
"regexp"
"strings"
"time"
)
type commitInfo struct {
hash string
commitDate time.Time
gover bool
logPath string
count, fails int
buildFailed bool
}
// getCommits returns the commit info for all of the revisions in the
// given git revision range, where the revision range is spelled as
// documented in gitrevisions(7). Commits are returned in reverse
// chronological order, most recent commit first (the same as
// git-rev-list(1)).
func getCommits(revRange []string, logPath string) []*commitInfo {
// Get commit sequence.
args := append(append([]string{"--no-walk"}, revRange...), "--")
hashes := lines(git("rev-list", args...))
commits := make([]*commitInfo, len(hashes))
commitMap := make(map[string]*commitInfo)
for i, hash := range hashes {
commits[i] = &commitInfo{
hash: hash,
logPath: logPath,
}
commitMap[hash] = commits[i]
}
// Get commit dates.
//
// TODO: This can produce a huge command line.
args = append([]string{"-s", "--format=format:%cI"}, hashes...)
dates := lines(git("show", args...))
for i := range commits {
d, err := time.Parse(time.RFC3339, dates[i])
if err != nil {
log.Fatalf("cannot parse commit date: %v", err)
}
commits[i].commitDate = d
}
// Get gover-cached builds. It's okay if this fails.
if fis, err := ioutil.ReadDir(goverDir()); err == nil {
for _, fi := range fis {
if ci := commitMap[fi.Name()]; ci != nil && fi.IsDir() {
ci.gover = true
}
}
}
// Load current benchmark state.
logf, err := os.Open(logPath)
if err != nil {
if !os.IsNotExist(err) {
log.Fatalf("opening %s: %v", logPath, err)
}
} else {
defer logf.Close()
parseLog(commitMap, logf)
}
return commits
}
// goverDir returns the directory containing gover-cached builds.
func goverDir() string {
cache := os.Getenv("XDG_CACHE_HOME")
if cache == "" {
home := os.Getenv("HOME")
if home == "" {
u, err := user.Current()
if err != nil {
home = u.HomeDir
}
}
cache = filepath.Join(home, ".cache")
}
return filepath.Join(cache, "gover")
}
// parseLog parses benchmark runs and failures from r and updates
// commits in commitMap.
func parseLog(commitMap map[string]*commitInfo, r io.Reader) {
scanner := bufio.NewScanner(r)
for scanner.Scan() {
b := scanner.Bytes()
switch {
case bytes.HasPrefix(b, []byte("commit: ")):
hash := scanner.Text()[len("commit: "):]
if ci := commitMap[hash]; ci != nil {
ci.count++
}
case bytes.HasPrefix(b, []byte("# FAILED at ")):
hash := scanner.Text()[len("# FAILED at "):]
if ci := commitMap[hash]; ci != nil {
ci.fails++
}
case bytes.HasPrefix(b, []byte("# BUILD FAILED at ")):
hash := scanner.Text()[len("# BUILD FAILED at "):]
if ci := commitMap[hash]; ci != nil {
ci.buildFailed = true
}
}
}
if err := scanner.Err(); err != nil {
log.Fatal("parsing benchmark log: ", err)
}
}
// binPath returns the file name of the binary for this commit.
func (c *commitInfo) binPath() string {
// TODO: This assumes the short commit hash is unique.
return fmt.Sprintf("bench.%s", c.hash[:7])
}
// failed returns whether commit c has failed and should not be run
// any more.
func (c *commitInfo) failed() bool {
return c.buildFailed || c.fails >= maxFails
}
// runnable returns whether commit c needs to be benchmarked at least
// one more time.
func (c *commitInfo) runnable() bool {
return !c.buildFailed && c.fails < maxFails && c.count < run.iterations
}
// partial returns true if this commit is both runnable and already
// has some runs.
func (c *commitInfo) partial() bool {
return c.count > 0 && c.runnable()
}
var commitRe = regexp.MustCompile(`^commit: |^# FAILED|^# BUILD FAILED`)
// cleanLog escapes lines in l that may confuse the log parser and
// makes sure l is newline terminated.
func cleanLog(l string) string {
l = commitRe.ReplaceAllString(l, "# $0")
if !strings.HasSuffix(l, "\n") {
l += "\n"
}
return l
}
// logRun updates c with a successful run.
func (c *commitInfo) logRun(out string) {
var log bytes.Buffer
fmt.Fprintf(&log, "commit: %s\n", c.hash)
fmt.Fprintf(&log, "commit-time: %s\n", c.commitDate.UTC().Format(time.RFC3339))
fmt.Fprintf(&log, "\n%s\n", cleanLog(out))
c.writeLog(log.String())
c.count++
}
// logFailed updates c with a failed run. If buildFailed is true, this
// is considered a permanent failure and buildFailed is set.
func (c *commitInfo) logFailed(buildFailed bool, out string) {
typ := "FAILED"
if buildFailed {
typ = "BUILD FAILED"
}
c.writeLog(fmt.Sprintf("# %s at %s\n# %s\n", typ, c.hash, strings.Replace(cleanLog(out), "\n", "\n# ", -1)))
if buildFailed {
c.buildFailed = true
} else {
c.fails++
}
}
// writeLog appends msg to c's log file. The caller is responsible for
// properly formatting it.
func (c *commitInfo) writeLog(msg string) {
logFile, err := os.OpenFile(c.logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("opening %s: %v", c.logPath, err)
}
if _, err := logFile.WriteString(msg); err != nil {
log.Fatalf("writing to %s: %v", c.logPath, err)
}
if err := logFile.Close(); err != nil {
log.Fatalf("closing %s: %v", c.logPath, err)
}
}
================================================
FILE: benchmany/readlog.go
================================================
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"io/ioutil"
"log"
"strconv"
"strings"
"github.com/aclements/go-moremath/stats"
)
// ComputeStats updates the derived statistics in s from the raw
// samples in s.Values.
func (stat *Benchstat) ComputeStats() {
stat.Mean = stats.Mean(stat.Values)
}
// A Benchstat is the metrics along one axis (e.g., ns/op or MB/s)
// for all runs of a specific benchmark.
type Benchstat struct {
Unit string
Values []float64 // metrics
Mean float64 // mean of Values
}
// A BenchKey identifies one metric (e.g., "ns/op", "B/op") from one
// benchmark (function name sans "Benchmark" prefix) in one
// configuration (input file name).
type BenchKey struct {
Config, Benchmark, Unit string
}
type Collection struct {
Stats map[BenchKey]*Benchstat
// Keys gives all keys of Stats in the order added.
Keys []BenchKey
// Configs, Benchmarks, and Units give the set of configs,
// benchmarks, and units from the keys in Stats in an order
// meant to match the order the benchmarks were read in.
Configs, Benchmarks, Units []string
// ConfigSet, BenchmarkSet, and UnitSet are set
// representations of Configs, Benchmarks, and Units.
ConfigSet, BenchmarkSet, UnitSet map[string]bool
}
func (c *Collection) AddStat(key BenchKey) *Benchstat {
if stat, ok := c.Stats[key]; ok {
return stat
}
c.addKey(key)
stat := &Benchstat{Unit: key.Unit}
c.Stats[key] = stat
return stat
}
func (c *Collection) addKey(key BenchKey) {
addString := func(strings *[]string, set map[string]bool, add string) {
if set[add] {
return
}
*strings = append(*strings, add)
set[add] = true
}
c.Keys = append(c.Keys, key)
addString(&c.Configs, c.ConfigSet, key.Config)
addString(&c.Benchmarks, c.BenchmarkSet, key.Benchmark)
addString(&c.Units, c.UnitSet, key.Unit)
}
func (c *Collection) Filter(key BenchKey) *Collection {
c2 := NewCollection()
for _, k := range c.Keys {
if (key.Config == "" || key.Config == k.Config) &&
(key.Benchmark == "" || key.Benchmark == k.Benchmark) &&
(key.Unit == "" || key.Unit == k.Unit) {
c2.addKey(k)
c2.Stats[k] = c.Stats[k]
}
}
return c2
}
func NewCollection() *Collection {
return &Collection{
Stats: make(map[BenchKey]*Benchstat),
ConfigSet: make(map[string]bool),
BenchmarkSet: make(map[string]bool),
UnitSet: make(map[string]bool),
}
}
// readFiles reads a set of benchmark files as a Collection.
func readFiles(files ...string) *Collection {
c := NewCollection()
for _, file := range files {
readFile(file, c)
}
return c
}
var unitOfXMetric = map[string]string{
"time": "ns/op",
"allocated": "allocated bytes/op", // ΔMemStats.TotalAlloc / N
"allocs": "allocs/op", // ΔMemStats.Mallocs / N
"sys-total": "bytes from system", // MemStats.Sys
"sys-heap": "heap bytes from system", // MemStats.HeapSys
"sys-stack": "stack bytes from system", // MemStats.StackSys
"sys-gc": "GC bytes from system", // MemStats.GCSys
"sys-other": "other bytes from system", // MemStats.OtherSys+MSpanSys+MCacheSys+BuckHashSys
"gc-pause-total": "STW ns/op", // ΔMemStats.PauseTotalNs / N
"gc-pause-one": "STW ns/GC", // ΔMemStats.PauseTotalNs / ΔNumGC
"rss": "max RSS bytes", // Rusage.Maxrss * 1<<10
"cputime": "user+sys ns/op", // Rusage.Utime+Stime
"virtual-mem": "peak VM bytes", // /proc/self/status VmPeak
}
// readFile reads a set of benchmarks from a file in to a Collection.
func readFile(file string, c *Collection) {
c.Configs = append(c.Configs, file)
key := BenchKey{Config: file}
text, err := ioutil.ReadFile(file)
if err != nil {
log.Fatal(err)
}
for _, line := range strings.Split(string(text), "\n") {
if strings.HasPrefix(line, "GOPERF-METRIC:") {
// x/benchmarks-style output.
line := line[14:]
f := strings.Split(line, "=")
val, err := strconv.ParseFloat(f[1], 64)
if err != nil {
continue
}
key.Benchmark = f[0]
key.Unit = unitOfXMetric[f[0]]
if key.Unit == "" {
continue
}
stat := c.AddStat(key)
stat.Values = append(stat.Values, val)
continue
}
f := strings.Fields(line)
if len(f) < 4 {
continue
}
name := f[0]
if !strings.HasPrefix(name, "Benchmark") {
continue
}
name = strings.TrimPrefix(name, "Benchmark")
n, _ := strconv.Atoi(f[1])
if n == 0 {
continue
}
key.Benchmark = name
for i := 2; i+2 <= len(f); i += 2 {
val, err := strconv.ParseFloat(f[i], 64)
if err != nil {
continue
}
key.Unit = f[i+1]
stat := c.AddStat(key)
stat.Values = append(stat.Values, val)
}
}
}
================================================
FILE: benchmany/run.go
================================================
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"bytes"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"math"
"math/rand"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"time"
"github.com/aclements/go-misc/bench"
"github.com/aclements/go-moremath/stats"
)
// TODO: Check CPU performance governor before each benchmark.
// TODO: Support running pre-built binaries without specific hashes.
// This is useful for testing things that aren't yet committed or that
// require unusual build steps.
var run struct {
order string
metric string
benchFlags string
buildCmd string
iterations int
saveTree bool
timeout time.Duration
clean bool
cleanFlags string
logPath string
binDir string
}
func init() {
// TODO: This makes a mess of flags during testing.
isXBenchmark := false
if abs, _ := os.Getwd(); strings.HasSuffix(abs, "golang.org/x/benchmarks/bench") {
isXBenchmark = true
}
f := flag.CommandLine
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage: %s [flags] <revision range>\n", os.Args[0])
f.PrintDefaults()
}
f.StringVar(&run.order, "order", "seq", "run benchmarks in `order`, which must be one of: seq, spread, metric")
f.StringVar(&run.metric, "metric", "ns/op", "for -order metric, the benchmark metric to find differences in")
f.StringVar(&gitDir, "C", "", "run git in `dir`")
defaultBenchFlags := "-test.run NONE -test.bench ."
if isXBenchmark {
defaultBenchFlags = ""
}
f.StringVar(&run.benchFlags, "benchflags", defaultBenchFlags, "pass `flags` to benchmark")
defaultBuildCmd := "go test -c"
if isXBenchmark {
defaultBuildCmd = "go build"
}
f.StringVar(&run.buildCmd, "buildcmd", defaultBuildCmd, "build benchmark using \"`cmd` -o <bin>\"")
f.IntVar(&run.iterations, "n", 5, "run each benchmark `N` times")
f.StringVar(&run.logPath, "o", "", "write benchmark results to `file` (default \"bench.log\" in -d directory)")
f.StringVar(&run.binDir, "d", ".", "write binaries to `directory`")
f.BoolVar(&run.saveTree, "save-tree", false, "save Go trees using gover and run benchmarks under saved trees")
f.DurationVar(&run.timeout, "timeout", 30*time.Minute, "time out a run after `duration`")
f.BoolVar(&dryRun, "dry-run", false, "print commands but do not run them")
f.BoolVar(&run.clean, "clean", false, "run \"git clean -f\" after every checkout")
f.StringVar(&run.cleanFlags, "cleanflags", "", "add `flags` to git clean command")
}
func doRun() {
if flag.NArg() < 1 {
flag.Usage()
os.Exit(2)
}
var pickCommit func([]*commitInfo) *commitInfo
switch run.order {
case "seq":
pickCommit = pickCommitSeq
case "spread":
pickCommit = pickCommitSpread
case "metric":
pickCommit = pickCommitMetric
default:
fmt.Fprintf(os.Stderr, "unknown order: %s\n", run.order)
flag.Usage()
os.Exit(2)
}
if run.logPath == "" {
run.logPath = filepath.Join(run.binDir, "bench.log")
}
commits := getCommits(flag.Args(), run.logPath)
// Write header block to log.
if len(commits) > 0 {
header := new(bytes.Buffer)
fmt.Fprintf(header, "# Run started at %s\n", time.Now())
writeHeader(header)
fmt.Fprintf(header, "\n")
commits[0].writeLog(header.String())
}
// Always run git from the top level of the git tree. Some
// commands, like git clean, care about this.
gitDir = trimNL(git("rev-parse", "--show-toplevel"))
status := NewStatusReporter()
defer status.Stop()
for {
doneIters, totalIters, partialCommits, doneCommits, failedCommits := runStats(commits)
unstartedCommits := len(commits) - (partialCommits + doneCommits + failedCommits)
msg := fmt.Sprintf("%d/%d runs, %d unstarted+%d partial+%d done+%d failed commits", doneIters, totalIters, unstartedCommits, partialCommits, doneCommits, failedCommits)
// TODO: Count builds and runs separately.
status.Progress(msg, float64(doneIters)/float64(totalIters))
commit := pickCommit(commits)
if commit == nil {
break
}
runBenchmark(commit, status)
}
}
func writeHeader(w io.Writer) {
goos, err := exec.Command("go", "env", "GOOS").Output()
if err != nil {
log.Fatalf("error running go env GOOS: %s", err)
}
fmt.Fprintf(w, "goos: %s\n", strings.TrimSpace(string(goos)))
goarch, err := exec.Command("go", "env", "GOARCH").Output()
if err != nil {
log.Fatalf("error running go env GOARCH: %s", err)
}
fmt.Fprintf(w, "goarch: %s\n", strings.TrimSpace(string(goarch)))
kernel, err := exec.Command("uname", "-sr").Output()
if err != nil {
log.Fatalf("error running uname -sr: %s", err)
}
fmt.Fprintf(w, "uname-sr: %s\n", strings.TrimSpace(string(kernel)))
cpuinfo, err := ioutil.ReadFile("/proc/cpuinfo")
if err == nil {
subs := regexp.MustCompile(`(?m)^model name\s*:\s*(.*)`).FindSubmatch(cpuinfo)
if subs != nil {
fmt.Fprintf(w, "cpu: %s\n", string(subs[1]))
}
}
fmt.Fprintf(w, "tool: benchmany\n")
}
func runStats(commits []*commitInfo) (doneIters, totalIters, partialCommits, doneCommits, failedCommits int) {
for _, c := range commits {
if c.count >= run.iterations {
// Don't care if it failed.
doneIters += c.count
totalIters += c.count
} else if c.runnable() {
doneIters += c.count
totalIters += run.iterations
}
if c.count == run.iterations {
doneCommits++
} else if c.runnable() {
if c.count != 0 {
partialCommits++
}
} else {
failedCommits++
}
}
return
}
// pickCommitSeq picks the next commit to run based on the most recent
// commit with the fewest iterations.
func pickCommitSeq(commits []*commitInfo) *commitInfo {
var minCommit *commitInfo
for _, commit := range commits {
if !commit.runnable() {
continue
}
if minCommit == nil || commit.count < minCommit.count {
minCommit = commit
}
}
return minCommit
}
// pickCommitSpread picks the next commit to run from commits using an
// algorithm that spreads out the runs.
func pickCommitSpread(commits []*commitInfo) *commitInfo {
// Assign weights to each commit. This is thoroughly
// heuristic, but it's geared toward either increasing the
// iteration count of commits that we have, or picking a new
// commit so as to spread out the commits we have.
weights := make([]int, len(commits))
totalWeight := 0
nPartial := 0
for _, commit := range commits {
if commit.partial() {
nPartial++
}
}
if nPartial >= len(commits)/10 {
// Limit the number of partially completed revisions
// to 10% by only choosing a partial commit in this
// case.
for i, commit := range commits {
if commit.partial() {
// Bias toward commits that are
// further from done.
weights[i] = run.iterations - commit.count
}
}
} else {
// Pick a new commit weighted by its distance from a
// commit that we already have.
// Find distance from left to right.
distance := len(commits)
haveAny := false
for i, commit := range commits {
if commit.count > 0 {
distance = 1
haveAny = true
} else if commit.runnable() {
distance++
}
weights[i] = distance
}
// Find distance from right to left.
distance = len(commits)
for i := len(commits) - 1; i >= 0; i-- {
commit := commits[i]
if commit.count > 0 {
distance = 1
} else if commit.runnable() {
distance++
}
if distance < weights[i] {
weights[i] = distance
}
}
if !haveAny {
// We don't have any commits. Pick one uniformly.
for i := range commits {
weights[i] = 1
}
}
// Zero non-runnable commits.
for i, commit := range commits {
if !commit.runnable() {
weights[i] = 0
}
}
}
for _, w := range weights {
totalWeight += w
}
if totalWeight == 0 {
return nil
}
// Pick a commit based on the weights.
x := rand.Intn(totalWeight)
cumulative := 0
for i, w := range weights {
cumulative += w
if cumulative > x {
return commits[i]
}
}
panic("unreachable")
}
func pickCommitMetric(commits []*commitInfo) *commitInfo {
// If there are any partial commits, finish them up.
for _, c := range commits {
if c.partial() {
return c
}
}
// Remove failed commits. This makes it easier to avoid
// picking a failed commit below.
ncommits := []*commitInfo{}
for _, c := range commits {
if !c.failed() {
ncommits = append(ncommits, c)
}
}
commits = ncommits
if len(ncommits) == 0 {
return nil
}
// Make sure we've run the most recent commit.
if commits[0].runnable() {
return commits[0]
}
// Make sure we've run the earliest commit.
if c := commits[len(commits)-1]; c.runnable() {
return c
}
// We're bounded from both sides and every commit we've run
// has the best stats we're going to get. Parse run.metric
// from the log file.
logf, err := os.Open(run.logPath)
if err != nil {
log.Fatal("opening benchmark log: ", err)
}
defer logf.Close()
bs, err := bench.Parse(logf)
if err != nil {
log.Fatal("parsing benchmark log for metrics: ", err)
}
results := make(map[string]map[string][]float64)
for _, b := range bs {
var hash string
if commitConfig, ok := b.Config["commit"]; !ok {
continue
} else {
hash = commitConfig.RawValue
}
result, ok := b.Result[run.metric]
if !ok {
continue
}
if results[hash] == nil {
results[hash] = make(map[string][]float64)
}
results[hash][b.Name] = append(results[hash][b.Name], result)
}
geomeans := make(map[string]float64)
for hash, benches := range results {
var means []float64
for _, results := range benches {
means = append(means, stats.Mean(results))
}
geomeans[hash] = stats.GeoMean(means)
}
// Find the pair of commits with the biggest difference in the
// metric.
prevI := -1
maxDiff, maxMid := -1.0, (*commitInfo)(nil)
for i, c := range commits {
if c.count == 0 || geomeans[c.hash] == 0 {
continue
}
if prevI == -1 {
prevI = i
continue
}
if i > prevI+1 {
// TODO: This isn't branch-aware. We should
// only compare commits with an ancestry
// relationship.
diff := math.Abs(geomeans[c.hash] - geomeans[commits[prevI].hash])
if diff > maxDiff {
maxDiff = diff
maxMid = commits[(prevI+i)/2]
}
}
prevI = i
}
return maxMid
}
// runBenchmark runs the benchmark at commit. It updates commit.count,
// commit.fails, and commit.buildFailed as appropriate and writes to
// the commit log to record the outcome.
func runBenchmark(commit *commitInfo, status *StatusReporter) {
// Build the benchmark if necessary.
binPath := filepath.Join(run.binDir, commit.binPath())
if !exists(binPath) {
runStatus(status, commit, "building")
// Check out the appropriate commit. This is necessary
// even if we're using gover because the benchmark
// itself might have changed (e.g., bug fixes).
git("checkout", "-q", commit.hash)
if run.clean {
args := append([]string{"-f"}, strings.Fields(run.cleanFlags)...)
git("clean", args...)
}
var buildCmd []string
if commit.gover {
buildCmd = []string{"gover", "with", commit.hash}
} else {
// If this is the Go toolchain, do a full
// make.bash. Otherwise, we assume that go
// test -c will build the necessary
// dependencies.
if exists(filepath.Join(gitDir, "src", "make.bash")) {
cmd := exec.Command("./make.bash")
cmd.Dir = filepath.Join(gitDir, "src")
if dryRun {
dryPrint(cmd)
} else if out, err := combinedOutputTimeout(cmd); err != nil {
detail := indent(string(out)) + indent(err.Error())
fmt.Fprintf(os.Stderr, "failed to build toolchain at %s:\n%s", commit.hash, detail)
commit.logFailed(true, detail)
return
}
if run.saveTree && doGoverSave() == nil {
commit.gover = true
}
}
// Assume build command is in $PATH.
//
// TODO: Force PATH if we built the toolchain.
buildCmd = []string{}
}
buildCmd = append(buildCmd, strings.Fields(run.buildCmd)...)
buildCmd = append(buildCmd, "-o", binPath)
cmd := exec.Command(buildCmd[0], buildCmd[1:]...)
if dryRun {
dryPrint(cmd)
} else if out, err := combinedOutputTimeout(cmd); err != nil {
detail := indent(string(out)) + indent(err.Error())
fmt.Fprintf(os.Stderr, "failed to build tests at %s:\n%s", commit.hash, detail)
commit.logFailed(true, detail)
return
}
}
// Run the benchmark.
runStatus(status, commit, "running")
if filepath.Base(binPath) == binPath {
// Make exec.Command treat this as a relative path.
binPath = "./" + binPath
}
args := append([]string{binPath}, strings.Fields(run.benchFlags)...)
if run.saveTree {
args = append([]string{"gover", "with", commit.hash}, args...)
}
cmd := exec.Command(args[0], args[1:]...)
if dryRun {
dryPrint(cmd)
commit.count++
return
}
out, err := combinedOutputTimeout(cmd)
if err == nil {
commit.logRun(string(out))
} else {
detail := indent(string(out)) + indent(err.Error())
fmt.Fprintf(os.Stderr, "failed to run benchmark at %s:\n%s", commit.hash, detail)
commit.logFailed(false, detail)
}
}
func doGoverSave() error {
cmd := exec.Command("gover", "save")
cmd.Dir = gitDir
if dryRun {
dryPrint(cmd)
return nil
} else {
out, err := cmd.CombinedOutput()
if err != nil {
fmt.Fprintf(os.Stderr, "gover save failed: %s:\n%s", err, indent(string(out)))
}
return err
}
}
// runStatus updates the status message for commit.
func runStatus(sr *StatusReporter, commit *commitInfo, status string) {
sr.Message(fmt.Sprintf("commit %s, iteration %d/%d: %s...", commit.hash[:7], commit.count+1, run.iterations, status))
}
// combinedOutputTimeout is like c.CombinedOutput(), but if
// run.timeout != 0, it will kill c after run.timeout time expires.
func combinedOutputTimeout(c *exec.Cmd) (out []byte, err error) {
var b bytes.Buffer
c.Stdout = &b
c.Stderr = &b
if err := c.Start(); err != nil {
return nil, err
}
if run.timeout == 0 {
err := c.Wait()
return b.Bytes(), err
}
tick := time.NewTimer(run.timeout)
trace := signalTrace
done := make(chan error)
go func() {
done <- c.Wait()
}()
loop:
for {
select {
case err = <-done:
break loop
case <-tick.C:
if trace != nil {
fmt.Fprintf(os.Stderr, "command timed out; sending %v\n", trace)
c.Process.Signal(trace)
tick = time.NewTimer(5 * time.Second)
trace = nil
} else {
fmt.Fprintf(os.Stderr, "command timed out; killing\n")
c.Process.Kill()
}
}
}
tick.Stop()
return b.Bytes(), err
}
================================================
FILE: benchmany/run_test.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"fmt"
"io/ioutil"
"math/rand"
"os"
"os/exec"
"path/filepath"
"testing"
"github.com/aclements/go-misc/bench"
)
func TestPickSpread(t *testing.T) {
run.iterations = 5
for iter := 0; iter < 10; iter++ {
commits := []*commitInfo{}
for i := 0; i < 100; i++ {
commits = append(commits, &commitInfo{})
}
for {
commit := pickCommitSpread(commits)
if commit == nil {
break
}
if rand.Intn(50) == 0 {
commit.buildFailed = true
} else if rand.Intn(50) == 1 {
commit.fails++
} else {
commit.count++
}
}
// Test that all of the commits ran the expected
// number of times.
for _, c := range commits {
if c.runnable() {
t.Fatalf("commit still runnable %+v", c)
}
}
}
}
func TestRun(t *testing.T) {
// Create a git repo for testing.
repo, err := ioutil.TempDir("", "benchmany-test")
if err != nil {
t.Fatal("creating temp dir: ", err)
}
defer os.RemoveAll(repo)
tgit(t, repo, "init")
tgit(t, repo, "config", "user.name", "gopher")
tgit(t, repo, "config", "user.email", "gopher@example.com")
// Write benchmark.
err = ioutil.WriteFile(filepath.Join(repo, "x_test.go"), []byte(`
package main
import "testing"
func TestMain(m *testing.M) {
println("BenchmarkX 1 100 ns/op")
}`), 0666)
if err != nil {
t.Fatal("writing x_test.go: ", err)
}
tgit(t, repo, "add", "x_test.go")
tgit(t, repo, "commit", "-m", "initial")
// Create several commits.
var revs []string
for i := 0; i < 3; i++ {
str := fmt.Sprintf("%d", i)
err = ioutil.WriteFile(filepath.Join(repo, "x"), []byte(str), 0666)
if err != nil {
t.Fatal("writing x: ", err)
}
tgit(t, repo, "add", "x")
tgit(t, repo, "commit", "-m", str)
revs = append(revs, trimNL(tgit(t, repo, "rev-parse", "HEAD")))
}
for iters := 4; iters <= 5; iters++ {
// Run benchmark.
tgit(t, repo, "checkout", "master")
oldArgs := os.Args
oldWD, err := os.Getwd()
if err != nil {
t.Fatal("Getwd: ", err)
}
os.Args = []string{os.Args[0], "-n", fmt.Sprintf("%d", iters), "HEAD~3..HEAD"}
os.Chdir(repo)
defer func() {
os.Args = oldArgs
os.Chdir(oldWD)
}()
main()
// Check results.
f, err := os.Open(filepath.Join(repo, "bench.log"))
if err != nil {
t.Fatal("opening bench.log: ", err)
}
defer f.Close()
bs, err := bench.Parse(f)
if err != nil {
t.Fatal("malformed benchmark log: ", err)
}
counts := make(map[string]int)
for _, b := range bs {
t.Log(b, b.Config["commit"].RawValue)
counts[b.Config["commit"].RawValue]++
if uname, ok := b.Config["uname-sr"]; !ok {
t.Errorf("missing uname-sr config")
} else {
t.Logf("uname-sr: %s", uname)
}
}
for _, rev := range revs {
if counts[rev] != iters {
t.Errorf("expected %d results for %s, got %d", iters, rev, counts[rev])
}
}
}
}
func tgit(t *testing.T, repo string, args ...string) string {
cmd := exec.Command("git", args...)
cmd.Dir = repo
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("git %s failed: %v\n%s", args, err, out)
}
return string(out)
}
================================================
FILE: benchmany/signal_notunix.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build plan9 windows
package main
import "os"
var signalTrace os.Signal = nil
================================================
FILE: benchmany/signal_unix.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !plan9,!windows
package main
import (
"os"
"syscall"
)
var signalTrace os.Signal = syscall.SIGQUIT
================================================
FILE: benchmany/status.go
================================================
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"fmt"
"math"
"os"
"time"
"github.com/aclements/go-moremath/fit"
"golang.org/x/crypto/ssh/terminal"
)
type StatusReporter struct {
update chan<- statusUpdate
done chan bool
}
type statusUpdate struct {
progress float64
message string
}
func NewStatusReporter() *StatusReporter {
if os.Getenv("TERM") == "dumb" || !terminal.IsTerminal(1) {
return &StatusReporter{}
}
update := make(chan statusUpdate)
sr := &StatusReporter{update: update}
go sr.loop(update)
return sr
}
func (sr *StatusReporter) Progress(msg string, frac float64) {
if sr.update != nil {
sr.update <- statusUpdate{message: msg, progress: frac}
}
}
func (sr *StatusReporter) Message(msg string) {
if sr.update == nil {
fmt.Println(msg)
} else {
sr.update <- statusUpdate{message: msg, progress: -1}
}
}
func (sr *StatusReporter) Stop() {
if sr.update != nil {
sr.done = make(chan bool)
close(sr.update)
<-sr.done
sr.update = nil
}
}
func (sr *StatusReporter) loop(updates <-chan statusUpdate) {
const resetLine = "\r\x1b[2K"
const wrapOff = "\x1b[?7l"
const wrapOn = "\x1b[?7h"
tick := time.NewTicker(time.Second / 4)
defer tick.Stop()
var end time.Time
t0 := time.Now()
var times, progress, weights []float64
var msg string
for {
select {
case update, ok := <-updates:
if !ok {
fmt.Print(resetLine)
close(sr.done)
return
}
if update.progress == -1 {
fmt.Print(resetLine)
fmt.Println(update.message)
break
}
now := float64(time.Now().Sub(t0))
times = append(times, float64(now))
progress = append(progress, update.progress)
weights = append(weights, 0)
msg = update.message
// Compute ETA using linear regression with
// exponentially decaying weights.
const halfLife = 150 * time.Second
for i, t := range times {
weights[i] = math.Exp(-1 / float64(halfLife) * (now - t))
}
reg := fit.PolynomialRegression(times, progress, weights, 1)
a, b := reg.Coefficients[0], reg.Coefficients[1]
// The intercept of a + b*x - 1 is the ending
// time.
if b == 0 {
end = time.Time{}
} else {
end = t0.Add(time.Duration((1 - a) / b))
}
case <-tick.C:
}
var eta string
if end.IsZero() {
eta = "unknown"
} else {
etaDur := end.Sub(time.Now())
// Trim off sub-second precision.
etaDur -= etaDur % time.Second
if etaDur <= 0 {
eta = "0s"
} else {
eta = etaDur.String()
}
}
if msg == "" {
eta = "ETA " + eta
} else {
eta = ", ETA " + eta
}
// TODO: This isn't quite right. If we hit the right
// edge of the terminal, it won't wrap, but the
// right-most character will be the *last* character
// in the string, since terminal keeps overwriting it.
fmt.Printf("%s%s%s%s%s", resetLine, wrapOff, msg, eta, wrapOn)
}
}
================================================
FILE: benchplot/git.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"log"
"os"
"os/exec"
"regexp"
"strings"
"time"
)
type CommitInfo struct {
Hash, Subject, Branch string
AuthorDate, CommitDate time.Time
Parents, Children []string
}
func Commits(repo string, revs ...string) (commits []CommitInfo) {
args := []string{"-C", repo, "log", "-s",
"--format=format:%H %aI %cI %P\n%s\n"}
if len(revs) == 0 {
args = append(args, "--all")
} else {
args = append(append(args, "--"), revs...)
}
cmd := exec.Command("git", args...)
cmd.Stderr = os.Stderr
out, err := cmd.Output()
if err != nil {
log.Fatal("git show failed: ", err)
}
for _, line := range strings.Split(string(out), "\n\n") {
parts := strings.Split(line, "\n")
subject := parts[1]
parts = strings.Split(parts[0], " ")
adate, err := time.Parse(time.RFC3339, parts[1])
if err != nil {
log.Fatal("cannot parse author date: ", err)
}
cdate, err := time.Parse(time.RFC3339, parts[2])
if err != nil {
log.Fatal("cannot parse commit date: ", err)
}
commits = append(commits, CommitInfo{
parts[0], subject, "", adate, cdate,
parts[3:], nil,
})
}
// Compute hash indexes.
hashset := make(map[string]*CommitInfo)
for i := range commits {
hashset[commits[i].Hash] = &commits[i]
}
// Compute children hashes.
for h, ci := range hashset {
for _, parent := range ci.Parents {
if ci2, ok := hashset[parent]; ok {
ci2.Children = append(ci2.Children, h)
}
}
}
// Compute branch names.
var branchRe = regexp.MustCompile(`^\[[^] ]+\] `)
var branchOf func(ci *CommitInfo) string
branchOf = func(ci *CommitInfo) string {
subject := ci.Subject
if strings.HasPrefix(subject, "[") {
m := branchRe.FindString(subject)
if m != "" {
return m[1 : len(m)-2]
}
}
if strings.HasPrefix(subject, "Merge") || strings.HasPrefix(subject, "Revert") {
// Walk children looking for a branch name.
for _, child := range ci.Children {
if ci2 := hashset[child]; ci2 != nil {
branch := branchOf(ci2)
if branch != "master" {
return branch
}
}
}
}
return "master"
}
for _, ci := range hashset {
ci.Branch = branchOf(ci)
}
// Clean up missing branch tags: if all parents and children
// of a commit have the same non-master branch, that commit
// must also have been from that branch.
cleanBranches:
for _, ci := range hashset {
if ci.Branch == "master" {
alt := ""
for _, child := range ci.Children {
if ci2 := hashset[child]; ci2 != nil {
if alt == "" {
alt = ci2.Branch
} else if ci2.Branch != alt {
continue cleanBranches
}
}
}
for _, parent := range ci.Parents {
if ci2 := hashset[parent]; ci2 != nil {
if alt == "" {
alt = ci2.Branch
} else if ci2.Branch != alt {
continue cleanBranches
}
}
}
if alt != "" {
ci.Branch = alt
}
}
}
return
}
================================================
FILE: benchplot/kza.go
================================================
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import "math"
// TODO: This all assumes that data is sampled at a regular interval
// and there are no missing values. It could be generalized to accept
// missing values (perhaps represented by NaN), or generalized much
// further by accepting (t, x) pairs and a vector of times at which to
// evaluate the filter (and an arbitrary window size). I would have to
// figure out how that affects the difference array in KZA.
// TODO: These can generate a lot of garbage. Perhaps the caller
// should pass in the target slice? Or these should just overwrite the
// input array and leave it to the caller to copy if necessary?
// MovingAverage performs a moving average (MA) filter of xs with
// window size m. m must be a positive odd integer.
//
// Note that this is filter is often described in terms of the half
// length of the window (m-1)/2.
func MovingAverage(xs []float64, m int) []float64 {
if m <= 0 || m%2 != 1 {
panic("m must be a positive, odd integer")
}
ys := make([]float64, len(xs))
sum, n := 0.0, 0
for l, i, r := -m, -(m-1)/2, 0; i < len(ys); l, i, r = l+1, i+1, r+1 {
if l >= 0 {
sum -= xs[l]
n--
}
if r < len(xs) {
sum += xs[r]
n++
}
if i >= 0 {
ys[i] = sum / float64(n)
}
}
return ys
}
// KolmogorovZurbenko performs a Kolmogorov-Zurbenko (KZ) filter of xs
// with window size m and k iterations. m must be a positive odd
// integer. k must be positive.
func KolmogorovZurbenko(xs []float64, m, k int) []float64 {
// k is typically small, and MA is quite efficient, so just do
// the iterated moving average rather than bothering to
// compute the binomial coefficient kernel.
for i := 0; i < k; i++ {
// TODO: Generate less garbage.
xs = MovingAverage(xs, m)
}
return xs
}
// AdaptiveKolmogorovZurbenko performs an adaptive Kolmogorov-Zurbenko
// (KZA) filter of xs using an initial window size m and k iterations.
// m must be a positive odd integer. k must be positive.
//
// See Zurbenko, et al. 1996: Detecting discontinuities in time series
// of upper air data: Demonstration of an adaptive filter technique.
// Journal of Climate, 9, 3548–3560.
func AdaptiveKolmogorovZurbenko(xs []float64, m, k int) []float64 {
// Perform initial KZ filter.
z := KolmogorovZurbenko(xs, m, k)
// Compute differenced values.
q := (m - 1) / 2
d := make([]float64, len(z)+1)
maxD := 0.0
for i := q; i < len(z)-q; i++ {
d[i] = math.Abs(z[i+q] - z[i-q])
if d[i] > maxD {
maxD = d[i]
}
}
if maxD == 0 {
// xs is constant, so no amount of filtering will do
// anything. Avoid dividing 0/0 below.
return xs
}
// Compute adaptive filter.
ys := make([]float64, len(xs))
for t := range ys {
dPrime := d[t+1] - d[t]
f := 1 - d[t]/maxD
qt := q
if dPrime <= 0 {
// Zurbenko doesn't specify what to do with
// the fractional part of qt and qh, so we
// interpret this as summing all points of xs
// between qt and qh.
qt = int(math.Ceil(float64(q) * f))
}
if t-qt < 0 {
qt = t
}
qh := q
if dPrime >= 0 {
qh = int(math.Floor(float64(q) * f))
}
if t+qh >= len(xs) {
qh = len(xs) - t - 1
}
sum := 0.0
for i := t - qt; i <= t+qh; i++ {
sum += xs[i]
}
// Zurbenko divides by qh+qt, but this undercounts the
// number of terms in the sum by 1.
ys[t] = sum / float64(qh+qt+1)
}
return ys
}
================================================
FILE: benchplot/kza_test.go
================================================
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"math/rand"
"testing"
)
// Aeq returns true if expect and got are equal to 8 significant
// figures (1 part in 100 million).
func Aeq(expect, got float64) bool {
if expect < 0 && got < 0 {
expect, got = -expect, -got
}
return expect*0.99999999 <= got && got*0.99999999 <= expect
}
func TestMovingAverage(t *testing.T) {
// Test MovingAverage against the obvious (but slow)
// implementation.
xs := make([]float64, 100)
for iter := 0; iter < 10; iter++ {
for i := range xs {
xs[i] = rand.Float64()
}
m := 1 + 2*rand.Intn(100)
ys1, ys2 := MovingAverage(xs, m), slowMovingAverage(xs, m)
// TODO: Use stuff from mathtest.
for i, y1 := range ys1 {
if !Aeq(y1, ys2[i]) {
t.Fatalf("want %v, got %v", ys2, ys1)
}
}
}
}
func slowMovingAverage(xs []float64, m int) []float64 {
ys := make([]float64, len(xs))
for i := range ys {
psum, n := 0.0, 0
for j := i - (m-1)/2; j <= i+(m-1)/2; j++ {
if 0 <= j && j < len(xs) {
psum += xs[j]
n++
}
}
ys[i] = psum / float64(n)
}
return ys
}
================================================
FILE: benchplot/main.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Command benchplot plots the results of benchmarks over time.
//
// benchplot takes an input file in Go benchmark format [1]. Each
// benchmark result must have a "commit" configuration key that gives
// the full commit hash of the revision that gave that result.
// benchplot will cross-reference these hashes against the specified
// Git repository and plot each metric over time for each benchmark.
//
// [1] https://github.com/golang/proposal/blob/master/design/14313-benchmark-format.md
package main
import (
"bytes"
"flag"
"fmt"
"log"
"os"
"os/exec"
"runtime"
"runtime/pprof"
"strings"
"github.com/aclements/go-gg/gg"
"github.com/aclements/go-gg/table"
"github.com/aclements/go-misc/bench"
)
func main() {
log.SetPrefix("benchplot: ")
log.SetFlags(0)
defaultGitDir, _ := exec.Command("git", "rev-parse", "--show-toplevel").Output()
defaultGitDir = bytes.TrimRight(defaultGitDir, "\n")
var (
flagCPUProfile = flag.String("cpuprofile", "", "write CPU profile to `file`")
flagMemProfile = flag.String("memprofile", "", "write heap profile to `file`")
flagGitDir = flag.String("C", string(defaultGitDir), "run git in `dir`")
flagOut = flag.String("o", "", "write output to `file` (default: stdout)")
flagTable = flag.Bool("table", false, "output a table instead of a plot")
)
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage: %s [flags] [inputs...]\n", os.Args[0])
flag.PrintDefaults()
}
flag.Parse()
if *flagCPUProfile != "" {
f, err := os.Create(*flagCPUProfile)
if err != nil {
log.Fatal(err)
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
}
if *flagMemProfile != "" {
defer func() {
runtime.GC()
f, err := os.Create(*flagMemProfile)
if err != nil {
log.Fatal(err)
}
pprof.WriteHeapProfile(f)
f.Close()
}()
}
// Parse benchmark inputs.
paths := flag.Args()
if len(paths) == 0 {
paths = []string{"-"}
}
var benchmarks []*bench.Benchmark
for _, path := range paths {
func() {
f := os.Stdin
if path != "-" {
var err error
f, err = os.Open(path)
if err != nil {
log.Fatal(err)
}
defer f.Close()
}
bs, err := bench.Parse(f)
if err != nil {
log.Fatal(err)
}
benchmarks = append(benchmarks, bs...)
}()
}
bench.ParseValues(benchmarks, nil)
// Prepare gg tables.
var tab table.Grouping
btab, configCols, resultCols := benchmarksToTable(benchmarks)
if btab.Column("commit") == nil {
tab = btab
} else {
gtab := commitsToTable(Commits(*flagGitDir))
tab = table.Join(btab, "commit", gtab, "commit")
}
// Prepare for output.
f := os.Stdout
if *flagOut != "" {
var err error
f, err = os.Create(*flagOut)
if err != nil {
log.Fatal(err)
}
defer f.Close()
}
// Output table.
if *flagTable {
table.Fprint(f, tab)
return
}
// Plot.
//
// TODO: Collect nrows/ncols from the plot itself.
p, nrows, ncols := plot(tab, configCols, resultCols)
if !(len(paths) == 1 && paths[0] == "-") {
p.Add(gg.Title(strings.Join(paths, " ")))
}
// Render plot.
p.WriteSVG(f, 500*ncols, 350*nrows)
}
================================================
FILE: benchplot/plot.go
================================================
package main
import (
"fmt"
"math"
"github.com/aclements/go-gg/generic/slice"
"github.com/aclements/go-gg/gg"
"github.com/aclements/go-gg/ggstat"
"github.com/aclements/go-gg/table"
)
// TODO: Support plotting non-normalized results.
func plot(t table.Grouping, configCols, resultCols []string) (*gg.Plot, int, int) {
//t = table.Flatten(table.HeadTables(table.GroupBy(t, "name"), 9))
// Filter to just the master branch.
//
// TODO: Flag to control this? Or separate filter command? Or
// accept a filter expression in the argument?
t = table.FilterEq(t, "branch", "master")
// Compute rows and columns.
ncols := len(resultCols)
nrows := len(table.GroupBy(t, "name").Tables())
plot := gg.NewPlot(t)
// Turn ordered commit date into a "commit index" column.
plot.SortBy("commit date")
plot.Stat(commitIndex{})
// Average each result at each commit (but keep columns names
// the same to keep things easier to read).
plot.Stat(ggstat.Agg("commit", "name")(ggstat.AggMean(resultCols...)))
for _, rcol := range resultCols {
plot.SetData(table.Rename(plot.Data(), "mean "+rcol, rcol))
}
// Unpivot all of the metrics into one column.
plot.Stat(convertFloat{resultCols})
plot.SetData(table.Unpivot(plot.Data(), "metric", "result", resultCols...))
y := "result"
// Normalize to earliest commit on master. It's important to
// do this before the geomean if there are commits missing.
// Unfortunately, that also means we have to *temporarily*
// group by name and metric, since the geomean needs to be
// done on a different grouping.
plot.GroupBy("name", "metric")
plot.Stat(ggstat.Normalize{X: "branch", By: firstMasterIndex, Cols: []string{"result"}})
y = "normalized " + y
plot.SetData(table.Remove(plot.Data(), "result"))
plot.SetData(table.Ungroup(table.Ungroup(plot.Data())))
// Compute geomean for each metric at each commit if there's
// more than one benchmark.
if len(table.GroupBy(t, "name").Tables()) > 1 {
gt := removeNaNs(plot.Data(), y)
gt = ggstat.Agg("commit", "metric")(ggstat.AggGeoMean(y)).F(gt)
gt = table.MapTables(gt, func(_ table.GroupID, t *table.Table) *table.Table {
return table.NewBuilder(t).AddConst("name", " geomean").Done()
})
gt = table.Rename(gt, "geomean "+y, y)
plot.SetData(table.Concat(plot.Data(), gt))
nrows++
}
// Facet by name and metric.
plot.Add(gg.FacetY{Col: "name"}, gg.FacetX{Col: "metric"})
// Filter the data to reduce noise.
plot.Stat(kza{y, 15, 3})
y = "filtered " + y
// Always show Y=0.
plot.SetScale("y", gg.NewLinearScaler().Include(0))
plot.Add(gg.LayerLines{
X: "commit index",
Y: y,
//Color: "branch",
})
// plot.Add(gg.LayerTags{X: "commit index", Y: y, Label: "branch"})
// Interactive tooltip with short hash.
plot.Stat(tooltip{y})
plot.Add(gg.LayerTooltips{X: "commit index", Y: y, Label: "tooltip"})
return plot, nrows, ncols
}
func firstMasterIndex(bs []string) int {
return slice.Index(bs, "master")
}
type commitIndex struct{}
func (commitIndex) F(g table.Grouping) table.Grouping {
return table.MapTables(g, func(_ table.GroupID, t *table.Table) *table.Table {
idxs := make([]int, t.Len())
last, idx := "", -1
for i, hash := range t.MustColumn("commit").([]string) {
if hash != last {
idx++
last = hash
}
idxs[i] = idx
}
t = table.NewBuilder(t).Add("commit index", idxs).Done()
return t
})
}
type convertFloat struct {
cols []string
}
func (c convertFloat) F(g table.Grouping) table.Grouping {
return table.MapTables(g, func(_ table.GroupID, t *table.Table) *table.Table {
b := table.NewBuilder(t)
for _, col := range c.cols {
var ncol []float64
slice.Convert(&ncol, t.MustColumn(col))
b.Add(col, ncol)
}
return b.Done()
})
}
func removeNaNs(g table.Grouping, col string) table.Grouping {
return table.Filter(g, func(result float64) bool {
return !math.IsNaN(result)
}, col)
}
type kza struct {
X string
M, K int
}
func (k kza) F(g table.Grouping) table.Grouping {
return table.MapTables(g, func(_ table.GroupID, t *table.Table) *table.Table {
var xs []float64
slice.Convert(&xs, t.MustColumn(k.X))
nxs := AdaptiveKolmogorovZurbenko(xs, k.M, k.K)
return table.NewBuilder(t).Add("filtered "+k.X, nxs).Done()
})
}
type tooltip struct {
Y string
}
func (t tooltip) F(g table.Grouping) table.Grouping {
return table.MapCols(g,
func(commit []string, result []float64, tooltip []string) {
for i, c := range commit {
tooltip[i] = fmt.Sprintf("%s %.2fX", c[:7], result[i])
}
}, "commit", t.Y)("tooltip")
}
================================================
FILE: benchplot/table.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"math"
"reflect"
"sort"
"strings"
"time"
"github.com/aclements/go-gg/table"
"github.com/aclements/go-misc/bench"
)
func benchmarksToTable(bs []*bench.Benchmark) (t *table.Table, configCols, resultCols []string) {
// Gather name, config, and result columns.
nan := math.NaN()
names := make([]string, len(bs))
configs, results := map[string]reflect.Value{}, map[string][]float64{}
for i, b := range bs {
names[i] = b.Name
for k, c := range b.Config {
seq, ok := configs[k]
if !ok {
t := reflect.SliceOf(reflect.TypeOf(c.Value))
seq = reflect.MakeSlice(t, len(bs), len(bs))
configs[k] = seq
}
seq.Index(i).Set(reflect.ValueOf(c.Value))
}
for k, v := range b.Result {
seq, ok := results[k]
if !ok {
seq = make([]float64, len(bs))
for i := range seq {
seq[i] = nan
}
results[k] = seq
}
seq[i] = v
}
}
// Build table.
tab := new(table.Builder).Add("name", names)
keys := make([]string, 0, len(configs))
for k := range configs {
keys = append(keys, k)
}
sort.Strings(keys)
for _, key := range keys {
nicekey := strings.Replace(key, "-", " ", -1)
niceval := configs[key].Interface()
if n, ok := niceval.([]time.Time); ok {
niceval = byTime(n)
}
tab.Add(nicekey, niceval)
configCols = append(configCols, nicekey)
}
keys = make([]string, 0, len(results))
for k := range results {
keys = append(keys, k)
}
sort.Strings(keys)
for _, key := range keys {
nicekey := strings.Replace(key, "-", " ", -1)
if nicekey == "ns/op" {
// TODO: Use the unit parser from benchstat.
nicekey = "time/op"
durations := make([]time.Duration, len(results[key]))
for i, x := range results[key] {
durations[i] = time.Duration(x)
}
tab.Add(nicekey, durations)
} else {
tab.Add(nicekey, results[key])
}
resultCols = append(resultCols, nicekey)
}
return tab.Done(), configCols, resultCols
}
func commitsToTable(commits []CommitInfo) *table.Table {
hashCol := make([]string, len(commits))
authorDateCol := make(byTime, len(commits))
commitDateCol := make(byTime, len(commits))
branchCol := make([]string, len(commits))
j := 0
for i := range commits {
ci := &commits[i]
hashCol[j] = ci.Hash
authorDateCol[j] = ci.AuthorDate
commitDateCol[j] = ci.CommitDate
branchCol[j] = ci.Branch
j++
}
return new(table.Builder).
Add("commit", hashCol).
Add("author date", authorDateCol).
Add("commit date", commitDateCol).
Add("branch", branchCol).
Done()
}
type byTime []time.Time
func (s byTime) Len() int {
return len(s)
}
func (s byTime) Less(i, j int) bool {
return s[i].Before(s[j])
}
func (s byTime) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/LICENSE
================================================
Copyright (c) 2016 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/README.md
================================================
# gg [](https://godoc.org/github.com/aclements/go-gg)
gg is a plotting package for Go inspired by the Grammar of Graphics.
Note that gg is currently very experimental and the API is still in
flux. Please vendor this package before using it.
To fetch gg, run
go get github.com/aclements/go-gg
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/doc.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package generic provides type-generic functions.
package generic
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/error.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package generic
import "reflect"
type TypeError struct {
Type1, Type2 reflect.Type
Extra string
}
func (e TypeError) Error() string {
msg := e.Type1.String()
if e.Type2 != nil {
msg += " and " + e.Type2.String()
}
msg += " " + e.Extra
return msg
}
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/order.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package generic
import "reflect"
// CanOrder returns whether the values a and b are orderable according
// to the Go language specification.
func CanOrder(a, b interface{}) bool {
ak, bk := reflect.ValueOf(a).Kind(), reflect.ValueOf(b).Kind()
if ak != bk {
return false
}
return CanOrderR(ak)
}
var orderable = map[reflect.Kind]bool{
reflect.Int: true,
reflect.Int8: true,
reflect.Int16: true,
reflect.Int32: true,
reflect.Int64: true,
reflect.Uint: true,
reflect.Uintptr: true,
reflect.Uint8: true,
reflect.Uint16: true,
reflect.Uint32: true,
reflect.Uint64: true,
reflect.Float32: true,
reflect.Float64: true,
reflect.String: true,
}
// CanOrderR returns whether two values of kind k are orderable
// according to the Go language specification.
func CanOrderR(k reflect.Kind) bool {
return orderable[k]
}
// Order returns the order of values a and b: -1 if a < b, 0 if a ==
// b, 1 if a > b. The results are undefined if either a or b is NaN.
//
// Order panics if a and b are not orderable according to the Go
// language specification.
func Order(a, b interface{}) int {
return OrderR(reflect.ValueOf(a), reflect.ValueOf(b))
}
// OrderR is equivalent to Order, but operates on reflect.Values.
func OrderR(a, b reflect.Value) int {
if a.Kind() != b.Kind() {
panic(&TypeError{a.Type(), b.Type(), "are not orderable because they are different kinds"})
}
switch a.Kind() {
case reflect.Float32, reflect.Float64:
a, b := a.Float(), b.Float()
if a < b {
return -1
} else if a > b {
return 1
}
return 0
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
a, b := a.Int(), b.Int()
if a < b {
return -1
} else if a > b {
return 1
}
return 0
case reflect.Uint, reflect.Uintptr, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
a, b := a.Uint(), b.Uint()
if a < b {
return -1
} else if a > b {
return 1
}
return 0
case reflect.String:
a, b := a.String(), b.String()
if a < b {
return -1
} else if a > b {
return 1
}
return 0
}
panic(&TypeError{a.Type(), nil, "is not orderable"})
}
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/concat.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package slice
import (
"reflect"
"github.com/aclements/go-gg/generic"
)
// Concat returns the concatenation of all of ss. The types of all of
// the arguments must be identical or Concat will panic with a
// *generic.TypeError. The returned slice will have the same type as the
// inputs. If there are 0 arguments, Concat returns nil. Concat does
// not modify any of the input slices.
func Concat(ss ...T) T {
if len(ss) == 0 {
return nil
}
rvs := make([]reflect.Value, len(ss))
total := 0
var typ reflect.Type
for i, s := range ss {
rvs[i] = reflectSlice(s)
total += rvs[i].Len()
if i == 0 {
typ = rvs[i].Type()
} else if rvs[i].Type() != typ {
panic(&generic.TypeError{typ, rvs[i].Type(), "have different types"})
}
}
out := reflect.MakeSlice(typ, 0, total)
for _, rv := range rvs {
out = reflect.AppendSlice(out, rv)
}
return out.Interface()
}
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/concat_test.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package slice
import "testing"
func TestConcat(t *testing.T) {
if g := Concat(); g != nil {
t.Errorf("Concat() should be nil; got %v", g)
}
if g, w := Concat([]int{}), []int{}; !de(w, g) {
t.Errorf("want %v; got %v", w, g)
}
if g, w := Concat([]int(nil)), []int{}; !de(w, g) {
t.Errorf("want %v; got %v", w, g)
}
if g, w := Concat([]int{1, 2}, []int{3, 4}), []int{1, 2, 3, 4}; !de(w, g) {
t.Errorf("want %v; got %v", w, g)
}
shouldPanic(t, "have different types", func() {
Concat([]int{}, []string{})
})
}
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/convert.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package slice
import (
"reflect"
"github.com/aclements/go-gg/generic"
)
// Convert converts each element in from and assigns it to *to. to
// must be a pointer to a slice. Convert slices or extends *to to
// len(from) and then assigns to[i] = T(from[i]) where T is the type
// of *to's elements. If from and *to have the same element type, it
// simply assigns *to = from.
func Convert(to interface{}, from T) {
fv := reflectSlice(from)
tv := reflect.ValueOf(to)
if tv.Kind() != reflect.Ptr {
panic(&generic.TypeError{tv.Type(), nil, "is not a *[]T"})
}
tst := tv.Type().Elem()
if tst.Kind() != reflect.Slice {
panic(&generic.TypeError{tv.Type(), nil, "is not a *[]T"})
}
if fv.Type().AssignableTo(tst) {
tv.Elem().Set(fv)
return
}
eltt := tst.Elem()
if !fv.Type().Elem().ConvertibleTo(eltt) {
panic(&generic.TypeError{fv.Type(), tst, "cannot be converted"})
}
switch to := to.(type) {
case *[]float64:
// This is extremely common.
*to = (*to)[:0]
for i, len := 0, fv.Len(); i < len; i++ {
*to = append(*to, fv.Index(i).Convert(eltt).Float())
}
default:
tsv := tv.Elem()
tsv.SetLen(0)
for i, len := 0, fv.Len(); i < len; i++ {
tsv = reflect.Append(tsv, fv.Index(i).Convert(eltt))
}
tv.Elem().Set(tsv)
}
}
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/convert_test.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package slice
import "testing"
func TestConvert(t *testing.T) {
var is []int
Convert(&is, []int{1, 2, 3})
if w := []int{1, 2, 3}; !de(w, is) {
t.Errorf("want %v; got %v", w, is)
}
Convert(&is, []float64{1, 2, 3})
if w := []int{1, 2, 3}; !de(w, is) {
t.Errorf("want %v; got %v", w, is)
}
var fs []float64
Convert(&fs, []int{1, 2, 3})
if w := []float64{1, 2, 3}; !de(w, fs) {
t.Errorf("want %v; got %v", w, fs)
}
Convert(&fs, []float64{1, 2, 3})
if w := []float64{1, 2, 3}; !de(w, fs) {
t.Errorf("want %v; got %v", w, fs)
}
shouldPanic(t, "cannot be converted", func() {
Convert(&is, []string{"1", "2", "3"})
})
shouldPanic(t, `is not a \*\[\]T`, func() {
Convert(is, []int{1, 2, 3})
})
shouldPanic(t, `is not a \*\[\]T`, func() {
x := 1
Convert(&x, []int{1, 2, 3})
})
shouldPanic(t, "is not a slice", func() {
Convert(&is, 1)
})
}
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/cycle.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package slice
import "reflect"
// Cycle constructs a slice of length length by repeatedly
// concatenating s to itself. If len(s) >= length, it returns
// s[:length]. Otherwise, it allocates a new slice. If len(s) == 0 and
// length != 0, Cycle panics.
func Cycle(s T, length int) T {
rv := reflectSlice(s)
if rv.Len() >= length {
return rv.Slice(0, length).Interface()
}
if rv.Len() == 0 {
panic("empty slice")
}
// Allocate a new slice of the appropriate length.
out := reflect.MakeSlice(rv.Type(), length, length)
// Copy elements to out.
for pos := 0; pos < length; {
pos += reflect.Copy(out.Slice(pos, length), rv)
}
return out.Interface()
}
// Repeat returns a slice consisting of length copies of v.
func Repeat(v interface{}, length int) T {
if length < 0 {
length = 0
}
rv := reflect.ValueOf(v)
out := reflect.MakeSlice(reflect.SliceOf(rv.Type()), length, length)
for i := 0; i < length; i++ {
out.Index(i).Set(rv)
}
return out.Interface()
}
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/doc.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package slice provides generic slice functions.
package slice
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/find.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package slice
import (
"reflect"
"github.com/aclements/go-gg/generic"
)
// Index returns the index of the first instance of val in s, or -1 if
// val is not present in s. val's type must be s's element type.
func Index(s T, val interface{}) int {
rs := reflectSlice(s)
if vt := reflect.TypeOf(val); rs.Type().Elem() != vt {
// TODO: Better "<seq> is not a sequence of <val>".
panic(&generic.TypeError{rs.Type(), vt, "cannot find"})
}
for i, l := 0, rs.Len(); i < l; i++ {
if rs.Index(i).Interface() == val {
return i
}
}
return -1
}
// LastIndex returns the index of the last instance of val in s, or -1
// if val is not present in s. val's type must be s's element type.
func LastIndex(s T, val interface{}) int {
rs := reflectSlice(s)
if vt := reflect.TypeOf(val); rs.Type().Elem() != vt {
// TODO: Better "<seq> is not a sequence of <val>".
panic(&generic.TypeError{rs.Type(), vt, "cannot find"})
}
for i := rs.Len() - 1; i >= 0; i-- {
if rs.Index(i).Interface() == val {
return i
}
}
return -1
}
// Contains reports whether val is within s. val's type must be s's
// element type.
func Contains(s T, val interface{}) bool {
return Index(s, val) >= 0
}
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/index.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package slice
import (
"reflect"
"github.com/aclements/go-gg/generic"
)
// Select returns a slice w such that w[i] = v[indexes[i]].
func Select(v T, indexes []int) T {
switch v := v.(type) {
case []int:
res := make([]int, len(indexes))
for i, x := range indexes {
res[i] = v[x]
}
return res
case []float64:
res := make([]float64, len(indexes))
for i, x := range indexes {
res[i] = v[x]
}
return res
case []string:
res := make([]string, len(indexes))
for i, x := range indexes {
res[i] = v[x]
}
return res
}
rv := reflectSlice(v)
res := reflect.MakeSlice(rv.Type(), len(indexes), len(indexes))
for i, x := range indexes {
res.Index(i).Set(rv.Index(x))
}
return res.Interface()
}
// SelectInto assigns out[i] = in[indexes[i]]. in and out must have
// the same types and len(out) must be >= len(indexes). If in and out
// overlap, the results are undefined.
func SelectInto(out, in T, indexes []int) {
// TODO: Maybe they should only have to be assignable?
if it, ot := reflect.TypeOf(in), reflect.TypeOf(out); it != ot {
panic(&generic.TypeError{it, ot, "must be the same type"})
}
switch in := in.(type) {
case []int:
out := out.([]int)
for i, x := range indexes {
out[i] = in[x]
}
return
case []float64:
out := out.([]float64)
for i, x := range indexes {
out[i] = in[x]
}
return
case []string:
out := out.([]string)
for i, x := range indexes {
out[i] = in[x]
}
return
}
inv, outv := reflectSlice(in), reflectSlice(out)
for i, x := range indexes {
outv.Index(i).Set(inv.Index(x))
}
}
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/min.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package slice
import (
"reflect"
"sort"
"github.com/aclements/go-gg/generic"
)
// Min returns the minimum value in v. v must either implement
// sort.Interface or its elements must be orderable. Min panics if v
// is empty.
func Min(v T) interface{} {
x, _ := minmax(v, -1, true)
return x.Interface()
}
// ArgMin returns the index of the minimum value in v. If there are
// multiple indexes equal to the minimum value, ArgMin returns the
// lowest of them. v must be a slice whose elements are orderable, or
// must implement sort.Interface. ArgMin panics if v is empty.
func ArgMin(v interface{}) int {
_, i := minmax(v, -1, false)
return i
}
// Max returns the maximum value in v. v must either implement
// sort.Interface or its elements must be orderable. Max panics if v
// is empty.
func Max(v T) interface{} {
x, _ := minmax(v, 1, true)
return x.Interface()
}
// ArgMax returns the index of the maximum value in v. If there are
// multiple indexes equal to the maximum value, ArgMax returns the
// lowest of them. v must be a slice whose elements are orderable, or
// must implement sort.Interface. ArgMax panics if v is empty.
func ArgMax(v interface{}) int {
_, i := minmax(v, 1, false)
return i
}
func minmax(v interface{}, keep int, val bool) (reflect.Value, int) {
switch v := v.(type) {
case sort.Interface:
if v.Len() == 0 {
if keep < 0 {
panic("zero-length sequence has no minimum")
} else {
panic("zero-length sequence has no maximum")
}
}
maxi := 0
if keep < 0 {
for i, len := 0, v.Len(); i < len; i++ {
if v.Less(i, maxi) {
maxi = i
}
}
} else {
for i, len := 0, v.Len(); i < len; i++ {
if v.Less(maxi, i) {
maxi = i
}
}
}
if !val {
return reflect.Value{}, maxi
}
rv := reflectSlice(v)
return rv.Index(maxi), maxi
}
rv := reflectSlice(v)
if !generic.CanOrderR(rv.Type().Elem().Kind()) {
panic(&generic.TypeError{rv.Type().Elem(), nil, "is not orderable"})
}
if rv.Len() == 0 {
if keep < 0 {
panic("zero-length slice has no minimum")
} else {
panic("zero-length slice has no maximum")
}
}
max, maxi := rv.Index(0), 0
for i, len := 1, rv.Len(); i < len; i++ {
if elt := rv.Index(i); generic.OrderR(elt, max) == keep {
max, maxi = elt, i
}
}
return max, maxi
}
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/min_test.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package slice
import (
"math"
"testing"
"time"
)
func TestMin(t *testing.T) {
shouldPanic(t, "no min", func() { Min([]float64{}) })
shouldPanic(t, "no min", func() { ArgMin([]float64{}) })
shouldPanic(t, "no max", func() { Max([]float64{}) })
shouldPanic(t, "no max", func() { ArgMax([]float64{}) })
xs := []float64{5, 1, 8, 1, 8, 3}
if x := Min(xs); x != 1.0 {
t.Errorf("Min should be 1, got %v", x)
}
if x := ArgMin(xs); x != 1 {
t.Errorf("ArgMin should be 1, got %v", x)
}
if x := Max(xs); x != 8.0 {
t.Errorf("Max should be 8, got %v", x)
}
if x := ArgMax(xs); x != 2 {
t.Errorf("ArgMax should be 2, got %v", x)
}
xs = []float64{1, 5, math.NaN()}
if x := Min(xs); x != 1.0 {
t.Errorf("Min should be 1, got %v", x)
}
if x := Max(xs); x != 5.0 {
t.Errorf("Max should be 5, got %v", x)
}
}
type fakeSortInterface struct {
len int
}
func (f fakeSortInterface) Len() int {
return f.len
}
func (f fakeSortInterface) Swap(i, j int) {
panic("can't")
}
func (f fakeSortInterface) Less(i, j int) bool {
return i < j
}
type timeSlice []time.Time
func (s timeSlice) Len() int {
return len(s)
}
func (s timeSlice) Less(i, j int) bool {
return s[i].Before(s[j])
}
func (s timeSlice) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func TestMinSort(t *testing.T) {
shouldPanic(t, "no min", func() { Min(fakeSortInterface{0}) })
shouldPanic(t, "no min", func() { ArgMin(fakeSortInterface{0}) })
shouldPanic(t, "no max", func() { Max(fakeSortInterface{0}) })
shouldPanic(t, "no max", func() { ArgMax(fakeSortInterface{0}) })
f := fakeSortInterface{5}
if x := ArgMin(f); x != 0 {
t.Errorf("ArgMin should be 0, got %v", x)
}
if x := ArgMax(f); x != 4 {
t.Errorf("ArgMax should be 4, got %v", x)
}
z := time.Unix(0, 0)
ts := timeSlice{z.Add(time.Hour), z, z.Add(2 * time.Hour), z.Add(time.Hour)}
if x := Min(ts); x != ts[1] {
t.Errorf("Min should be %v, got %v", ts[1], x)
}
if x := ArgMin(ts); x != 1 {
t.Errorf("ArgMin should be 1, got %v", x)
}
if x := Max(ts); x != ts[2] {
t.Errorf("Max should be %v, got %v", ts[2], x)
}
if x := ArgMax(ts); x != 2 {
t.Errorf("ArgMax should be 2, got %v", x)
}
}
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/nub.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package slice
import "reflect"
var trueVal = reflect.ValueOf(true)
// Nub returns v with duplicates removed. It keeps the first instance
// of each distinct value and preserves their order.
func Nub(v T) T {
rv := reflectSlice(v)
indexes := make([]int, 0)
set := reflect.MakeMap(reflect.MapOf(rv.Type().Elem(), trueVal.Type()))
for i, l := 0, rv.Len(); i < l; i++ {
x := rv.Index(i)
if set.MapIndex(x).IsValid() {
continue
}
set.SetMapIndex(x, trueVal)
indexes = append(indexes, i)
}
return Select(v, indexes)
}
// NubAppend is equivalent to appending all of the slices in vs and
// then calling Nub on the result, but more efficient.
func NubAppend(vs ...T) T {
if len(vs) == 0 {
return nil
}
rv := reflectSlice(vs[0])
set := reflect.MakeMap(reflect.MapOf(rv.Type().Elem(), trueVal.Type()))
out := reflect.MakeSlice(rv.Type(), 0, 0)
for _, v := range vs {
rv := reflectSlice(v)
for i, l := 0, rv.Len(); i < l; i++ {
x := rv.Index(i)
if set.MapIndex(x).IsValid() {
continue
}
set.SetMapIndex(x, trueVal)
out = reflect.Append(out, x)
}
}
return out.Interface()
}
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/select_test.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package slice
import (
"reflect"
"testing"
)
func TestSelect(t *testing.T) {
x1 := []int{1, 2, 3}
got := Select(x1, []int{2, 1, 0})
if want := []int{3, 2, 1}; !reflect.DeepEqual(got, want) {
t.Fatalf("expected %v, got %v", want, got)
}
got = Select(x1, []int{1, 1, 1, 1})
if want := []int{2, 2, 2, 2}; !reflect.DeepEqual(got, want) {
t.Fatalf("expected %v, got %v", want, got)
}
type T struct{ x int }
x2 := []T{{1}, {2}, {3}}
got = Select(x2, []int{2, 1, 0})
if want := []T{{3}, {2}, {1}}; !reflect.DeepEqual(got, want) {
t.Fatalf("expected %v, got %v", want, got)
}
}
func TestSelectType(t *testing.T) {
type T []float64
x1 := T{1, 2, 3}
y1 := Select(x1, []int{})
if _, ok := y1.(T); !ok {
t.Fatalf("result has wrong type; expected T, got %T", y1)
}
type U int
x2 := []U{1, 2, 3}
y2 := Select(x2, []int{})
if _, ok := y2.([]U); !ok {
t.Fatalf("result has wrong type; expected []U, got %T", y2)
}
}
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/seq.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package slice
import (
"reflect"
"github.com/aclements/go-gg/generic"
)
// T is a Go slice value of type []U.
//
// This is primarily for documentation. There is no way to statically
// enforce this in Go; however, functions that expect a slice will
// panic with a *generic.TypeError if passed a non-slice value.
type T interface{}
// reflectSlice checks that s is a slice and returns its
// reflect.Value. It panics with a *generic.TypeError if s is not a slice.
func reflectSlice(s T) reflect.Value {
rv := reflect.ValueOf(s)
if rv.Kind() != reflect.Slice {
panic(&generic.TypeError{rv.Type(), nil, "is not a slice"})
}
return rv
}
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/sort.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package slice
import (
"reflect"
"sort"
"time"
"github.com/aclements/go-gg/generic"
)
// CanSort returns whether the value v can be sorted.
func CanSort(v interface{}) bool {
switch v.(type) {
case sort.Interface, []time.Time:
return true
}
return generic.CanOrderR(reflect.TypeOf(v).Elem().Kind())
}
// Sort sorts v in increasing order. v must implement sort.Interface,
// be a slice whose elements are orderable, or be a []time.Time.
func Sort(v interface{}) {
sort.Sort(Sorter(v))
}
// Sorter returns a sort.Interface for sorting v. v must implement
// sort.Interface, be a slice whose elements are orderable, or be a
// []time.Time.
func Sorter(v interface{}) sort.Interface {
switch v := v.(type) {
case []int:
return sort.IntSlice(v)
case []float64:
return sort.Float64Slice(v)
case []string:
return sort.StringSlice(v)
case []time.Time:
return sortTimeSlice(v)
case sort.Interface:
return v
}
rv := reflectSlice(v)
switch rv.Type().Elem().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return sortIntSlice{rv}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return sortUintSlice{rv}
case reflect.Float32, reflect.Float64:
return sortFloatSlice{rv}
case reflect.String:
return sortStringSlice{rv}
}
panic(&generic.TypeError{rv.Type().Elem(), nil, "is not orderable"})
}
type sortIntSlice struct {
reflect.Value
}
func (s sortIntSlice) Len() int {
return s.Value.Len()
}
func (s sortIntSlice) Less(i, j int) bool {
return s.Index(i).Int() < s.Index(j).Int()
}
func (s sortIntSlice) Swap(i, j int) {
a, b := s.Index(i).Int(), s.Index(j).Int()
s.Index(i).SetInt(b)
s.Index(j).SetInt(a)
}
type sortUintSlice struct {
reflect.Value
}
func (s sortUintSlice) Len() int {
return s.Value.Len()
}
func (s sortUintSlice) Less(i, j int) bool {
return s.Index(i).Uint() < s.Index(j).Uint()
}
func (s sortUintSlice) Swap(i, j int) {
a, b := s.Index(i).Uint(), s.Index(j).Uint()
s.Index(i).SetUint(b)
s.Index(j).SetUint(a)
}
type sortFloatSlice struct {
reflect.Value
}
func (s sortFloatSlice) Len() int {
return s.Value.Len()
}
func (s sortFloatSlice) Less(i, j int) bool {
return s.Index(i).Float() < s.Index(j).Float()
}
func (s sortFloatSlice) Swap(i, j int) {
a, b := s.Index(i).Float(), s.Index(j).Float()
s.Index(i).SetFloat(b)
s.Index(j).SetFloat(a)
}
type sortStringSlice struct {
reflect.Value
}
func (s sortStringSlice) Len() int {
return s.Value.Len()
}
func (s sortStringSlice) Less(i, j int) bool {
return s.Index(i).String() < s.Index(j).String()
}
func (s sortStringSlice) Swap(i, j int) {
a, b := s.Index(i).String(), s.Index(j).String()
s.Index(i).SetString(b)
s.Index(j).SetString(a)
}
type sortTimeSlice []time.Time
func (s sortTimeSlice) Len() int { return len(s) }
func (s sortTimeSlice) Less(i, j int) bool { return s[i].Before(s[j]) }
func (s sortTimeSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/util_test.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package slice
import (
"fmt"
"reflect"
"regexp"
"testing"
)
func de(x, y interface{}) bool {
return reflect.DeepEqual(x, y)
}
func shouldPanic(t *testing.T, re string, f func()) {
r := regexp.MustCompile(re)
defer func() {
err := recover()
if err == nil {
t.Fatalf("want panic matching %q; got no panic", re)
} else if !r.MatchString(fmt.Sprintf("%s", err)) {
t.Fatalf("want panic matching %q; got %s", re, err)
}
}()
f()
}
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/gg/example_scale_test.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gg
import (
"fmt"
"math/rand"
"os"
"time"
"github.com/aclements/go-gg/table"
)
func ExampleNewTimeScaler() {
var x []time.Time
var y []float64
var steps []time.Duration
for _, step := range []time.Duration{
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
time.Minute, time.Hour, 24 * time.Hour, 7 * 24 * time.Hour,
} {
t := time.Now()
for i := 0; i < 100; i++ {
x = append(x, t)
y = append(y, rand.Float64()-.5)
steps = append(steps, 100*step)
t = t.Add(-step)
}
}
tb := table.NewBuilder(nil)
tb.Add("x", x).Add("y", y).Add("steps", steps)
plot := NewPlot(tb.Done())
plot.SetScale("x", NewTimeScaler())
plot.Add(FacetY{
Col: "steps",
SplitXScales: true,
})
plot.Add(LayerLines{
X: "x",
Y: "y",
})
f, err := os.Create("scale_time.svg")
if err != nil {
panic("unable to create scale_time.svg")
}
defer f.Close()
plot.WriteSVG(f, 800, 1000)
fmt.Println("ok")
// output:
// ok
}
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/gg/facet.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gg
import (
"fmt"
"math"
"reflect"
"github.com/aclements/go-gg/generic"
"github.com/aclements/go-gg/generic/slice"
"github.com/aclements/go-gg/table"
)
// TODO: What if there are already layers? Maybe they should be
// repeated in all facets. ggplot2 apparently does this when the
// faceting variable isn't in one of the data frames.
// TODO: Subplot is getting rather complicated. If I want to make
// facets only use public APIs, perhaps gg itself should only know
// about some interface for table group labels that provides a layout
// manager and the layout logic should live with the facets.
// TODO: This is very nearly flexible enough to make pairwise plots.
// TODO: Is this flexible enough to make marginal distribution plots?
// TODO: There's logical overlap between how a facet chooses to
// position and label a subplot and a discrete-ranged scalar. Perhaps
// facets should use scalars to chose positions and labels?
// FacetCommon is the base type for plot faceting operations. Faceting
// is a grouping operation that subdivides a plot into subplots based
// on the values in data column. Faceting operations may be composed:
// if a faceting operation has already divided the plot into subplots,
// a further faceting operation will subdivide each of those subplots.
type FacetCommon struct {
// Col names the column to facet by. Each distinct value of
// this column will become a separate plot. If Col is
// orderable, the facets will be in value order; otherwise,
// they will be in index order.
Col string
// SplitXScales indicates that each band (column for FacetX;
// row for FacetY) created by this faceting operation should
// have separate X axis scales. The default, false, indicates
// that subplots should continue to share X scales.
//
// SplitXScales and SplitYScales, combined with facet
// composition, give a great deal of control over how scales
// are shared. Suppose you want to create an X/Y facet grid by
// first performing a FacetX and then a FacetY. Here are some
// common ways to share or split the scales:
//
// * To share the same scales between all subplots, set both
// flags to false in both facet operations.
//
// * To have independent scales in all subplots, set both
// flags to true in the FacetY (and it doesn't matter what
// they are in the FacetX).
//
// * To share the X scale within each column and the Y scale
// within each row, set SplitXScales in the FacetX and
// SplitYScales in the FacetY.
SplitXScales bool
// SplitYScales is the equivalent of SplitXScales for Y axis
// scales.
SplitYScales bool
// Labeler is a function that constructs facet labels from
// data values. If this is nil, the default is fmt.Sprint.
//
// TODO: Call this through reflect to get the argument type
// right?
Labeler func(interface{}) string
// Rows and Cols specify the number of rows or columns for
// FacetWrap. If both are zero, FacetWrap chooses reasonable
// defaults. Otherwise, one or the other should be zero.
Rows, Cols int
// TODO: Wrap order and label side for FacetWrap.
}
// FacetX splits a plot into columns.
type FacetX FacetCommon
// FacetY splits a plot into rows.
type FacetY FacetCommon
// FacetWrap splits a plot into a grid of rows and columns.
type FacetWrap FacetCommon
func (f FacetX) Apply(p *Plot) {
(*FacetCommon)(&f).apply(p, "x")
}
func (f FacetY) Apply(p *Plot) {
(*FacetCommon)(&f).apply(p, "y")
}
func (f FacetWrap) Apply(p *Plot) {
(*FacetCommon)(&f).apply(p, "-")
}
func (f *FacetCommon) apply(p *Plot, dir string) {
if f.Labeler == nil {
f.Labeler = func(x interface{}) string { return fmt.Sprint(x) }
}
grouped := table.GroupBy(p.Data(), f.Col)
// TODO: What should this do if there are multiple faceting
// operations and the results aren't a complete cross-product?
// Using GroupBy to form the initial faceting groups will
// leave out subplots with no data. Alternatively, I could
// base this on the total set of values and force there to be
// a complete cross-product.
// TODO: If this is, say, and X faceting and different
// existing columns have different sets of values, should I
// only split a column on the values it has? Doing that right
// would require grouping existing subplots in potentially
// complex ways (for example, if I do a FacetWrap and then a
// FacetX, grouping subplots by column alone will be wrong.)
// Collect grouped values. If there was already grouping
// structure, it's possible we'll have multiple groups with
// the same value for Col.
type valInfo struct {
index int
label string
}
var valType reflect.Type
vals := make(map[interface{}]*valInfo)
for i, gid := range grouped.Tables() {
val := gid.Label()
if _, ok := vals[val]; !ok {
vals[val] = &valInfo{len(vals), f.Labeler(val)}
}
if i == 0 {
valType = reflect.TypeOf(val)
}
}
// If f.Col is orderable, order and re-index values.
if generic.CanOrderR(valType.Kind()) {
valSeq := reflect.MakeSlice(reflect.SliceOf(valType), 0, len(vals))
for val := range vals {
valSeq = reflect.Append(valSeq, reflect.ValueOf(val))
}
slice.Sort(valSeq.Interface())
for i := 0; i < valSeq.Len(); i++ {
vals[valSeq.Index(i).Interface()].index = i
}
}
// Compute FacetWrap rows and cols.
if dir == "-" {
cells := float64(len(vals))
if f.Cols == 0 {
if f.Rows == 0 {
// Chose default Rows and Cols.
f.Rows = int(math.Ceil(math.Sqrt(cells)))
}
// Compute Cols from Rows.
f.Cols = int(math.Ceil(cells / float64(f.Rows)))
} else {
// Compute Rows from Cols.
f.Rows = int(math.Ceil(cells / float64(f.Cols)))
}
}
// Find existing subplots, split existing subplots and bands
// into len(vals) new subplots and bands, and transform each
// GroupBy group into its new subplot.
type bandKey struct {
// band1 is the primary band. band2 is only used by
// FacetWrap.
band1, band2 *subplotBand
// X and Y of band. This is a necessary part of the
// key because FacetWrap creates rows but does not
// create distant horizontal bands for them.
x, y int
}
type bandScale struct {
band *subplotBand
scale Scaler
}
subplots := make(map[*subplot][]*subplot)
bands := make(map[bandKey][]*subplotBand)
scales := make(map[bandScale]Scaler)
var ndata table.GroupingBuilder
for _, gid := range grouped.Tables() {
// Find subplot by walking up group hierarchy.
sub := subplotOf(gid)
// Split old band into len(vals) new bands in the
// orthogonal axis.
var obandKey bandKey
if dir == "x" {
obandKey = bandKey{band1: sub.vBand, x: sub.x}
} else if dir == "y" {
obandKey = bandKey{band1: sub.hBand, y: sub.y}
} else {
obandKey = bandKey{sub.vBand, sub.hBand, sub.x, sub.y}
}
nbands := bands[obandKey]
if nbands == nil {
nbands = make([]*subplotBand, len(vals))
for _, val := range vals {
nb := &subplotBand{parent: obandKey.band1, label: val.label}
nbands[val.index] = nb
}
bands[obandKey] = nbands
}
// Split old subplot into len(vals) new subplots.
nsubplots := subplots[sub]
if nsubplots == nil {
nsubplots = make([]*subplot, len(vals))
for _, val := range vals {
ns := &subplot{parent: sub, x: sub.x, y: sub.y,
vBand: sub.vBand, hBand: sub.hBand}
if dir == "x" {
ns.x = sub.x*len(vals) + val.index
ns.vBand = nbands[val.index]
} else if dir == "y" {
ns.y = sub.y*len(vals) + val.index
ns.hBand = nbands[val.index]
} else {
ns.x = sub.x*f.Cols + val.index%f.Cols
ns.y = sub.y*f.Rows + val.index/f.Cols
ns.vBand = nbands[val.index]
}
nsubplots[val.index] = ns
}
subplots[sub] = nsubplots
}
// Map this group to its new subplot.
nsubplot := nsubplots[vals[gid.Label()].index]
ngid := gid.Parent().Extend(nsubplot)
ndata.Add(ngid, grouped.Table(gid))
// Split scales if requested. At a high level, we want
// to give each band a new scale, but there may
// already be multiple scales within a band, so we
// find the set of scales within a band and split each
// distinct scale up.
var nband *subplotBand
if dir == "x" {
nband = nsubplot.vBand
} else if dir == "y" {
nband = nsubplot.hBand
} else {
if f.SplitXScales || f.SplitYScales {
// TODO: I probably need to rephrase
// this whole scale splitting
// operation in terms of subplot X and
// Y and possibly do it as a second
// pass once all of the subplots are
// created.
panic("not implemented: scale splitting for FacetWrap")
}
}
if f.SplitXScales {
scaler := p.GetScaleAt("x", gid)
nscaler := scales[bandScale{nband, scaler}]
if nscaler == nil {
nscaler = scaler.CloneScaler()
scales[bandScale{nband, scaler}] = nscaler
}
p.SetScaleAt("x", nscaler, ngid)
}
if f.SplitYScales {
scaler := p.GetScaleAt("y", gid)
nscaler := scales[bandScale{nband, scaler}]
if nscaler == nil {
nscaler = scaler.CloneScaler()
scales[bandScale{nband, scaler}] = nscaler
}
p.SetScaleAt("y", nscaler, ngid)
}
}
p.SetData(ndata.Done())
}
// subplotBand represents a rectangular group of subplots in either a
// vertical group (with a label on top) or a horizontal group (with a
// label to the right).
type subplotBand struct {
parent *subplotBand
label string
}
type subplot struct {
parent *subplot
// x and y are the position of this subplot, where 0, 0 is the
// top left.
x, y int
vBand, hBand *subplotBand
}
var rootSubplot = &subplot{}
func subplotOf(gid table.GroupID) *subplot {
for ; gid != table.RootGroupID; gid = gid.Parent() {
sub, ok := gid.Label().(*subplot)
if ok {
return sub
}
}
return rootSubplot
}
func (s subplot) String() string {
return fmt.Sprintf("[%d %d]", s.x, s.y)
}
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/gg/group.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gg
import "github.com/aclements/go-gg/table"
// TODO: GroupByKey? Would the key function only work on one binding?
// With a first-class row representation we could pass that.
// GroupBy sub-divides all groups such that all of the rows in each
// group have equal values for all of the named columns.
func (p *Plot) GroupBy(cols ...string) *Plot {
// TODO: Should this accept column expressions, like layers?
return p.SetData(table.GroupBy(p.Data(), cols...))
}
// GroupAuto groups p's data table on all columns that are comparable
// but are not numeric (that is, all categorical columns).
//
// TODO: Maybe there should be a CategoricalBindings that returns the
// set of categorical bindings, which callers could just pass to
// GroupBy, possibly after manipulating.
//
// TODO: Does implementing sort.Interface make an otherwise cardinal
// column ordinal?
func (p *Plot) GroupAuto() *Plot {
// Find the categorical columns.
categorical := []string{}
g := p.Data()
for _, col := range g.Columns() {
et := table.ColType(g, col).Elem()
if et.Comparable() && !isCardinal(et.Kind()) {
categorical = append(categorical, col)
}
}
return p.GroupBy(categorical...)
}
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/gg/layer.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gg
import (
"fmt"
"github.com/aclements/go-gg/table"
)
func defaultCols(p *Plot, cols ...*string) {
dcols := p.Data().Columns()
for i, colp := range cols {
if *colp == "" {
if i >= len(dcols) {
panic(fmt.Sprintf("cannot get default column %d; table has only %d columns", i, len(dcols)))
}
*colp = dcols[i]
}
}
}
// LayerLines is like LayerPaths, but connects data points in order by
// the "x" property.
type LayerLines LayerPaths
func (l LayerLines) Apply(p *Plot) {
LayerPaths(l).apply(p, true)
}
//go:generate stringer -type StepMode
// StepMode controls how LayerSteps connects subsequent points.
type StepMode int
const (
// StepHV makes LayerSteps connect subsequent points with a
// horizontal segment and then a vertical segment.
StepHV StepMode = iota
// StepVH makes LayerSteps connect subsequent points with a
// vertical segment and then a horizontal segment.
StepVH
// StepHMid makes LayerSteps connect subsequent points A and B
// with three segments: a horizontal segment from A to the
// midpoint between A and B, followed by vertical segment,
// followed by a horizontal segment from the midpoint to B.
StepHMid
// StepVMid makes LayerSteps connect subsequent points A and B
// with three segments: a vertical segment from A to the
// midpoint between A and B, followed by horizontal segment,
// followed by a vertical segment from the midpoint to B.
StepVMid
)
// LayerSteps is like LayerPaths, but connects data points with a path
// consisting only of horizontal and vertical segments.
type LayerSteps struct {
LayerPaths
Step StepMode
}
func (l LayerSteps) Apply(p *Plot) {
// TODO: Should this also support only showing horizontal or
// vertical segments?
//
// TODO: This could be a data transform instead of a layer.
// Then it could be used in conjunction with, for example,
// ribbons.
defaultCols(p, &l.X, &l.Y)
p.marks = append(p.marks, plotMark{&markSteps{
l.Step,
p.use("x", l.X),
p.use("y", l.Y),
p.use("stroke", l.Color),
p.use("fill", l.Fill),
}, p.Data().Tables()})
}
// LayerPaths groups by Color and Fill, and then connects successive
// data points in each group with a path and/or a filled polygon.
type LayerPaths struct {
// X and Y name columns that define the input and response of
// each point on the path. If these are empty, they default to
// the first and second columns, respectively.
X, Y string
// Color names a column that defines the stroke color of each
// path. If Color is "", it defaults to constant black.
// Otherwise, the data is grouped by Color.
Color string
// Fill names a column that defines the fill color of each
// path. If Fill is "", it defaults to none. Otherwise, the
// data is grouped by Fill.
Fill string
// XXX Perhaps the theme should provide default values for
// things like "color". That would suggest we need to resolve
// defaults like that at render time. Possibly a special scale
// that gets values from the theme could be used to resolve
// them.
//
// XXX strokeOpacity, fillOpacity, strokeWidth, what other
// properties do SVG strokes have?
//
// XXX Should the set of known styling bindings be fixed, and
// all possible rendering targets have to know what to do with
// them, or should the rendering target be able to have
// different styling bindings they understand (presumably with
// some reasonable base set)? If the renderer can determine
// the known bindings, we would probably just capture the
// environment here (and make it so a captured environment
// does not change) and hand that to the renderer later.
}
func (l LayerPaths) Apply(p *Plot) {
l.apply(p, false)
}
func (l LayerPaths) apply(p *Plot, sort bool) {
defaultCols(p, &l.X, &l.Y)
if l.Color != "" {
p.GroupBy(l.Color)
}
if l.Fill != "" {
p.GroupBy(l.Fill)
}
if sort {
defer p.Save().Restore()
p = p.SortBy(l.X)
}
p.marks = append(p.marks, plotMark{&markPath{
p.use("x", l.X),
p.use("y", l.Y),
p.use("stroke", l.Color),
p.use("fill", l.Fill),
}, p.Data().Tables()})
}
// LayerArea shades the area between two columns with a polygon. It is
// useful in conjunction with ggstat.AggMax and ggstat.AggMin for
// drawing the extents of data.
type LayerArea struct {
// X names the column that defines the input of each point. If
// this is empty, it defaults to the first column.
X string
// Upper and Lower name columns that define the range of
// response to shade. If either is "", it defaults to a
// constant 0 value.
Upper, Lower string
// Fill names a column that defines the fill color of each
// area. If Fill is "", it defaults to black. Otherwise, the
// data is grouped by Fill.
Fill string
// FillOpacity names a column that defines the fill opacity of
// each area. If FillOpacity is "", it defaults to 0.5.
// Otherwise, the data is grouped by FillOpacity.
FillOpacity string
}
func (l LayerArea) Apply(p *Plot) {
defaultCols(p, &l.X)
if l.Fill != "" {
p.GroupBy(l.Fill)
}
if l.FillOpacity != "" {
p.GroupBy(l.FillOpacity)
}
defer p.Save().Restore()
p = p.SortBy(l.X)
upper, lower := l.Upper, l.Lower
if upper == "" {
upper = p.Const(0)
}
if lower == "" {
lower = p.Const(0)
}
p.marks = append(p.marks, plotMark{&markArea{
p.use("x", l.X),
p.use("y", upper),
p.use("y", lower),
p.use("fill", l.Fill),
p.use("opacity", l.FillOpacity),
}, p.Data().Tables()})
}
// LayerPoints layers a point mark at each data point.
type LayerPoints struct {
// X and Y name columns that define input and response of each
// point. If these are empty, they default to the first and
// second columns, respectively.
X, Y string
// Color names the column that defines the fill color of each
// point. If Color is "", it defaults to constant black.
Color string
// Opacity names the column that defines the opacity of each
// point. If Opacity is "", it defaults to fully opaque. This
// is multiplied by any alpha value specified by Color.
Opacity string
// Size names the column that defines the size of each point.
// If Size is "", it defaults to 1% of the smallest plot
// dimension.
Size string
// XXX fill vs stroke, shape
}
func (l LayerPoints) Apply(p *Plot) {
defaultCols(p, &l.X, &l.Y)
p.marks = append(p.marks, plotMark{&markPoint{
p.use("x", l.X),
p.use("y", l.Y),
// TODO: It's actually the fill color, but I generally
// want it to match things that are stroke colors.
// Maybe I should have a "color" aesthetic for the
// "primary" color? Or I could have a hierarchy of
// aesthetics, in which this uses "stroke" if it has a
// scale, but otherwise uses "color".
p.use("stroke", l.Color),
// TODO: What scale for opacity? Or should I assume
// callers will use PreScaled values if they want
// specific opacities? What's the physical type?
p.use("opacity", l.Opacity),
p.use("size", l.Size),
}, p.Data().Tables()})
}
// LayerTiles layers a rectangle at each data point. The rectangle is
// specified by its center, width, and height.
type LayerTiles struct {
// X and Y name columns that define the input and response at
// the center of each rectangle. If they are "", they default
// to the first and second columns, respectively.
X, Y string
// Width and Height name columns that define the width and
// height of each rectangle. If they are "", the width and/or
// height are automatically determined from the smallest
// spacing between distinct X and Y points.
Width, Height string
// Fill names a column that defines the fill color of each
// rectangle. If it is "", the default fill is black.
Fill string
// XXX Stroke color/width, opacity, center adjustment.
}
func (l LayerTiles) Apply(p *Plot) {
defaultCols(p, &l.X, &l.Y)
if l.Width != "" || l.Height != "" {
// TODO: What scale are these in? (x+width) is in the
// X scale, but width itself is not. It doesn't make
// sense to train the X scale on width, and if there's
// a scale transform, (x+width) has to happen before
// the transform. OTOH, if x is discrete, I can't do
// (x+width); maybe in that case you just can't
// specify a width. OTOOH, if width is specified and
// the value is unscaled, I could still do something
// reasonable with that if x is discrete.
panic("not implemented: non-default width/height")
}
p.marks = append(p.marks, plotMark{&markTiles{
p.use("x", l.X),
p.use("y", l.Y),
p.use("fill", l.Fill),
}, p.Data().Tables()})
}
// LayerTags attaches text annotations to data points.
//
// TODO: Currently this groups by label and makes one annotation per
// group. This should be a controllable.
type LayerTags struct {
// X and Y name columns that define the input and response
// each tag is attached to. If they are "", they default to
// the first and second columns, respectively.
X, Y string
// Label names the column that gives the text to put in the
// tag at X, Y. Label is required.
Label string
// HPos controls the horizontal position of the tag if
// multiple points have the same Label. The label will be
// attached to the point closest to HPos between the left-most
// (HPos == 0) and the right-most (HPos == 1) points on this
// curve.
HPos float64
// Offset controls the pixel offset of the tag from the point
// it is attached to. If these are both zero, they are treated
// as -20, -20.
OffsetX, OffsetY int
}
func (l LayerTags) Apply(p *Plot) {
// TODO: Should there be special "annotation marks" that are
// always on top and can perhaps extend outside the plot area?
defaultCols(p, &l.X, &l.Y)
if l.OffsetX == 0 && l.OffsetY == 0 {
l.OffsetX, l.OffsetY = -20, -20
}
defer p.Save().Restore()
p.GroupBy(l.Label)
// TODO: I keep wanting an abstraction for a column across
// groups like this.
labels := make(map[table.GroupID]table.Slice)
for _, gid := range p.Data().Tables() {
labels[gid] = p.Data().Table(gid).MustColumn(l.Label)
}
p.marks = append(p.marks, plotMark{&markTags{
p.use("x", l.X),
p.use("y", l.Y),
labels,
l.HPos,
l.OffsetX,
l.OffsetY,
}, p.Data().Tables()})
}
// LayerTooltips attaches hover tooltips to data points.
type LayerTooltips struct {
// X and Y name columns that define locations of tooltips. If
// they are "", they default to the first and second columns,
// respectively.
X, Y string
// Label names the column that gives the text of the tooltip.
Label string
// TODO: Text styling, closest X or closest point, multiple
// tooltips if there are multiple points at the same X with
// different Ys?
}
func (l LayerTooltips) Apply(p *Plot) {
defer p.Save().Restore()
defaultCols(p, &l.X, &l.Y)
// Split up by subplot and flatten each subplot.
tables := map[*subplot][]*table.Table{}
gids := map[*subplot]table.GroupID{}
for _, gid := range p.Data().Tables() {
s := subplotOf(gid)
tables[s] = append(tables[s], p.Data().Table(gid))
gids[s] = gid
}
var ng table.GroupingBuilder
for k, ts := range tables {
var subg table.GroupingBuilder
for i, t := range ts {
subg.Add(table.RootGroupID.Extend(i), t)
}
ngid := table.RootGroupID.Extend(k)
ng.Add(ngid, table.Flatten(subg.Done()))
p.copyScales(gids[k], ngid)
}
p.SetData(ng.Done())
labels := make(map[table.GroupID]table.Slice)
for _, gid := range p.Data().Tables() {
labels[gid] = p.Data().Table(gid).MustColumn(l.Label)
}
p.marks = append(p.marks, plotMark{&markTooltips{
p.use("x", l.X),
p.use("y", l.Y),
labels,
}, p.Data().Tables()})
}
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/gg/layout/grid.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package layout
import "sort"
// Grid lays out elements in a two dimensional table. Each child is
// assigned to a cell in the table and may optionally span multiple
// rows and/or columns.
type Grid struct {
elts []*gridElement
cols, rows int
x, y, w, h float64
}
type gridElement struct {
e Element
x, y, colSpan, rowSpan int
}
// Add adds Element e to Grid g, spanning cells (x,y) up to but not
// including (x+colSpan, y+colSpan).
func (g *Grid) Add(e Element, x, y, colSpan, rowSpan int) {
if x+colSpan > g.cols {
g.cols = x + colSpan
}
if y+rowSpan > g.rows {
g.rows = y + rowSpan
}
g.elts = append(g.elts, &gridElement{e, x, y, colSpan, rowSpan})
}
func (g *Grid) Children() []Element {
res := make([]Element, len(g.elts))
for i, elt := range g.elts {
res[i] = elt.e
}
return res
}
func (g *Grid) doLayout(byRow bool, allocated float64) (dims []float64, flexes []bool) {
seq := func(n int) []int {
res := make([]int, n)
for i := range res {
res[i] = i
}
return res
}
max := func(x, y float64) float64 {
if x > y {
return x
}
return y
}
if byRow {
dims = make([]float64, g.rows)
flexes = make([]bool, g.rows)
} else {
dims = make([]float64, g.cols)
flexes = make([]bool, g.cols)
}
for i := range flexes {
// TODO: Should empty columns be set to false?
flexes[i] = true
}
// Sort elements by colSpan or rowSpan.
eltOrder := seq(len(g.elts))
sort.Sort(&gridElementSorter{g.elts, eltOrder, byRow})
// Add a fake element that spans everything and uses the
// allocated space.
if allocated > 0 {
eltOrder = append(eltOrder, -1)
}
// Process elements by increasing span.
for _, i := range eltOrder {
var (
edim float64
eflex bool
epos int
espan int
)
if i == -1 {
// Fake element for final space allocation.
edim, eflex, epos, espan = allocated, true, 0, len(dims)
} else {
e := g.elts[i]
// TODO: We need to make one pass and get both size
// hints or this will be exponential.
if byRow {
_, edim, _, eflex = e.e.SizeHint()
epos, espan = e.y, e.rowSpan
} else {
edim, _, eflex, _ = e.e.SizeHint()
epos, espan = e.x, e.colSpan
}
}
if espan == 1 {
dims[epos] = max(dims[epos], edim)
if !eflex {
flexes[epos] = false
}
} else if espan > 1 {
total := edim
// Expand flexible columns so that the total
// dim is >= e's dim, and so the rows/columns
// we do expand get equal dims. We don't
// shrink any row/column. If all rows/columns
// are fixed, we treat them all as flexible.
var subdims []float64
forceFlex := false
for i := epos; i < epos+espan; i++ {
if flexes[i] {
subdims = append(subdims, dims[i])
} else {
// This space is accounted for.
total -= dims[i]
}
}
if len(subdims) == 0 {
// All rows/columns are fixed, so treat
// them all as flexible.
forceFlex = true
subdims = append(subdims, dims[epos:epos+espan]...)
total = edim
}
if total <= 0 {
// Fixed columns already take e's space.
continue
}
// Remove flex columns already wider than
// total/count from consideration.
count := len(subdims)
sort.Sort(sort.Reverse(sort.Float64Slice(subdims)))
for _, dim := range dims {
if dim > total/float64(count) {
total -= dim
count--
}
}
// Expand remaining rows/columns to total/count.
if count <= 0 {
// Flex columns already take e's space.
continue
}
dim := total / float64(count)
for i := epos; i < epos+espan; i++ {
if flexes[i] || forceFlex {
dims[i] = max(dims[i], dim)
}
}
// TODO: What do I do with e's flex? Clearly
// if a fixed element spans the whole grid,
// the grid should be fixed, so I shouldn't
// ignore it.
}
}
return
}
func (g *Grid) SizeHint() (w, h float64, flexw, flexh bool) {
sum := func(xs []float64) float64 {
s := 0.0
for _, x := range xs {
s += x
}
return s
}
any := func(xs []bool) bool {
for _, x := range xs {
if x {
return true
}
}
return false
}
xdims, xflexes := g.doLayout(false, 0)
ydims, yflexes := g.doLayout(true, 0)
return sum(xdims), sum(ydims), any(xflexes), any(yflexes)
}
func (g *Grid) SetLayout(x, y, w, h float64) {
// Record layout.
g.x, g.y, g.w, g.h = x, y, w, h
// Layout children.
csum := func(xs []float64) []float64 {
res, csum := make([]float64, len(xs)+1), 0.0
for i, x := range xs {
res[i+1] = csum + x
csum += x
}
return res
}
xdims, _ := g.doLayout(false, w)
ydims, _ := g.doLayout(true, h)
xpos := csum(xdims)
ypos := csum(ydims)
for _, elt := range g.elts {
elt.e.SetLayout(xpos[elt.x], ypos[elt.y], xpos[elt.x+elt.colSpan]-xpos[elt.x], ypos[elt.y+elt.rowSpan]-ypos[elt.y])
}
}
func (g *Grid) Layout() (x, y, w, h float64) {
return g.x, g.y, g.w, g.h
}
type gridElementSorter struct {
elts []*gridElement
seq []int
byRowSpan bool
}
func (g *gridElementSorter) Len() int {
return len(g.seq)
}
func (g *gridElementSorter) Less(i, j int) bool {
e1, e2 := g.elts[g.seq[i]], g.elts[g.seq[j]]
if g.byRowSpan {
return e1.rowSpan < e2.rowSpan
}
return e1.colSpan < e2.colSpan
}
func (g *gridElementSorter) Swap(i, j int) {
g.seq[i], g.seq[j] = g.seq[j], g.seq[i]
}
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/gg/layout/layout.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package layout provides helpers for laying out hierarchies of
// rectangular elements in two dimensional space.
package layout
// TODO: If I want to handle wrapped text, this API is insufficient.
// In that case, I may need something more like Android where the
// parent can pass in Unspecified, (Exactly x), or (AtMost x) for both
// dimensions and make multiple calls. I would probably start out with
// AtMost the allocated dimension for everything and if the total came
// back too large, I would cut back space (possibly causing the other
// dimension to grow if text wraps).
// An Element is a rectangular feature in a layout.
type Element interface {
// SizeHint returns this Element's desired size and whether it
// can expand from that size in either direction.
SizeHint() (w, h float64, flexw, flexh bool)
// SetLayout sets this Element's layout relative to its parent
// and, if this Element is a container, recursively lays out
// this Element's children.
//
// w and h may be smaller than SizeHint() if the space is
// constrained. They may also be larger, even if the element
// isn't flexible, in which case the Element will position
// itself within the assigned size using some gravity.
//
// TODO: Or should the parent be responsible for gravity if it
// allocates too much space to a fixed element?
//
// TODO: Since an Element doesn't know its parent, it's
// difficult to turn local coordinates into absolute
// coordinates. These should either be absolute coordinates,
// or Element should have a parent and it should be easy to
// get absolute coordinates.
SetLayout(x, y, w, h float64)
// Layout returns this Element's layout.
Layout() (x, y, w, h float64)
}
// A Group is an Element that manages the layout of child Elements.
type Group interface {
Element
// Children returns the child Elements laid out by this Group.
Children() []Element
}
// Leaf is a leaf in a layout hierarchy. It is meant for embedding: it
// partially implements Element, leaving SizeHint to the embedding
// type.
type Leaf struct {
x, y, w, h float64
}
func (l *Leaf) SetLayout(x, y, w, h float64) {
l.x, l.y, l.w, l.h = x, y, w, h
}
func (l *Leaf) Layout() (x, y, w, h float64) {
return l.x, l.y, l.w, l.h
}
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/gg/layout.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gg
import (
"fmt"
"math"
"sort"
"github.com/aclements/go-gg/gg/layout"
"github.com/aclements/go-gg/table"
"github.com/ajstarks/svgo"
)
// A plotElt is a high-level element of a plot layout.
//
// plotElts are arranged in a 2D grid. Coordinates in the grid are
// specified by a pair of "paths" rather than a simple pair of
// indexes. For example, element A is to the left of element B if A's
// X path is less than B's X path, where paths are compared as tuples
// with an infinite number of trailing 0's. This makes it easy to, for
// example, place an element to the right of another element without
// having to renumber all of the elements that are already to its
// right.
//
// The first level of the hierarchy is simply the coordinate of the
// plot in the grid. Within this, we layout plot elements as follows:
//
// +----------------------+
// | Label (x, y/-3/-1) |
// +----------------------+
// | Label (x, y/-3/0) |
// +----------------------+
// | Padding (x, y/-2) |
// +-----------+----------+----------------------+----------+------------+
// | Padding | YTicks | | Padding | Label |
// | (x/-2, y) | (x/-1,y) | Subplot (x, y) | (x/2, y) | (x/3/0, y) |
// | | | | | |
// +-----------+----------+----------------------+----------+------------+
// | XTicks (x, y/1) |
// +----------------------+
// | Padding (x, y/2) |
// +----------------------+
//
// TODO: Should I instead think of this as specifying the edges rather
// than the cells?
type plotElt interface {
layout.Element
// paths returns the top-left and bottom-right cells of this
// element. x2Path and y2Path may be nil, indicating that they
// are the same as xPath and yPath.
paths() (xPath, yPath, x2Path, y2Path eltPath)
// render draws this plot element to r.svg.
render(r *eltRender)
}
type eltRender struct {
svg *svg.SVG
id int
}
func (r *eltRender) genid(prefix string) (id, ref string) {
id = fmt.Sprintf("%s%d", prefix, r.id)
ref = "url(#" + id + ")"
r.id++
return
}
type eltCommon struct {
xPath, yPath, x2Path, y2Path eltPath
}
func (c *eltCommon) paths() (xPath, yPath, x2Path, y2Path eltPath) {
return c.xPath, c.yPath, c.x2Path, c.y2Path
}
type eltSubplot struct {
eltCommon
layout.Leaf
subplot *subplot
marks []plotMark
scales map[string]map[Scaler]bool
xTicks, yTicks *eltTicks
plotMargins struct {
t, r, b, l float64
}
}
func newEltSubplot(s *subplot) *eltSubplot {
return &eltSubplot{
eltCommon: eltCommon{xPath: eltPath{s.x}, yPath: eltPath{s.y}},
subplot: s,
scales: make(map[string]map[Scaler]bool),
}
}
func (e *eltSubplot) SizeHint() (w, h float64, flexw, flexh bool) {
return 0, 0, true, true
}
func (e *eltSubplot) SetLayout(x, y, w, h float64) {
e.Leaf.SetLayout(x, y, w, h)
m := &e.plotMargins
m.t, m.r, m.b, m.l = plotMargins(w, h)
}
type eltTicks struct {
eltCommon
layout.Leaf
axis rune // 'x' or 'y'
ticksFor *eltSubplot // Subplot to which this is directly attached
ticks map[Scaler]plotEltTicks
}
type plotEltTicks struct {
major table.Slice
minor table.Slice
labels []string
}
func newEltTicks(axis rune, s *eltSubplot) *eltTicks {
elt := &eltTicks{
eltCommon: s.eltCommon,
axis: axis,
ticksFor: s,
}
switch axis {
case 'x':
elt.yPath = eltPath{s.subplot.y, 1}
case 'y':
elt.xPath = eltPath{s.subplot.x, -1}
default:
panic("bad axis")
}
return elt
}
func (e *eltTicks) scales() map[Scaler]bool {
switch e.axis {
case 'x':
return e.ticksFor.scales["x"]
case 'y':
return e.ticksFor.scales["y"]
default:
panic("bad axis")
}
}
func (e *eltTicks) mapTicks(s Scaler, ticks table.Slice) (pixels []float64) {
x, y, w, h := e.Layout()
// TODO: This doesn't show ticks in the margin area. This may
// be fine with niced tick labels, but it tends to look bad
// with un-niced ticks. Ideally we would expand the input
// domain instead, but this isn't well-defined for discrete
// scales. We could use Unmap to try to find the expanded
// input domain on both sides, but fall back to expanding the
// ranger if Unmap fails (which it would for a discrete
// scale).
m := e.ticksFor.plotMargins
switch e.axis {
case 'x':
s.Ranger(NewFloatRanger(x+m.l, x+w-m.r))
case 'y':
s.Ranger(NewFloatRanger(y+h-m.b, y+m.t))
}
return mapMany(s, ticks).([]float64)
}
// computeTicks computes the location and labels of the ticks in
// element e based on the dimensions of e.ticksFor (which must have
// been laid out prior to calling this).
func (e *eltTicks) computeTicks() {
const tickDistance = 30 // TODO: Theme. Min pixels between tick labels.
_, _, w, h := e.ticksFor.Layout()
var dim float64
switch e.axis {
case 'x':
dim = w
case 'y':
dim = h
}
// Compute max ticks assuming the labels are zero sized.
maxTicks := int(dim / tickDistance)
// Optimize ticks, keeping labels at least tickDistance apart.
e.ticks = make(map[Scaler]plotEltTicks)
for s := range e.scales() {
pred := func(ticks, _ table.Slice, labels []string) bool {
if len(labels) <= 1 {
return true
}
// Check distance between labels.
pos := e.mapTicks(s, ticks)
// Ticks are in value order, but we need them
// in position order.
sort.Float64s(pos)
var last float64
for i, p := range pos {
if i > 0 && p-last < tickDistance {
// Labels i-1 and i are too close.
return false
}
metrics := measureString(fontSize, labels[i])
switch e.axis {
case 'x':
last = p + metrics.width
case 'y':
last = p + metrics.leading
}
}
return true
}
major, minor, labels := s.Ticks(maxTicks, pred)
e.ticks[s] = plotEltTicks{major, minor, labels}
}
}
func (e *eltTicks) SizeHint() (w, h float64, flexw, flexh bool) {
if len(e.ticks) == 0 {
// Ticks haven't been computed yet or there are none.
// Assume this takes up no space.
switch e.axis {
case 'x':
return 0, 0, true, false
case 'y':
return 0, 0, false, true
default:
panic("bad axis")
}
}
var maxWidth, maxHeight float64
for s := range e.scales() {
for _, label := range e.ticks[s].labels {
metrics := measureString(fontSize, label)
maxHeight = math.Max(maxHeight, metrics.leading)
maxWidth = math.Max(maxWidth, metrics.width)
}
}
switch e.axis {
case 'x':
maxHeight += xTickSep
case 'y':
maxWidth += yTickSep
}
return maxWidth, maxHeight, e.axis == 'x', e.axis == 'y'
}
type eltLabel struct {
eltCommon
layout.Leaf
side rune // 't', 'b', 'l', 'r'
label string
fill string
}
func newEltLabelFacet(side rune, label string, x1, y1, x2, y2 int, level int) *eltLabel {
elt := &eltLabel{
side: side,
label: label,
fill: "#ccc", // TODO: Theme.
}
switch side {
case 't':
elt.eltCommon = eltCommon{
xPath: eltPath{x1},
yPath: eltPath{y1, -3, -level},
x2Path: eltPath{x2},
}
case 'r':
elt.eltCommon = eltCommon{
xPath: eltPath{x2, 3, level},
yPath: eltPath{y1},
y2Path: eltPath{y2},
}
default:
panic("bad side")
}
return elt
}
func newEltLabelAxis(side rune, label string, x, y, span int) *eltLabel {
elt := &eltLabel{
eltCommon: eltCommon{xPath: eltPath{x}, yPath: eltPath{y}},
side: side,
label: label,
fill: "none",
}
switch side {
case 'T', 'b':
elt.x2Path = eltPath{x + span}
case 'l':
elt.y2Path = eltPath{y + span}
default:
panic("bad side")
}
return elt
}
func (e *eltLabel) SizeHint() (w, h float64, flexw, flexh bool) {
// TODO: We actually want the height of the text, which could
// be N*leading if there are multiple lines.
dim := measureString(fontSize, e.label).leading * facetLabelHeight
switch e.side {
case 't', 'b':
return 0, dim, true, false
case 'T': // Titles
return 0, 1.5 * dim, true, false
case 'l', 'r':
return dim, 0, false, true
default:
panic("bad side")
}
}
type eltPadding struct {
eltCommon
layout.Leaf
side rune // 't', 'b', 'l', 'r'
}
func newEltPadding(side rune, x, y int) *eltPadding {
elt := &eltPadding{
eltCommon: eltCommon{xPath: eltPath{x}, yPath: eltPath{y}},
side: side,
}
switch side {
case 't':
elt.yPath = eltPath{y, -2}
case 'r':
elt.xPath = eltPath{x, 2}
case 'b':
elt.yPath = eltPath{y, 2}
case 'l':
elt.xPath = eltPath{x, -2}
default:
panic("bad side")
}
return elt
}
func (e *eltPadding) SizeHint() (w, h float64, flexw, flexh bool) {
const padding = 4 // TODO: Theme.
switch e.side {
case 't', 'b':
return 0, padding, true, false
case 'l', 'r':
return padding, 0, false, true
default:
panic("bad side")
}
}
func addSubplotLabels(elts []plotElt) []plotElt {
// Find the regions covered by each subplot band.
vBands := make(map[*subplotBand]subplotRegion)
hBands := make(map[*subplotBand]subplotRegion)
for _, elt := range elts {
elt, ok := elt.(*eltSubplot)
if !ok {
continue
}
s := elt.subplot
level := 0
for vBand := s.vBand; vBand != nil; vBand = vBand.parent {
r := vBands[vBand]
r.update(s, level)
vBands[vBand] = r
level++
}
level = 0
for hBand := s.hBand; hBand != nil; hBand = hBand.parent {
r := hBands[hBand]
r.update(s, level)
hBands[hBand] = r
level++
}
}
// Create ticks.
//
// TODO: If the facet grid isn't total, this can add ticks to
// the side of a plot that's in the middle of the grid and
// that creates a gap between all of the plots. This seems
// like a fundamental limitation of treating this as a grid.
// We could either abandon the grid and instead use a
// hierarchy of left-of/right-of/above/below relations, or we
// could make facets produce a total grid.
var prev *eltSubplot
var curTicks *eltTicks
sorter := newSubplotSorter(elts, 'x')
sort.Sort(sorter)
for _, elt := range sorter.elts {
if prev == nil || prev.subplot.y != elt.subplot.y || !eqScales(prev, elt, "y") {
// Show Y axis ticks.
curTicks = newEltTicks('y', elt)
elts = append(elts, curTicks)
}
elt.yTicks = curTicks
prev = elt
}
sorter.dir = 'y'
sort.Sort(sorter)
prev, curTicks = nil, nil
for _, elt := range sorter.elts {
if prev == nil || prev.subplot.x != elt.subplot.x || !eqScales(prev, elt, "x") {
// Show X axis ticks.
curTicks = newEltTicks('x', elt)
elts = append(elts, curTicks)
}
elt.xTicks = curTicks
prev = elt
}
// Create labels.
for vBand, r := range vBands {
elts = append(elts, newEltLabelFacet('t', vBand.label, r.x1, r.y1, r.x2, r.y2, r.level))
}
for hBand, r := range hBands {
elts = append(elts, newEltLabelFacet('r', hBand.label, r.x1, r.y1, r.x2, r.y2, r.level))
}
return elts
}
func addAxisLabels(elts []plotElt, title, xlabel, ylabel string) []plotElt {
// Find the region covered by subplots.
var r subplotRegion
for _, elt := range elts {
elt, ok := elt.(*eltSubplot)
if !ok {
continue
}
r.update(elt.subplot, 0)
}
if !r.valid {
return elts
}
// Add title.
// TODO: Make this larger.
if title != "" {
elts = append(elts,
newEltLabelAxis('T', title, r.x1, r.y1-1, r.x2-r.x1))
}
// Add labels.
elts = append(elts,
newEltLabelAxis('b', xlabel, r.x1, r.y2+1, r.x2-r.x1),
newEltLabelAxis('l', ylabel, r.x1-1, r.y1, r.y2-r.y1))
return elts
}
type subplotRegion struct {
valid bool
x1, x2, y1, y2, level int
}
func (r *subplotRegion) update(s *subplot, level int) {
if !r.valid {
r.x1, r.x2, r.y1, r.y2, r.level = s.x, s.x, s.y, s.y, level
r.valid = true
return
}
if s.x < r.x1 {
r.x1 = s.x
} else if s.x > r.x2 {
r.x2 = s.x
}
if s.y < r.y1 {
r.y1 = s.y
} else if s.y > r.y2 {
r.y2 = s.y
}
if level > r.level {
r.level = level
}
}
// subplotSorter sorts eltSubplots by subplot (x, y) position.
type subplotSorter struct {
elts []*eltSubplot
// dir indicates primary sorting direction: 'x' means to sort
// left-to-right, top-to-bottom; 'y' means to sort
// bottom-to-top, left-to-right.
dir rune
}
func newSubplotSorter(elts []plotElt, dir rune) *subplotSorter {
selts := []*eltSubplot{}
for _, elt := range elts {
if s, ok := elt.(*eltSubplot); ok {
selts = append(selts, s)
}
}
return &subplotSorter{selts, dir}
}
func (s subplotSorter) Len() int {
return len(s.elts)
}
func (s subplotSorter) Less(i, j int) bool {
a, b := s.elts[i], s.elts[j]
if s.dir == 'x' {
if a.subplot.y != b.subplot.y {
return a.subplot.y < b.subplot.y
}
return a.subplot.x < b.subplot.x
} else {
if a.subplot.x != b.subplot.x {
return a.subplot.x < b.subplot.x
}
return a.subplot.y > b.subplot.y
}
}
func (s subplotSorter) Swap(i, j int) {
s.elts[i], s.elts[j] = s.elts[j], s.elts[i]
}
func eqScales(a, b *eltSubplot, aes string) bool {
sa, sb := a.scales[aes], b.scales[aes]
if len(sa) != len(sb) {
return false
}
for k, v := range sa {
if sb[k] != v {
return false
}
}
return true
}
type eltPath []int
func (a eltPath) cmp(b eltPath) int {
for len(a) > 0 || len(b) > 0 {
var ax, bx int
if len(a) > 0 {
ax, a = a[0], a[1:]
}
if len(b) > 0 {
bx, b = b[0], b[1:]
}
if ax != bx {
if ax < bx {
return -1
} else {
return 1
}
}
}
return 0
}
type eltPaths []eltPath
func (s eltPaths) Len() int {
return len(s)
}
func (s eltPaths) Less(i, j int) bool {
return s[i].cmp(s[j]) < 0
}
func (s eltPaths) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s eltPaths) nub() eltPaths {
var i, o int
for i, o = 1, 1; i < len(s); i++ {
if s[i].cmp(s[i-1]) != 0 {
s[o] = s[i]
o++
}
}
return s[:o]
}
func (s eltPaths) find(p eltPath) int {
return sort.Search(len(s), func(i int) bool {
return s[i].cmp(p) >= 0
})
}
// layoutPlotElts returns a layout containing all of the elements in
// elts.
//
// layoutPlotElts flattens the X and Y paths of elts into simple
// coordinate indexes and constructs a layout.Grid.
func layoutPlotElts(elts []plotElt) layout.Element {
// Add padding elements to each subplot.
//
// TODO: Should there be padding between labels and the plot?
for _, elt := range elts {
elt, ok := elt.(*eltSubplot)
if !ok {
continue
}
x, y := elt.xPath[0], elt.yPath[0]
elts = append(elts,
newEltPadding('t', x, y),
newEltPadding('r', x, y),
newEltPadding('b', x, y),
newEltPadding('l', x, y),
)
}
// Construct the global element grid from coordinate paths by
// sorting the sets of X paths and Y paths to each leaf and
// computing a global (x,y) for each leaf from these orders.
type eltPos struct {
x, y, xSpan, ySpan int
}
flat := map[plotElt]eltPos{}
dir := func(get func(plotElt) (p, p2 eltPath), set func(p *eltPos, pos, span int)) {
var paths eltPaths
for _, elt := range elts {
p, p2 := get(elt)
paths = append(paths, p)
if p2 != nil {
paths = append(paths, p2)
}
}
sort.Sort(paths)
paths = paths.nub()
for _, elt := range elts {
p, p2 := get(elt)
pos, span := paths.find(p), 1
if p2 != nil {
span = paths.find(p2) - pos + 1
}
eltPos := flat[elt]
set(&eltPos, pos, span)
flat[elt] = eltPos
}
}
dir(func(e plotElt) (p, p2 eltPath) {
p, _, p2, _ = e.paths()
return
}, func(p *eltPos, pos, span int) {
p.x, p.xSpan = pos, span
})
dir(func(e plotElt) (p, p2 eltPath) {
_, p, _, p2 = e.paths()
return
}, func(p *eltPos, pos, span int) {
p.y, p.ySpan = pos, span
})
// Construct the grid layout.
l := new(layout.Grid)
for elt, pos := range flat {
l.Add(elt, pos.x, pos.y, pos.xSpan, pos.ySpan)
}
return l
}
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/gg/mark.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gg
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"image"
"image/color"
"image/png"
"math"
"reflect"
"sort"
"strconv"
"github.com/aclements/go-gg/generic/slice"
"github.com/aclements/go-gg/table"
"github.com/aclements/go-moremath/stats"
"github.com/ajstarks/svgo"
)
// TODO: Audit all of this for inf and NaN.
type marker interface {
mark(env *renderEnv, canvas *svg.SVG)
}
func isFinite(x float64) bool {
return !(math.IsNaN(x) || math.IsInf(x, 0))
}
type plotMark struct {
m marker
groups []table.GroupID
}
type markPath struct {
x, y, stroke, fill *scaledData
}
func (m *markPath) mark(env *renderEnv, canvas *svg.SVG) {
// XXX What ensures these type assertions will succeed,
// especially if it's an identity scale? Maybe identity scales
// still need to coerce their results to the right type.
xs, ys := env.get(m.x).([]float64), env.get(m.y).([]float64)
var stroke color.Color = color.Black
if m.stroke != nil {
stroke = env.getFirst(m.stroke).(color.Color)
}
var fill color.Color = color.Transparent
if m.fill != nil {
fill = env.getFirst(m.fill).(color.Color)
}
drawPath(canvas, xs, ys, stroke, fill)
}
type markArea struct {
x, upper, lower, fill, fillOpacity *scaledData
}
func reversed(data []float64) []float64 {
var rev []float64
for i := len(data) - 1; i >= 0; i-- {
rev = append(rev, data[i])
}
return rev
}
func (m *markArea) mark(env *renderEnv, canvas *svg.SVG) {
xs := env.get(m.x).([]float64)
upper := env.get(m.upper).([]float64)
lower := env.get(m.lower).([]float64)
var fill color.Color = color.Black
if m.fill != nil {
fill = env.getFirst(m.fill).(color.Color)
}
fillOpacity := 0.5
if m.fillOpacity != nil {
fillOpacity = env.getFirst(m.fillOpacity).(float64)
}
r, g, b, a := fill.RGBA()
fill = color.RGBA64{
uint16(float64(r) * fillOpacity),
uint16(float64(g) * fillOpacity),
uint16(float64(b) * fillOpacity),
uint16(float64(a) * fillOpacity)}
xs = append(xs, reversed(xs)...)
ys := append(upper, reversed(lower)...)
drawPath(canvas, xs, ys, color.Transparent, fill)
}
type markSteps struct {
dir StepMode
x, y, stroke, fill *scaledData
}
func (m *markSteps) mark(env *renderEnv, canvas *svg.SVG) {
xs, ys := env.get(m.x).([]float64), env.get(m.y).([]float64)
var stroke color.Color = color.Black
if m.stroke != nil {
stroke = env.getFirst(m.stroke).(color.Color)
}
var fill color.Color = color.Transparent
if m.fill != nil {
fill = env.getFirst(m.fill).(color.Color)
}
if len(xs) == 0 {
return
}
// Create intermediate points.
xs2, ys2 := make([]float64, 2*len(xs)), make([]float64, 2*len(ys))
for i := range xs2 {
switch m.dir {
case StepHV, StepVH:
xs2[i], ys2[i] = xs[i/2], ys[i/2]
case StepHMid, StepVMid:
if i == 0 || i == len(xs2)-1 {
xs2[i], ys2[i] = xs[i/2], ys[i/2]
break
}
var p1, p2 int
if i%2 == 0 {
// Interpolate i/2-1 and i/2.
p1, p2 = i/2-1, i/2
} else {
// Interpolate i/2 and i/2+1.
p1, p2 = i/2, i/2+1
}
if m.dir == StepHMid {
xs2[i], ys2[i] = (xs[p1]+xs[p2])/2, ys[i/2]
} else {
xs2[i], ys2[i] = xs[i/2], (ys[p1]+ys[p2])/2
}
}
}
if m.dir == StepHV {
xs2 = xs2[1:]
} else if m.dir == StepVH {
ys2 = ys2[1:]
}
drawPath(canvas, xs2, ys2, stroke, fill)
}
func drawPath(canvas *svg.SVG, xs, ys []float64, stroke color.Color, fill color.Color) {
switch len(xs) {
case 0:
return
case 1:
// TODO: Depending on the stroke cap, this *could* be
// well-defined.
Warning.Print("cannot draw path through 1 point; ignoring")
return
}
// Build path.
var path []byte
inLine := false
for i := range xs {
if !isFinite(xs[i]) || !isFinite(ys[i]) {
inLine = false
continue
}
if !inLine {
path = append(path, 'M')
inLine = true
}
path = append(path, ' ')
path = strconv.AppendFloat(path, xs[i], 'g', 6, 64)
path = append(path, ' ')
path = strconv.AppendFloat(path, ys[i], 'g', 6, 64)
}
if len(path) == 0 {
return
}
// XXX Stroke width
style := cssPaint("stroke", stroke) + ";" + cssPaint("fill", fill) + ";stroke-width:3"
canvas.Path(wrapPath(string(path)), style)
}
type markPoint struct {
x, y, color, opacity, size *scaledData
}
func (m *markPoint) mark(env *renderEnv, canvas *svg.SVG) {
xs, ys := env.get(m.x).([]float64), env.get(m.y).([]float64)
var colors []color.Color
if m.color != nil {
slice.Convert(&colors, env.get(m.color))
}
var opacities []float64
if m.opacity != nil {
opacities = env.get(m.opacity).([]float64)
}
var sizes []float64
if m.size != nil {
sizes = env.get(m.size).([]float64)
}
mindim := math.Min(env.Size())
for i := range xs {
if !isFinite(xs[i]) || !isFinite(ys[i]) {
continue
}
var style string
if colors != nil {
style = cssPaint("fill", colors[i])
}
if opacities != nil {
if style != "" {
style += ";"
}
style += fmt.Sprintf("opacity:%.6g", opacities[i])
}
r := mindim * 0.01
if sizes != nil {
r = mindim * sizes[i]
}
canvas.Circle(int(xs[i]), int(ys[i]), int(r), style)
}
}
type markTiles struct {
x, y, fill *scaledData
}
func (m *markTiles) mark(env *renderEnv, canvas *svg.SVG) {
xs, ys := env.get(m.x).([]float64), env.get(m.y).([]float64)
// TODO: Should the Scaler (or Ranger) ensure that the values
// are color.Color? How would this work with an identity
// scaler?
var fills []color.Color
if m.fill != nil {
slice.Convert(&fills, env.get(m.fill))
}
// TODO: We can't use an <image> this if the width and height
// are specified, or if there is a stroke.
// minx, maxx := stats.Bounds(xs)
// miny, maxy := stats.Bounds(ys)
// Compute image bounds.
imageBounds := func(vals []float64) (float64, float64, float64, bool) {
// Reduce to unique values.
unique := []float64{}
uset := map[float64]bool{}
for _, v := range vals {
if !uset[v] {
if !isFinite(v) {
continue
}
unique = append(unique, v)
uset[v] = true
}
}
var minGap float64
regular := true
switch len(unique) {
case 0:
return 0, 0, -1, false
case 1:
// TODO: In this case we'll produce a 1 pixel
// wide/high line. That's probably not what's
// desired. Maybe we want it to be the
// width/height of the plot area?
minGap = 1.0
default:
sort.Float64s(unique)
minGap = unique[1] - unique[0]
for i, u := range unique[1:] {
minGap = math.Min(minGap, u-unique[i])
}
// Consider the spacing "regular" if every
// point is within a 1000th of a multiple of
// minGap.
for _, u := range unique {
_, error := math.Modf((u - unique[0]) / minGap)
if 0.001 <= error && error <= 0.999 {
regular = false
break
}
}
}
return unique[0], unique[len(unique)-1], minGap, regular
}
xmin, xmax, xgap, xreg := imageBounds(xs)
ymin, ymax, ygap, yreg := imageBounds(ys)
if xgap == -1 || ygap == -1 {
return
}
if !xreg || !yreg {
// TODO: Can't use an image.
panic("not implemented: irregular tile spacing")
}
// TODO: If there are a small number of cells, just make the
// rectangles since it's hard to reliably disable
// interpolation (e.g., the below doesn't work in rsvg).
// Create the image.
iw, ih := round((xmax-xmin+xgap)/xgap), round((ymax-ymin+ygap)/ygap)
img := image.NewRGBA(image.Rect(0, 0, iw, ih))
fill := color.Color(color.Black)
for i := range xs {
if !isFinite(xs[i]) || !isFinite(ys[i]) {
continue
}
if fills != nil {
fill = fills[i]
}
img.Set(round((xs[i]-xmin)/xgap), round((ys[i]-ymin)/ygap), fill)
}
// Encode the image.
uri := bytes.NewBufferString("data:image/png;base64,")
w := base64.NewEncoder(base64.StdEncoding, uri)
if err := png.Encode(w, img); err != nil {
Warning.Println("error encoding image:", err)
return
}
w.Close()
canvas.Image(round(xmin-xgap/2), round(ymin-ygap/2),
round(xmax-xmin+xgap), int(ymax-ymin+ygap),
uri.String(), `preserveAspectRatio="none" style="image-rendering:optimizeSpeed;image-rendering:-moz-crisp-edges;image-rendering:-webkit-optimize-contrast;image-rendering:pixelated"`)
}
type markTags struct {
x, y *scaledData
labels map[table.GroupID]table.Slice
hpos float64
offsetX, offsetY int
}
func (m *markTags) mark(env *renderEnv, canvas *svg.SVG) {
const padX = 5
xs, ys := env.get(m.x).([]float64), env.get(m.y).([]float64)
if len(xs) == 0 {
return
}
// Find the point closest to hpos between the min and max.
//
// TODO: Give the user control over this.
minx, maxx := stats.Bounds(xs)
targetx := minx + (maxx-minx)*m.hpos
midi, middelta := 0, math.Abs(xs[0]-targetx)
for i, x := range xs {
delta := math.Abs(x - targetx)
if delta < middelta {
midi, middelta = i, delta
}
}
// Get label.
label := fmt.Sprint(reflect.ValueOf(m.labels[env.gid]).Index(midi).Interface())
// Attach tag to this point.
//
// TODO: More user control.
//
// TODO: Make automatic positioning account for bounds of plot.
//
// TODO: Adjust positions to avoid overlap. Unfortunately,
// this requires some global optimization, but mark only sees
// one tag at a time.
//
// TODO: Re-enable the tag box when I have decent text metrics.
//t := measureString(fontSize, label)
//canvas.Rect(int(xs[midi]+offsetX-t.width), int(ys[midi]+offsetY-0.75*t.leading), int(t.width), int(1.5*t.leading), `rx="4"`, `fill="white"`, `stroke="black"`)
if m.offsetX > 0 {
// To the right, left-aligned.
canvas.Text(int(xs[midi])+m.offsetX+padX, int(ys[midi])+m.offsetY, label, `dy=".3em"`)
} else {
canvas.Text(int(xs[midi])+m.offsetX-padX, int(ys[midi])+m.offsetY, label, `dy=".3em"`, `text-anchor="end"`)
}
canvas.Path(fmt.Sprintf("M%.6g %.6gc%.6g %.6g,%.6g %.6g,%.6g %.6g", xs[midi], ys[midi], 0.8*float64(m.offsetX), 0.0, 0.2*float64(m.offsetX), float64(m.offsetY), float64(m.offsetX), float64(m.offsetY)), `fill="none"`, `stroke="black"`, `stroke-dasharray="2, 3"`, `stroke-width="2"`)
}
type markTooltips struct {
x, y *scaledData
labels map[table.GroupID]table.Slice
}
func (m *markTooltips) mark(env *renderEnv, canvas *svg.SVG) {
// Construct JSON for data.
xs, ys := env.get(m.x).([]float64), env.get(m.y).([]float64)
if len(xs) == 0 {
return
}
var labels []string
switch l2 := m.labels[env.gid].(type) {
case []string:
labels = l2
default:
l2v := reflect.ValueOf(l2)
labels = make([]string, l2v.Len())
for i := range labels {
labels[i] = fmt.Sprint(l2v.Index(i).Interface())
}
}
// TODO: Make env able to generate IDs.
//
// TODO: Sort by x and use binary search in Javascript.
//
// TODO: Remove points that round to the same coordinate.
//
// TODO: Put on the left if we're close to the right edge.
id := fmt.Sprintf("tooltips%p", env)
var buf bytes.Buffer
fmt.Fprintf(&buf, "var %s = ", id)
data := struct {
X []int `json:"x"`
Y []int `json:"y"`
L []string `json:"l"`
}{make([]int, 0, len(xs)), make([]int, 0, len(ys)), labels}
for i := range xs {
if !isFinite(xs[i]) || !isFinite(ys[i]) {
continue
}
// Round data to an int to save space.
data.X = append(data.X, int(xs[i]+0.5))
data.Y = append(data.Y, int(ys[i]+0.5))
}
if len(data.X) == 0 {
return
}
json.NewEncoder(&buf).Encode(data)
canvas.Script("text/javascript", buf.String())
canvas.Path("", `display="none"`, `fill="white"`, `stroke="black"`, fmt.Sprintf(`id="%s-p"`, id))
canvas.Text(0, 0, "", `display="none"`, fmt.Sprintf(`id="%s-t"`, id))
px, _, pw, _ := env.Area()
canvas.Rect(int(env.area[0]), int(env.area[1]), int(env.area[2]), int(env.area[3]), `fill-opacity="0"`, fmt.Sprintf(`onmousemove="tooltipMove(evt,%s,"%s",%v,%v)"`, id, id, px, px+pw), fmt.Sprintf(`onmouseout="tooltipOut(evt,%s,"%s")"`, id, id))
// TODO: Only write this once per SVG.
canvas.Script("text/javascript", `
function tooltipMove(evt, data, tid, minx, maxx) {
// Convert evt.x to an SVG coordinate.
var svg = document.rootElement;
var pt = svg.createSVGPoint();
pt.x = evt.clientX;
pt.y = evt.clientY;
var epos = pt.matrixTransform(svg.getScreenCTM().inverse());
// Find data point closest to event coordinate.
var cd = Math.sqrt(Math.pow(epos.x-data.x[0], 2) + Math.pow(epos.y-data.y[0], 2)), ci = 0;
for (var i = 1; i < data.x.length; i++) {
var d = Math.sqrt(Math.pow(epos.x-data.x[i], 2) + Math.pow(epos.y-data.y[i], 2));
if (d < cd) { cd = d; ci = i; }
}
// Update text content and position.
var text = document.getElementById(tid+"-t");
text.textContent = data.l[ci];
text.style.display = "block";
text.setAttribute("x", 0);
text.setAttribute("y", 0);
var bb = text.getBBox();
var hm = 2, r = 3;
var tx = data.x[ci] + bb.height/4 + hm;
var flip = false;
if (tx + bb.width + 2*hm + r > maxx) {
var tx2 = data.x[ci] - bb.height/4 - hm - bb.width;
if (tx2 - 2*hm - r >= minx) {
// Position left of point.
tx = tx2;
flip = true;
}
}
text.setAttribute("x", tx);
text.setAttribute("y", data.y[ci] - (bb.y + bb.height/2));
// Update marker.
var p = document.getElementById(tid+"-p");
if (flip) {
p.setAttribute("transform", "translate("+2*data.x[ci]+",0) scale(-1,1)")
} else {
p.setAttribute("transform", "")
}
p.setAttribute("d", "M"+data.x[ci]+","+data.y[ci]+
"l"+(bb.height/4)+","+(-bb.height/2)+
"h"+(bb.width+2*hm)+
"a"+r+","+r+",90,0,1,"+r+","+r+
"v"+(bb.height-2*r)+
"a"+r+","+r+",90,0,1,"+(-r)+","+r+
"h"+(-bb.width-2*hm)+"z");
p.style.display = "block";
}
function tooltipOut(evt, data, tid) {
var text = document.getElementById(tid+"-t");
text.style.display = "none";
var p = document.getElementById(tid+"-p");
p.style.display = "none";
}
`)
}
// cssPaint returns a CSS fragment for setting CSS property prop to
// color c.
func cssPaint(prop string, c color.Color) string {
r, g, b, a := c.RGBA()
if a == 0 {
// No paint.
return prop + ":none"
}
if a != 0xffff {
// Undo alpha pre-multiplication.
r = r * 0xffff / a
g = g * 0xffff / a
b = b * 0xffff / a
}
r, g, b = r>>8, g>>8, b>>8
css := prop
if r>>4 == r&0xF && g>>4 == g&0xF && b>>4 == b&0xF {
// Use #rgb form.
css += fmt.Sprintf(":#%x%x%x", r>>4, g>>4, b>>4)
} else {
// Use #rrggbb form.
css += fmt.Sprintf(":#%02x%02x%02x", r, g, b)
}
if a != 0xffff {
// SVG 1.1 only supports CSS2 color formats, which
// unfortunately does not include rgba, so we have to
// use a separate CSS property.
css += ";" + prop + "-opacity:" + strconv.FormatFloat(float64(a)/0xffff, 'g', 0, 64)
}
return css
}
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/gg/package.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package gg creates plots using the Grammar of Graphics.
//
// WARNING: This API is highly unstable. For now, please vendor this
// package.
//
// gg creates statistical visualizations. It's designed to help users
// quickly navigate and explore complex data in different ways, both
// in terms of what they're plotting and how they're plotting it. This
// focus on rapid exploration of complex data leads to a very
// different design than typical plotting packages.
//
// gg is heavily inspired by Wilkinson's Grammar of Graphics [1]. A
// key observation of the Grammar of Graphics is that there are many
// motifs across different types of plots. The Grammar of Graphics
// separates these motifs into orthogonal concerns that can be
// manipulated and extended independently, enabling the creation of
// traditional plot types from their fundamental components as well as
// the creation of entirely new plot types.
//
// Data model
//
// Central to gg is its data model. At the most basic level, the input
// data consists of a table with a set of named columns, with the rows
// organized into one or more groups. At a higher level, because gg
// makes it easy to restructure data before plotting it, it expects to
// start with regularized input data, where each column represents a
// distinct independent or dependent variable. In other words, any two
// values that make sense to plot on the same axis should be in the
// same column.
//
// For example, to express a line graph with several series of
// different colors in gg, you would say "plot column A against column
// B, grouped into series and colored according to column C". In
// contrast, typical plotting packages use a "spreadsheet" model,
// where each data series is a separate column, so expressing the same
// graph requires saying "plot column A against column B in color 1
// and plot column A against column C in color 2" and so on.
//
// gg's approach is suited to exploratory data analysis because you
// don't have to restructure the data to see it in a different way. In
// the traditional spreadsheet model, you have to structure the data
// to match the plot. In gg, you tell the plot what structure to
// extract from the data.
//
// Layers and scales
//
// To visualize data, gg provides a set of composable plot building
// blocks. There are no fixed "plot types" in gg. The main building
// block is a "layer", which transforms a data set into a set of
// visual marks, such as lines, points, or rectangles. Each layer is
// configured by mapping columns of the data set to different
// "aesthetics". An aesthetic is a generalization of a dimension: X
// and Y are aesthetics, but so are color and stroke width and point
// shape. Unlike typical plotting packages, these various aesthetics
// are treated symmetrically and any aesthetic can be fed from any
// column of the data.
//
// Layers work in close concert with "scales", which map from values
// in the data space to values in the visual space. Scales can map
// from continuous or discrete data values (such as numbers or
// strings) to continuous or discrete visual values (such as pixel
// offsets or point shapes). Each aesthetic has an associated scale.
// If the user hasn't provided a specific scale for an aesthetic, gg
// uses a default scale that guesses what to do based on the data type
// and aesthetic.
//
// Stats
//
// Data can be pre-processed prior to rendering it with a layer using
// a "stat". A stat can be an arbitrary data transformation, but it's
// typically used to compute statistical summaries, such as the
// five-number summary (e.g., for a box plot), a linear regression, or
// a density estimate.
//
// TODO: "Compound" layers?
//
// Facets
//
// TODO.
//
// Aesthetics
//
// gg understands the following aesthetics.
//
// "x" and "y" give the offset from the lower-left corner of a plot.
// Their ranges are always set to the pixel coordinates of the X and Y
// axes, respectively, and cannot be overridden.
//
// "stroke" and "fill" give the stroke and fill colors of paths and
// points. Their ranger must have type color.Color. The default ranger
// returns a single-hue gradient for continuous data, or a categorical
// palette for discrete data.
//
// "opacity" gives the overall opacity of a mark. Its ranger must have
// type float64 and give values between 0 and 1, inclusive. The
// default ranger ranges from 10% opaque (0.1) to fully opaque (1.0).
//
// "size" gives the size of marks. Its ranger must have type float64
// and yields values that are relative to the smallest dimension of
// the plot area (e.g., a value of 0.5 creates a point that cover half
// of the plot width or height, whichever is smaller). The default
// ranger ranges from 1% (0.01) to 10% (0.1).
//
// Related work
//
// gg draws ideas and inspiration from many sources. The core
// principle of a Grammar of Graphics was introduced by Wiklinson [1].
// There have been many implementations in many languages. The most
// popular is certainly Wickham's ggplot2 for R [2]. gg draws most
// heavily on Wickham's follow-up work on ggvis for R [3].
//
// [1] Leland Wilkinson, The Grammar of Graphics, Springer, 1999.
//
// [2] Hadley Wickham, ggplot2: Elegant Graphics for Data Analysis,
// Springer, 2009.
//
// [3] Hadley Wickham, ggvis, http://ggvis.rstudio.com/.
//
// TODO: Scale transforms, coordinate spaces.
package gg
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/gg/plot.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gg
import (
"fmt"
"log"
"os"
"github.com/aclements/go-gg/table"
)
// TODO: Split transforms, scalers, and layers into their own packages
// to clean up the name spaces and un-prefix their names?
// Warning is a logger for reporting conditions that don't prevent the
// production of a plot, but may lead to unexpected results.
var Warning = log.New(os.Stderr, "[gg] ", log.Lshortfile)
// Plot represents a single (potentially faceted) plot.
type Plot struct {
env *plotEnv
scales map[string]scalerTree
scaledData map[scaledDataKey]*scaledData
scaleSet map[scaleKey]bool
marks []plotMark
axisLabels map[string]string
autoAxisLabels map[string][]string
title string
constNonce int
}
// NewPlot returns a new Plot backed by data. It has no layers, one
// facet, and all scales are default.
func NewPlot(data table.Grouping) *Plot {
p := &Plot{
env: &plotEnv{
data: data,
},
scales: make(map[string]scalerTree),
scaledData: make(map[scaledDataKey]*scaledData),
scaleSet: make(map[scaleKey]bool),
axisLabels: make(map[string]string),
autoAxisLabels: make(map[string][]string),
}
return p
}
type plotEnv struct {
parent *plotEnv
data table.Grouping
}
type scaleKey struct {
gid table.GroupID
aes string
scale Scaler
}
// SetData sets p's current data table. The caller must not modify
// data in this table after this point.
func (p *Plot) SetData(data table.Grouping) *Plot {
p.env.data = data
return p
}
// Data returns p's current data table.
func (p *Plot) Data() table.Grouping {
return p.env.data
}
// Const creates a new constant column bound to val in all groups and
// returns the generated column name. This is a convenient way to pass
// constant values to layers as columns.
//
// TODO: Typically this should be used with PreScaled or physical types.
func (p *Plot) Const(val interface{}) string {
tab := p.Data()
retry:
col := fmt.Sprintf("[gg-const-%d]", p.constNonce)
p.constNonce++
for _, col2 := range tab.Columns() {
if col == col2 {
goto retry
}
}
p.SetData(table.MapTables(tab, func(_ table.GroupID, t *table.Table) *table.Table {
return table.NewBuilder(t).AddConst(col, val).Done()
}))
return col
}
type scalerTree struct {
scales map[table.GroupID]Scaler
}
func newScalerTree() scalerTree {
return scalerTree{map[table.GroupID]Scaler{
table.RootGroupID: &defaultScale{},
}}
}
func (t scalerTree) bind(gid table.GroupID, s Scaler) {
// Unbind scales under gid.
for ogid := range t.scales {
if gid == table.RootGroupID {
// Optimize binding the root GID.
delete(t.scales, ogid)
continue
}
for p := ogid; ; p = p.Parent() {
if p == gid {
delete(t.scales, ogid)
break
}
if p == table.RootGroupID {
break
}
}
}
t.scales[gid] = s
}
func (t scalerTree) find(gid table.GroupID) Scaler {
for {
if s, ok := t.scales[gid]; ok {
return s
}
if gid == table.RootGroupID {
// This should never happen.
panic("no scale for group " + gid.String())
}
gid = gid.Parent()
}
}
func (p *Plot) getScales(aes string) scalerTree {
st, ok := p.scales[aes]
if !ok {
st = newScalerTree()
p.scales[aes] = st
}
return st
}
func (p *Plot) copyScales(old, new table.GroupID) {
for _, st := range p.scales {
st.scales[new] = st.find(old)
}
}
// SetScale binds a scale to the given visual aesthetic. SetScale is
// shorthand for SetScaleAt(aes, s, table.RootGroupID). SetScale must
// be called before Add.
//
// SetScale returns p for ease of chaining.
func (p *Plot) SetScale(aes string, s Scaler) *Plot {
return p.SetScaleAt(aes, s, table.RootGroupID)
}
// SetScaleAt binds a scale to the given visual aesthetic for all data
// in group gid or descendants of gid. SetScaleAt must be called
// before Add.
func (p *Plot) SetScaleAt(aes string, s Scaler, gid table.GroupID) *Plot {
// TODO: Should aes be an enum so you can't mix up aesthetics
// and column names?
p.getScales(aes).bind(gid, s)
return p
}
// GetScale returns the scale for the given visual aesthetic used for
// data in the root group.
func (p *Plot) GetScale(aes string) Scaler {
return p.GetScaleAt(aes, table.RootGroupID)
}
// GetScaleAt returns the scale for the given visual aesthetic used
// for data in group gid.
func (p *Plot) GetScaleAt(aes string, gid table.GroupID) Scaler {
return p.getScales(aes).find(gid)
}
type scaledDataKey struct {
aes string
data table.Grouping
col string
}
// use binds a column of data to an aesthetic. It expands the domain
// of the aesthetic's scale to include the data in col, and returns
// the scaled data.
//
// col may be "", in which case it simply returns nil.
//
// TODO: Should aes be an enum?
func (p *Plot) use(aes string, col string) *scaledData {
if col == "" {
return nil
}
// TODO: This is wrong. If the scale tree for aes changes,
// this may return a stale scaledData bound to the wrong
// scalers. If I got rid of scale trees, I could just put the
// scaler in the key. Or I could clean up the cache when the
// scale tree changes.
sd := p.scaledData[scaledDataKey{aes, p.Data(), col}]
if sd == nil {
// Construct the scaledData.
sd = &scaledData{
seqs: make(map[table.GroupID]scaledSeq),
}
// Get the scale tree.
st := p.getScales(aes)
for _, gid := range p.Data().Tables() {
table := p.Data().Table(gid)
// Get the data.
seq := table.MustColumn(col)
// Find the scale.
scaler := st.find(gid)
// Add the scale to the scale set.
p.scaleSet[scaleKey{gid, aes, scaler}] = true
// Train the scale.
if _, ok := seq.([]Unscaled); !ok {
scaler.ExpandDomain(seq)
}
// Add it to the scaledData.
sd.seqs[gid] = scaledSeq{seq, scaler}
}
p.scaledData[scaledDataKey{aes, p.Data(), col}] = sd
}
// Update axis labels.
if aes == "x" || aes == "y" {
p.autoAxisLabels[aes] = append(p.autoAxisLabels[aes], col)
}
return sd
}
// Save saves the current data table of p to a stack.
func (p *Plot) Save() *Plot {
p.env = &plotEnv{
parent: p.env,
data: p.env.data,
}
return p
}
// Restore restores the data table of p from the save stack.
func (p *Plot) Restore() *Plot {
if p.env.parent == nil {
panic("unbalanced Save/Restore")
}
p.env = p.env.parent
return p
}
// A Plotter is an operation that can modify a Plot.
type Plotter interface {
Apply(*Plot)
}
// Add applies each of plotters to Plot in order.
func (p *Plot) Add(plotters ...Plotter) *Plot {
for _, plotter := range plotters {
plotter.Apply(p)
}
return p
}
// AxisLabel returns a Plotter that sets the label of an axis on a
// Plot. By default, Plot constructs automatic axis labels from column
// names, but AxisLabel lets callers override these.
//
// TODO: Should labels be attached to aesthetics, generally?
//
// TODO: Should this really be a Plotter or just a method of Plot?
func AxisLabel(axis, label string) Plotter {
return axisLabel{axis, label}
}
type axisLabel struct {
axis, label string
}
func (a axisLabel) Apply(p *Plot) {
p.axisLabels[a.axis] = a.label
}
// Title returns a Plotter that sets the title of a Plot.
func Title(label string) Plotter {
return titlePlotter{label}
}
type titlePlotter struct {
label string
}
func (t titlePlotter) Apply(p *Plot) {
p.title = t.label
}
// A Stat transforms a table.Grouping.
type Stat interface {
F(table.Grouping) table.Grouping
}
// Stat applies each of stats in order to p's data.
//
// TODO: Perform scale transforms before applying stats.
func (p *Plot) Stat(stats ...Stat) *Plot {
data := p.Data()
for _, stat := range stats {
data = stat.F(data)
}
return p.SetData(data)
}
================================================
FILE: benchplot/vendor/github.com/aclements/go-gg/gg/render.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gg
import (
"bytes"
"fmt"
"io"
"math"
"reflect"
"strings"
"github.com/aclements/go-gg/generic/slice"
"github.com/aclements/go-gg/table"
"github.com/ajstarks/svgo"
)
// fontSize is the font size in pixels.
//
// TODO: Theme.
const fontSize float64 = 14
// facetLabelHeight is the height of facet labels, as a multiple of
// the font height.
//
// TODO: Should this be a multiple of fontSize, em height, leading?
// Currently it's leading.
//
// TODO: Theme.
const facetLabelHeight = 1.3
const xTickSep = 5 // TODO: Theme.
const yTickSep = 5 // TODO: Theme.
// plotMargins returns the top, right, bottom, and left margins for a
// plot of the given width and height.
//
// By default, this adds a 5% margin based on the smaller of width and
// height. This ensures that (with automatic scales), the extremes of
// the data and its tick labels don't appear right at the edge of the
// plot area.
//
// TODO: Theme.
var plotMargins = func(w, h float64) (t, r, b, l float64) {
margin := 0.05 * math.Min(w, h)
return margin, margin, margin, margin
}
func (p *Plot) WriteSVG(w io.Writer, width, height int) error {
// TODO: Legend, title.
// TODO: Check if the same scaler is used for multiple
// aesthetics with conflicting rangers. Alternatively, if we
// just computed the scaled data eagerly here, it wouldn't
// matter if the same Scaler was used for multiple things
// because we would just change its Ranger between scaling
// different data. We could still optimize for get/get1 by
// specifying whether we care about all of the values or just
// the first when fetching the scaledData (arguably this
// should also affect scale training, so this is necessary
// anyway).
// TODO: Rather than finding these scales here and giving them
// Ratners, we could use special "Width"/"Height" Rangers and
// assign them much earlier (e.g., when they are Used). We
// could then either find all of the scales that have those
// Rangers and configure them at this point, or we could pass
// the renderEnv in when ranging.
// TODO: Default ranges for other things like color.
// TODO: Expose the layout so a package user can put together
// multiple Plots.
//
// What if the user wants multiple aligned plots, but as
// *different* images (e.g., flipping from one slide to
// another)?
// TODO: Let the user alternatively specify the width and
// height of the subplots, rather than the whole plot.
// TODO: Automatic aspect ratio by averaging slopes.
// TODO: Custom tick breaks.
// TODO: Make sure *all* Scalers have Rangers or the user will
// get confusing panics.
// TODO: If the user restricts, say, the X range, should that
// only train the Y axis on what's in the X range?
// Assign default Rangers to scales that don't have them.
//
// TODO: Do this on a clone of the scale so this doesn't
// persist.
for aes, scales := range p.scales {
if aes == "x" || aes == "y" {
// We'll assign these when we render each
// subplot.
continue
}
for _, scale := range scales.scales {
if scale.Ranger(nil) == nil {
scale.Ranger(defaultRanger(aes))
}
}
}
// Find all of the subplots and subdivide the marks.
//
// TODO: If a mark was done in a parent subplot, broadcast it
// to all child leafs of that subplot.
subplots := make(map[*subplot]*eltSubplot)
plotElts := []plotElt{}
for _, mark := range p.marks {
submarks := make(map[*eltSubplot]plotMark)
for _, gid := range mark.groups {
subplot := subplotOf(gid)
elt := subplots[subplot]
if elt == nil {
elt = newEltSubplot(subplot)
plotElts = append(plotElts, elt)
subplots[subplot] = elt
}
submark := submarks[elt]
submark.m = mark.m
submark.groups = append(submark.groups, gid)
submarks[elt] = submark
}
for subplot, submark := range submarks {
subplot.marks = append(subplot.marks, submark)
}
}
// Subdivide the scales.
for sk := range p.scaleSet {
subplot := subplotOf(sk.gid)
elt := subplots[subplot]
if elt == nil {
continue
}
ss := elt.scales[sk.aes]
if ss == nil {
ss = make(map[Scaler]bool)
elt.scales[sk.aes] = ss
}
ss[sk.scale] = true
}
// Add ticks and facet labels.
plotElts = addSubplotLabels(plotElts)
// Add axis labels and title.
var xlabel, ylabel string
if l, ok := p.axisLabels["x"]; ok {
xlabel = l
} else {
xlabel = strings.Join(slice.Nub(p.autoAxisLabels["x"]).([]string), "\n")
}
if l, ok := p.axisLabels["y"]; ok {
ylabel = l
} else {
ylabel = strings.Join(slice.Nub(p.autoAxisLabels["y"]).([]string), "\n")
}
plotElts = addAxisLabels(plotElts, p.title, xlabel, ylabel)
// Compute plot element layout.
layout := layoutPlotElts(plotElts)
// Perform layout. There's a cyclic dependency involving tick
// labels here: the tick labels depend on how many ticks there
// are, how
gitextract_zuo9c5tu/
├── LICENSE
├── abi/
│ ├── abi.go
│ ├── go.mod
│ └── go.sum
├── bench/
│ ├── parse.go
│ ├── parse_test.go
│ └── print.go
├── benchcmd/
│ ├── main.go
│ ├── rss_nounix.go
│ └── rss_unix.go
├── benchmany/
│ ├── benchmany.go
│ ├── commits.go
│ ├── readlog.go
│ ├── run.go
│ ├── run_test.go
│ ├── signal_notunix.go
│ ├── signal_unix.go
│ └── status.go
├── benchplot/
│ ├── git.go
│ ├── kza.go
│ ├── kza_test.go
│ ├── main.go
│ ├── plot.go
│ ├── table.go
│ └── vendor/
│ ├── github.com/
│ │ └── aclements/
│ │ ├── go-gg/
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ ├── generic/
│ │ │ │ ├── doc.go
│ │ │ │ ├── error.go
│ │ │ │ ├── order.go
│ │ │ │ └── slice/
│ │ │ │ ├── concat.go
│ │ │ │ ├── concat_test.go
│ │ │ │ ├── convert.go
│ │ │ │ ├── convert_test.go
│ │ │ │ ├── cycle.go
│ │ │ │ ├── doc.go
│ │ │ │ ├── find.go
│ │ │ │ ├── index.go
│ │ │ │ ├── min.go
│ │ │ │ ├── min_test.go
│ │ │ │ ├── nub.go
│ │ │ │ ├── select_test.go
│ │ │ │ ├── seq.go
│ │ │ │ ├── sort.go
│ │ │ │ └── util_test.go
│ │ │ ├── gg/
│ │ │ │ ├── example_scale_test.go
│ │ │ │ ├── facet.go
│ │ │ │ ├── group.go
│ │ │ │ ├── layer.go
│ │ │ │ ├── layout/
│ │ │ │ │ ├── grid.go
│ │ │ │ │ └── layout.go
│ │ │ │ ├── layout.go
│ │ │ │ ├── mark.go
│ │ │ │ ├── package.go
│ │ │ │ ├── plot.go
│ │ │ │ ├── render.go
│ │ │ │ ├── scale.go
│ │ │ │ ├── stepmode_string.go
│ │ │ │ ├── testmain.go
│ │ │ │ ├── text.go
│ │ │ │ └── transform.go
│ │ │ ├── ggstat/
│ │ │ │ ├── agg.go
│ │ │ │ ├── bin.go
│ │ │ │ ├── common.go
│ │ │ │ ├── density.go
│ │ │ │ ├── domain.go
│ │ │ │ ├── ecdf.go
│ │ │ │ ├── fn.go
│ │ │ │ ├── loess.go
│ │ │ │ ├── lsquares.go
│ │ │ │ └── normalize.go
│ │ │ ├── palette/
│ │ │ │ ├── blend.go
│ │ │ │ ├── brewer/
│ │ │ │ │ ├── brewer.go
│ │ │ │ │ ├── colorbrewer.json
│ │ │ │ │ ├── genbrewer.go
│ │ │ │ │ └── package.go
│ │ │ │ ├── makesrgbtab.go
│ │ │ │ ├── palette.go
│ │ │ │ ├── srgb.go
│ │ │ │ ├── srgbtab.go
│ │ │ │ └── viridis.go
│ │ │ └── table/
│ │ │ ├── concat.go
│ │ │ ├── filter.go
│ │ │ ├── group.go
│ │ │ ├── head.go
│ │ │ ├── join.go
│ │ │ ├── map.go
│ │ │ ├── new.go
│ │ │ ├── new_test.go
│ │ │ ├── pivot.go
│ │ │ ├── pivot_test.go
│ │ │ ├── print.go
│ │ │ ├── print_test.go
│ │ │ ├── sort.go
│ │ │ ├── table.go
│ │ │ └── table_test.go
│ │ └── go-moremath/
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── cmd/
│ │ │ └── dist/
│ │ │ ├── dist.go
│ │ │ └── plot.go
│ │ ├── fit/
│ │ │ ├── loess.go
│ │ │ ├── loess_test.go
│ │ │ ├── lsquares.go
│ │ │ └── package.go
│ │ ├── internal/
│ │ │ └── mathtest/
│ │ │ └── mathtest.go
│ │ ├── mathx/
│ │ │ ├── beta.go
│ │ │ ├── beta_test.go
│ │ │ ├── choose.go
│ │ │ ├── gamma.go
│ │ │ ├── gamma_test.go
│ │ │ ├── package.go
│ │ │ └── sign.go
│ │ ├── scale/
│ │ │ ├── err.go
│ │ │ ├── interface.go
│ │ │ ├── linear.go
│ │ │ ├── linear_test.go
│ │ │ ├── log.go
│ │ │ ├── log_test.go
│ │ │ ├── package.go
│ │ │ ├── ticks.go
│ │ │ ├── ticks_test.go
│ │ │ └── util.go
│ │ ├── stats/
│ │ │ ├── alg.go
│ │ │ ├── deltadist.go
│ │ │ ├── dist.go
│ │ │ ├── dist_test.go
│ │ │ ├── hist.go
│ │ │ ├── hypergdist.go
│ │ │ ├── hypergdist_test.go
│ │ │ ├── kde.go
│ │ │ ├── kde_test.go
│ │ │ ├── kdeboundarymethod_string.go
│ │ │ ├── kdekernel_string.go
│ │ │ ├── linearhist.go
│ │ │ ├── locationhypothesis_string.go
│ │ │ ├── loghist.go
│ │ │ ├── normaldist.go
│ │ │ ├── normaldist_test.go
│ │ │ ├── package.go
│ │ │ ├── sample.go
│ │ │ ├── sample_test.go
│ │ │ ├── stream.go
│ │ │ ├── tdist.go
│ │ │ ├── tdist_test.go
│ │ │ ├── ttest.go
│ │ │ ├── ttest_test.go
│ │ │ ├── udist.go
│ │ │ ├── udist_test.go
│ │ │ ├── utest.go
│ │ │ ├── utest_test.go
│ │ │ └── util_test.go
│ │ └── vec/
│ │ ├── package.go
│ │ └── vec.go
│ └── update
├── benchscripts/
│ ├── bench-many
│ ├── benchstat2
│ ├── plot-time
│ └── plot-time-2
├── buildstats/
│ ├── alg.go
│ ├── go.mod
│ ├── go.sum
│ ├── main.go
│ ├── rev.go
│ └── timeflag.go
├── cl-fetch/
│ └── main.go
├── dashquery/
│ ├── compile.go
│ ├── compile_test.go
│ ├── main.go
│ └── xdg.go
├── findflakes/
│ ├── adtest.go
│ ├── flaketest.go
│ ├── geodist.go
│ ├── html.go
│ ├── logs.go
│ ├── main.go
│ ├── paths.go
│ ├── text.go
│ └── xdg.go
├── findtypes/
│ └── main.go
├── foreachplatform/
│ ├── go.mod
│ └── main.go
├── gc-S/
│ ├── go.mod
│ └── main.go
├── gcdense/
│ └── test.py
├── git-p/
│ ├── gerrit.go
│ ├── git.go
│ ├── go.mod
│ ├── go.sum
│ ├── main.go
│ ├── pager.go
│ ├── shell.go
│ └── style.go
├── go-weave/
│ ├── amb/
│ │ ├── det.go
│ │ ├── progress.go
│ │ ├── rand.go
│ │ └── run.go
│ ├── models/
│ │ ├── cl20858.go
│ │ ├── issue16083.go
│ │ ├── markterm.go
│ │ ├── maxtree.go
│ │ ├── rescan.go
│ │ ├── rwmutex.go
│ │ └── yuasa.go
│ └── weave/
│ ├── atomic.go
│ ├── mutex.go
│ ├── sema.go
│ ├── tls.go
│ ├── trace.go
│ ├── waitgroup.go
│ └── weave.go
├── go.mod
├── go.sum
├── goi/
│ └── main.go
├── gover/
│ ├── cache.go
│ ├── gover.go
│ └── shutil.go
├── greplogs/
│ └── main.go
├── internal/
│ └── loganal/
│ ├── classify.go
│ ├── doc.go
│ ├── failure.go
│ └── matcher.go
├── minutes3/
│ ├── README.md
│ ├── gdoc.go
│ ├── gdoc_test.go
│ ├── github.go
│ ├── go.mod
│ ├── go.sum
│ ├── minutes.go
│ ├── oauth.go
│ └── tables.go
├── pcvaluetab/
│ ├── README.md
│ ├── alt.go
│ ├── alt_test.go
│ ├── bench_test.go
│ ├── dist.go
│ ├── enc.go
│ ├── go.mod
│ ├── go.sum
│ ├── main.go
│ ├── read.go
│ └── symtab.go
├── ptype/
│ └── main.go
├── rtanalysis/
│ ├── directives/
│ │ └── analysis.go
│ ├── main.go
│ └── systemstack/
│ └── analysis.go
├── scanpagemap.go
├── split/
│ ├── README.md
│ ├── bench_test.go
│ ├── example_id_test.go
│ ├── example_rwmutex_test.go
│ ├── examples_test.go
│ ├── stub.s
│ ├── value.go
│ └── vlogger_test.go
├── srgb/
│ └── main.go
├── stackmapcompress.py
├── stress2/
│ ├── cmd.go
│ ├── cmd_test.go
│ ├── go.mod
│ ├── go.sum
│ ├── main.go
│ ├── reporter.go
│ ├── signal_notunix.go
│ ├── signal_unix.go
│ ├── stress.go
│ └── stress_test.go
├── varint/
│ ├── README.md
│ ├── asm_amd64.s
│ ├── bench_test.go
│ └── varint.go
└── whichtest/
└── whichtest
SYMBOL INDEX (1621 symbols across 219 files)
FILE: abi/abi.go
constant minIntRegs (line 26) | minIntRegs = 0
constant maxIntRegs (line 27) | maxIntRegs = 16
constant minFloatRegs (line 31) | minFloatRegs = 8
constant maxFloatRegs (line 32) | maxFloatRegs = 8
constant modeCompare (line 35) | modeCompare = false
function main (line 38) | func main() {
type ABIOptions (line 182) | type ABIOptions struct
method Assign (line 214) | func (a *ABIOptions) Assign(sig *types.Signature, sizes types.Sizes) F...
type frameBuilder (line 195) | type frameBuilder struct
method AddArg (line 244) | func (f *frameBuilder) AddArg(arg types.Type, needsSpill bool) {
method RegAssign (line 268) | func (f *frameBuilder) RegAssign(arg types.Type, top bool) bool {
method StackAssign (line 346) | func (f *frameBuilder) StackAssign(arg types.Type) {
type Frame (line 205) | type Frame struct
function align (line 351) | func align(x, n int) int {
function intQuantiles (line 355) | func intQuantiles(xs []int, qs ...float64) []int {
function floatQuantiles (line 370) | func floatQuantiles(xs []float64, qs ...float64) []float64 {
function printTable (line 385) | func printTable(w io.Writer, table [][]interface{}) {
FILE: bench/parse.go
type Benchmark (line 24) | type Benchmark struct
type Config (line 45) | type Config struct
function Parse (line 69) | func Parse(r io.Reader) ([]*Benchmark, error) {
function parseBenchmark (line 103) | func parseBenchmark(line string, gconfig map[string]*Config) *Benchmark {
type ValueParser (line 173) | type ValueParser
function ParseValues (line 193) | func ParseValues(benchmarks []*Benchmark, valueParsers []ValueParser) {
FILE: bench/parse_test.go
function TestParse (line 13) | func TestParse(t *testing.T) {
FILE: bench/print.go
function Print (line 15) | func Print(bs []*Benchmark) error {
function Fprint (line 19) | func Fprint(w io.Writer, bs []*Benchmark) error {
type resultKeySorter (line 172) | type resultKeySorter
method Len (line 174) | func (s resultKeySorter) Len() int {
method Less (line 178) | func (s resultKeySorter) Less(i, j int) bool {
method Swap (line 186) | func (s resultKeySorter) Swap(i, j int) {
FILE: benchcmd/main.go
function main (line 16) | func main() {
FILE: benchcmd/rss_nounix.go
function getMaxRSS (line 11) | func getMaxRSS(ps *os.ProcessState) (bytes uint64, ok bool) {
FILE: benchcmd/rss_unix.go
function getMaxRSS (line 15) | func getMaxRSS(ps *os.ProcessState) (bytes uint64, ok bool) {
FILE: benchmany/benchmany.go
constant maxFails (line 64) | maxFails = 5
function main (line 66) | func main() {
function git (line 73) | func git(subcmd string, args ...string) string {
function dryPrint (line 96) | func dryPrint(cmd *exec.Cmd) {
function shellEscape (line 107) | func shellEscape(x string) string {
function shellEscapeList (line 121) | func shellEscapeList(xs []string) string {
function exists (line 129) | func exists(path string) bool {
function trimNL (line 134) | func trimNL(s string) string {
function indent (line 140) | func indent(s string) string {
function lines (line 151) | func lines(s string) []string {
FILE: benchmany/commits.go
type commitInfo (line 22) | type commitInfo struct
method binPath (line 134) | func (c *commitInfo) binPath() string {
method failed (line 141) | func (c *commitInfo) failed() bool {
method runnable (line 147) | func (c *commitInfo) runnable() bool {
method partial (line 153) | func (c *commitInfo) partial() bool {
method logRun (line 170) | func (c *commitInfo) logRun(out string) {
method logFailed (line 181) | func (c *commitInfo) logFailed(buildFailed bool, out string) {
method writeLog (line 196) | func (c *commitInfo) writeLog(msg string) {
function getCommits (line 36) | func getCommits(revRange []string, logPath string) []*commitInfo {
function goverDir (line 87) | func goverDir() string {
function parseLog (line 104) | func parseLog(commitMap map[string]*commitInfo, r io.Reader) {
function cleanLog (line 161) | func cleanLog(l string) string {
FILE: benchmany/readlog.go
type Benchstat (line 24) | type Benchstat struct
method ComputeStats (line 18) | func (stat *Benchstat) ComputeStats() {
type BenchKey (line 33) | type BenchKey struct
type Collection (line 37) | type Collection struct
method AddStat (line 53) | func (c *Collection) AddStat(key BenchKey) *Benchstat {
method addKey (line 64) | func (c *Collection) addKey(key BenchKey) {
method Filter (line 78) | func (c *Collection) Filter(key BenchKey) *Collection {
function NewCollection (line 91) | func NewCollection() *Collection {
function readFiles (line 101) | func readFiles(files ...string) *Collection {
function readFile (line 126) | func readFile(file string, c *Collection) {
FILE: benchmany/run.go
function init (line 48) | func init() {
function doRun (line 83) | func doRun() {
function writeHeader (line 140) | func writeHeader(w io.Writer) {
function runStats (line 170) | func runStats(commits []*commitInfo) (doneIters, totalIters, partialComm...
function pickCommitSeq (line 196) | func pickCommitSeq(commits []*commitInfo) *commitInfo {
function pickCommitSpread (line 211) | func pickCommitSpread(commits []*commitInfo) *commitInfo {
function pickCommitMetric (line 302) | func pickCommitMetric(commits []*commitInfo) *commitInfo {
function runBenchmark (line 403) | func runBenchmark(commit *commitInfo, status *StatusReporter) {
function doGoverSave (line 487) | func doGoverSave() error {
function runStatus (line 503) | func runStatus(sr *StatusReporter, commit *commitInfo, status string) {
function combinedOutputTimeout (line 509) | func combinedOutputTimeout(c *exec.Cmd) (out []byte, err error) {
FILE: benchmany/run_test.go
function TestPickSpread (line 19) | func TestPickSpread(t *testing.T) {
function TestRun (line 53) | func TestRun(t *testing.T) {
function tgit (line 137) | func tgit(t *testing.T, repo string, args ...string) string {
FILE: benchmany/status.go
type StatusReporter (line 17) | type StatusReporter struct
method Progress (line 37) | func (sr *StatusReporter) Progress(msg string, frac float64) {
method Message (line 43) | func (sr *StatusReporter) Message(msg string) {
method Stop (line 51) | func (sr *StatusReporter) Stop() {
method loop (line 60) | func (sr *StatusReporter) loop(updates <-chan statusUpdate) {
type statusUpdate (line 22) | type statusUpdate struct
function NewStatusReporter (line 27) | func NewStatusReporter() *StatusReporter {
FILE: benchplot/git.go
type CommitInfo (line 16) | type CommitInfo struct
function Commits (line 23) | func Commits(repo string, revs ...string) (commits []CommitInfo) {
FILE: benchplot/kza.go
function MovingAverage (line 25) | func MovingAverage(xs []float64, m int) []float64 {
function KolmogorovZurbenko (line 50) | func KolmogorovZurbenko(xs []float64, m, k int) []float64 {
function AdaptiveKolmogorovZurbenko (line 68) | func AdaptiveKolmogorovZurbenko(xs []float64, m, k int) []float64 {
FILE: benchplot/kza_test.go
function Aeq (line 14) | func Aeq(expect, got float64) bool {
function TestMovingAverage (line 21) | func TestMovingAverage(t *testing.T) {
function slowMovingAverage (line 41) | func slowMovingAverage(xs []float64, m int) []float64 {
FILE: benchplot/main.go
function main (line 32) | func main() {
FILE: benchplot/plot.go
function plot (line 15) | func plot(t table.Grouping, configCols, resultCols []string) (*gg.Plot, ...
function firstMasterIndex (line 94) | func firstMasterIndex(bs []string) int {
type commitIndex (line 98) | type commitIndex struct
method F (line 100) | func (commitIndex) F(g table.Grouping) table.Grouping {
type convertFloat (line 117) | type convertFloat struct
method F (line 121) | func (c convertFloat) F(g table.Grouping) table.Grouping {
function removeNaNs (line 133) | func removeNaNs(g table.Grouping, col string) table.Grouping {
type kza (line 139) | type kza struct
method F (line 144) | func (k kza) F(g table.Grouping) table.Grouping {
type tooltip (line 153) | type tooltip struct
method F (line 157) | func (t tooltip) F(g table.Grouping) table.Grouping {
FILE: benchplot/table.go
function benchmarksToTable (line 18) | func benchmarksToTable(bs []*bench.Benchmark) (t *table.Table, configCol...
function commitsToTable (line 92) | func commitsToTable(commits []CommitInfo) *table.Table {
type byTime (line 116) | type byTime
method Len (line 118) | func (s byTime) Len() int {
method Less (line 122) | func (s byTime) Less(i, j int) bool {
method Swap (line 126) | func (s byTime) Swap(i, j int) {
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/error.go
type TypeError (line 9) | type TypeError struct
method Error (line 14) | func (e TypeError) Error() string {
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/order.go
function CanOrder (line 11) | func CanOrder(a, b interface{}) bool {
function CanOrderR (line 38) | func CanOrderR(k reflect.Kind) bool {
function Order (line 47) | func Order(a, b interface{}) int {
function OrderR (line 52) | func OrderR(a, b reflect.Value) int {
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/concat.go
function Concat (line 18) | func Concat(ss ...T) T {
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/concat_test.go
function TestConcat (line 9) | func TestConcat(t *testing.T) {
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/convert.go
function Convert (line 18) | func Convert(to interface{}, from T) {
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/convert_test.go
function TestConvert (line 9) | func TestConvert(t *testing.T) {
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/cycle.go
function Cycle (line 13) | func Cycle(s T, length int) T {
function Repeat (line 35) | func Repeat(v interface{}, length int) T {
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/find.go
function Index (line 15) | func Index(s T, val interface{}) int {
function LastIndex (line 32) | func LastIndex(s T, val interface{}) int {
function Contains (line 49) | func Contains(s T, val interface{}) bool {
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/index.go
function Select (line 14) | func Select(v T, indexes []int) T {
function SelectInto (line 49) | func SelectInto(out, in T, indexes []int) {
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/min.go
function Min (line 17) | func Min(v T) interface{} {
function ArgMin (line 26) | func ArgMin(v interface{}) int {
function Max (line 34) | func Max(v T) interface{} {
function ArgMax (line 43) | func ArgMax(v interface{}) int {
function minmax (line 48) | func minmax(v interface{}, keep int, val bool) (reflect.Value, int) {
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/min_test.go
function TestMin (line 13) | func TestMin(t *testing.T) {
type fakeSortInterface (line 42) | type fakeSortInterface struct
method Len (line 46) | func (f fakeSortInterface) Len() int {
method Swap (line 50) | func (f fakeSortInterface) Swap(i, j int) {
method Less (line 54) | func (f fakeSortInterface) Less(i, j int) bool {
type timeSlice (line 58) | type timeSlice
method Len (line 60) | func (s timeSlice) Len() int {
method Less (line 64) | func (s timeSlice) Less(i, j int) bool {
method Swap (line 68) | func (s timeSlice) Swap(i, j int) {
function TestMinSort (line 72) | func TestMinSort(t *testing.T) {
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/nub.go
function Nub (line 13) | func Nub(v T) T {
function NubAppend (line 30) | func NubAppend(vs ...T) T {
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/select_test.go
function TestSelect (line 12) | func TestSelect(t *testing.T) {
function TestSelectType (line 31) | func TestSelectType(t *testing.T) {
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/seq.go
type T (line 18) | type T interface
function reflectSlice (line 22) | func reflectSlice(s T) reflect.Value {
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/sort.go
function CanSort (line 16) | func CanSort(v interface{}) bool {
function Sort (line 26) | func Sort(v interface{}) {
function Sorter (line 33) | func Sorter(v interface{}) sort.Interface {
type sortIntSlice (line 61) | type sortIntSlice struct
method Len (line 65) | func (s sortIntSlice) Len() int {
method Less (line 69) | func (s sortIntSlice) Less(i, j int) bool {
method Swap (line 73) | func (s sortIntSlice) Swap(i, j int) {
type sortUintSlice (line 79) | type sortUintSlice struct
method Len (line 83) | func (s sortUintSlice) Len() int {
method Less (line 87) | func (s sortUintSlice) Less(i, j int) bool {
method Swap (line 91) | func (s sortUintSlice) Swap(i, j int) {
type sortFloatSlice (line 97) | type sortFloatSlice struct
method Len (line 101) | func (s sortFloatSlice) Len() int {
method Less (line 105) | func (s sortFloatSlice) Less(i, j int) bool {
method Swap (line 109) | func (s sortFloatSlice) Swap(i, j int) {
type sortStringSlice (line 115) | type sortStringSlice struct
method Len (line 119) | func (s sortStringSlice) Len() int {
method Less (line 123) | func (s sortStringSlice) Less(i, j int) bool {
method Swap (line 127) | func (s sortStringSlice) Swap(i, j int) {
type sortTimeSlice (line 133) | type sortTimeSlice
method Len (line 135) | func (s sortTimeSlice) Len() int { return len(s) }
method Less (line 136) | func (s sortTimeSlice) Less(i, j int) bool { return s[i].Before(s[j]) }
method Swap (line 137) | func (s sortTimeSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
FILE: benchplot/vendor/github.com/aclements/go-gg/generic/slice/util_test.go
function de (line 14) | func de(x, y interface{}) bool {
function shouldPanic (line 18) | func shouldPanic(t *testing.T, re string, f func()) {
FILE: benchplot/vendor/github.com/aclements/go-gg/gg/example_scale_test.go
function ExampleNewTimeScaler (line 16) | func ExampleNewTimeScaler() {
FILE: benchplot/vendor/github.com/aclements/go-gg/gg/facet.go
type FacetCommon (line 39) | type FacetCommon struct
method apply (line 109) | func (f *FacetCommon) apply(p *Plot, dir string) {
type FacetX (line 89) | type FacetX
method Apply (line 97) | func (f FacetX) Apply(p *Plot) {
type FacetY (line 92) | type FacetY
method Apply (line 101) | func (f FacetY) Apply(p *Plot) {
type FacetWrap (line 95) | type FacetWrap
method Apply (line 105) | func (f FacetWrap) Apply(p *Plot) {
type subplotBand (line 297) | type subplotBand struct
type subplot (line 302) | type subplot struct
method String (line 324) | func (s subplot) String() string {
function subplotOf (line 314) | func subplotOf(gid table.GroupID) *subplot {
FILE: benchplot/vendor/github.com/aclements/go-gg/gg/group.go
method GroupBy (line 14) | func (p *Plot) GroupBy(cols ...string) *Plot {
method GroupAuto (line 28) | func (p *Plot) GroupAuto() *Plot {
FILE: benchplot/vendor/github.com/aclements/go-gg/gg/layer.go
function defaultCols (line 13) | func defaultCols(p *Plot, cols ...*string) {
type LayerLines (line 27) | type LayerLines
method Apply (line 29) | func (l LayerLines) Apply(p *Plot) {
type StepMode (line 36) | type StepMode
constant StepHV (line 41) | StepHV StepMode = iota
constant StepVH (line 45) | StepVH
constant StepHMid (line 51) | StepHMid
constant StepVMid (line 57) | StepVMid
type LayerSteps (line 62) | type LayerSteps struct
method Apply (line 68) | func (l LayerSteps) Apply(p *Plot) {
type LayerPaths (line 88) | type LayerPaths struct
method Apply (line 123) | func (l LayerPaths) Apply(p *Plot) {
method apply (line 127) | func (l LayerPaths) apply(p *Plot, sort bool) {
type LayerArea (line 151) | type LayerArea struct
method Apply (line 172) | func (l LayerArea) Apply(p *Plot) {
type LayerPoints (line 199) | type LayerPoints struct
method Apply (line 222) | func (l LayerPoints) Apply(p *Plot) {
type LayerTiles (line 244) | type LayerTiles struct
method Apply (line 263) | func (l LayerTiles) Apply(p *Plot) {
type LayerTags (line 288) | type LayerTags struct
method Apply (line 311) | func (l LayerTags) Apply(p *Plot) {
type LayerTooltips (line 339) | type LayerTooltips struct
method Apply (line 353) | func (l LayerTooltips) Apply(p *Plot) {
FILE: benchplot/vendor/github.com/aclements/go-gg/gg/layout.go
type plotElt (line 49) | type plotElt interface
type eltRender (line 61) | type eltRender struct
method genid (line 66) | func (r *eltRender) genid(prefix string) (id, ref string) {
type eltCommon (line 73) | type eltCommon struct
method paths (line 77) | func (c *eltCommon) paths() (xPath, yPath, x2Path, y2Path eltPath) {
type eltSubplot (line 81) | type eltSubplot struct
method SizeHint (line 104) | func (e *eltSubplot) SizeHint() (w, h float64, flexw, flexh bool) {
method SetLayout (line 108) | func (e *eltSubplot) SetLayout(x, y, w, h float64) {
function newEltSubplot (line 96) | func newEltSubplot(s *subplot) *eltSubplot {
type eltTicks (line 114) | type eltTicks struct
method scales (line 146) | func (e *eltTicks) scales() map[Scaler]bool {
method mapTicks (line 157) | func (e *eltTicks) mapTicks(s Scaler, ticks table.Slice) (pixels []flo...
method computeTicks (line 180) | func (e *eltTicks) computeTicks() {
method SizeHint (line 229) | func (e *eltTicks) SizeHint() (w, h float64, flexw, flexh bool) {
type plotEltTicks (line 123) | type plotEltTicks struct
function newEltTicks (line 129) | func newEltTicks(axis rune, s *eltSubplot) *eltTicks {
type eltLabel (line 260) | type eltLabel struct
method SizeHint (line 312) | func (e *eltLabel) SizeHint() (w, h float64, flexw, flexh bool) {
function newEltLabelFacet (line 269) | func newEltLabelFacet(side rune, label string, x1, y1, x2, y2 int, level...
function newEltLabelAxis (line 294) | func newEltLabelAxis(side rune, label string, x, y, span int) *eltLabel {
type eltPadding (line 328) | type eltPadding struct
method SizeHint (line 355) | func (e *eltPadding) SizeHint() (w, h float64, flexw, flexh bool) {
function newEltPadding (line 335) | func newEltPadding(side rune, x, y int) *eltPadding {
function addSubplotLabels (line 368) | func addSubplotLabels(elts []plotElt) []plotElt {
function addAxisLabels (line 441) | func addAxisLabels(elts []plotElt, title, xlabel, ylabel string) []plotE...
type subplotRegion (line 469) | type subplotRegion struct
method update (line 474) | func (r *subplotRegion) update(s *subplot, level int) {
type subplotSorter (line 496) | type subplotSorter struct
method Len (line 515) | func (s subplotSorter) Len() int {
method Less (line 519) | func (s subplotSorter) Less(i, j int) bool {
method Swap (line 534) | func (s subplotSorter) Swap(i, j int) {
function newSubplotSorter (line 505) | func newSubplotSorter(elts []plotElt, dir rune) *subplotSorter {
function eqScales (line 538) | func eqScales(a, b *eltSubplot, aes string) bool {
type eltPath (line 551) | type eltPath
method cmp (line 553) | func (a eltPath) cmp(b eltPath) int {
type eltPaths (line 573) | type eltPaths
method Len (line 575) | func (s eltPaths) Len() int {
method Less (line 579) | func (s eltPaths) Less(i, j int) bool {
method Swap (line 583) | func (s eltPaths) Swap(i, j int) {
method nub (line 587) | func (s eltPaths) nub() eltPaths {
method find (line 598) | func (s eltPaths) find(p eltPath) int {
function layoutPlotElts (line 609) | func layoutPlotElts(elts []plotElt) layout.Element {
FILE: benchplot/vendor/github.com/aclements/go-gg/gg/layout/grid.go
type Grid (line 12) | type Grid struct
method Add (line 25) | func (g *Grid) Add(e Element, x, y, colSpan, rowSpan int) {
method Children (line 35) | func (g *Grid) Children() []Element {
method doLayout (line 43) | func (g *Grid) doLayout(byRow bool, allocated float64) (dims []float64...
method SizeHint (line 173) | func (g *Grid) SizeHint() (w, h float64, flexw, flexh bool) {
method SetLayout (line 195) | func (g *Grid) SetLayout(x, y, w, h float64) {
method Layout (line 217) | func (g *Grid) Layout() (x, y, w, h float64) {
type gridElement (line 18) | type gridElement struct
type gridElementSorter (line 221) | type gridElementSorter struct
method Len (line 227) | func (g *gridElementSorter) Len() int {
method Less (line 231) | func (g *gridElementSorter) Less(i, j int) bool {
method Swap (line 239) | func (g *gridElementSorter) Swap(i, j int) {
FILE: benchplot/vendor/github.com/aclements/go-gg/gg/layout/layout.go
type Element (line 18) | type Element interface
type Group (line 47) | type Group interface
type Leaf (line 57) | type Leaf struct
method SetLayout (line 61) | func (l *Leaf) SetLayout(x, y, w, h float64) {
method Layout (line 65) | func (l *Leaf) Layout() (x, y, w, h float64) {
FILE: benchplot/vendor/github.com/aclements/go-gg/gg/mark.go
type marker (line 28) | type marker interface
function isFinite (line 32) | func isFinite(x float64) bool {
type plotMark (line 36) | type plotMark struct
type markPath (line 41) | type markPath struct
method mark (line 45) | func (m *markPath) mark(env *renderEnv, canvas *svg.SVG) {
type markArea (line 62) | type markArea struct
method mark (line 74) | func (m *markArea) mark(env *renderEnv, canvas *svg.SVG) {
function reversed (line 66) | func reversed(data []float64) []float64 {
type markSteps (line 99) | type markSteps struct
method mark (line 105) | func (m *markSteps) mark(env *renderEnv, canvas *svg.SVG) {
function drawPath (line 155) | func drawPath(canvas *svg.SVG, xs, ys []float64, stroke color.Color, fil...
type markPoint (line 193) | type markPoint struct
method mark (line 197) | func (m *markPoint) mark(env *renderEnv, canvas *svg.SVG) {
type markTiles (line 236) | type markTiles struct
method mark (line 240) | func (m *markTiles) mark(env *renderEnv, canvas *svg.SVG) {
type markTags (line 341) | type markTags struct
method mark (line 349) | func (m *markTags) mark(env *renderEnv, canvas *svg.SVG) {
type markTooltips (line 395) | type markTooltips struct
method mark (line 400) | func (m *markTooltips) mark(env *renderEnv, canvas *svg.SVG) {
function cssPaint (line 518) | func cssPaint(prop string, c color.Color) string {
FILE: benchplot/vendor/github.com/aclements/go-gg/gg/plot.go
type Plot (line 23) | type Plot struct
method SetData (line 68) | func (p *Plot) SetData(data table.Grouping) *Plot {
method Data (line 74) | func (p *Plot) Data() table.Grouping {
method Const (line 83) | func (p *Plot) Const(val interface{}) string {
method getScales (line 147) | func (p *Plot) getScales(aes string) scalerTree {
method copyScales (line 156) | func (p *Plot) copyScales(old, new table.GroupID) {
method SetScale (line 167) | func (p *Plot) SetScale(aes string, s Scaler) *Plot {
method SetScaleAt (line 174) | func (p *Plot) SetScaleAt(aes string, s Scaler, gid table.GroupID) *Pl...
method GetScale (line 183) | func (p *Plot) GetScale(aes string) Scaler {
method GetScaleAt (line 189) | func (p *Plot) GetScaleAt(aes string, gid table.GroupID) Scaler {
method use (line 206) | func (p *Plot) use(aes string, col string) *scaledData {
method Save (line 260) | func (p *Plot) Save() *Plot {
method Restore (line 269) | func (p *Plot) Restore() *Plot {
method Add (line 283) | func (p *Plot) Add(plotters ...Plotter) *Plot {
method Stat (line 330) | func (p *Plot) Stat(stats ...Stat) *Plot {
function NewPlot (line 41) | func NewPlot(data table.Grouping) *Plot {
type plotEnv (line 55) | type plotEnv struct
type scaleKey (line 60) | type scaleKey struct
type scalerTree (line 102) | type scalerTree struct
method bind (line 112) | func (t scalerTree) bind(gid table.GroupID, s Scaler) {
method find (line 134) | func (t scalerTree) find(gid table.GroupID) Scaler {
function newScalerTree (line 106) | func newScalerTree() scalerTree {
type scaledDataKey (line 193) | type scaledDataKey struct
type Plotter (line 278) | type Plotter interface
function AxisLabel (line 297) | func AxisLabel(axis, label string) Plotter {
type axisLabel (line 301) | type axisLabel struct
method Apply (line 305) | func (a axisLabel) Apply(p *Plot) {
function Title (line 310) | func Title(label string) Plotter {
type titlePlotter (line 314) | type titlePlotter struct
method Apply (line 318) | func (t titlePlotter) Apply(p *Plot) {
type Stat (line 323) | type Stat interface
FILE: benchplot/vendor/github.com/aclements/go-gg/gg/render.go
constant fontSize (line 23) | fontSize float64 = 14
constant facetLabelHeight (line 32) | facetLabelHeight = 1.3
constant xTickSep (line 34) | xTickSep = 5
constant yTickSep (line 36) | yTickSep = 5
method WriteSVG (line 52) | func (p *Plot) WriteSVG(w io.Writer, width, height int) error {
method render (line 207) | func (e *eltSubplot) render(r *eltRender) {
function renderBackground (line 278) | func renderBackground(svg *svg.SVG, x, y, w, h int) {
function renderGrid (line 282) | func renderGrid(svg *svg.SVG, dir rune, scale Scaler, ticks plotEltTicks...
function renderScale (line 302) | func renderScale(svg *svg.SVG, dir rune, scale Scaler, ticks plotEltTick...
method render (line 339) | func (e *eltTicks) render(r *eltRender) {
method render (line 355) | func (e *eltLabel) render(r *eltRender) {
method render (line 382) | func (e *eltPadding) render(r *eltRender) {
type renderEnv (line 385) | type renderEnv struct
method get (line 409) | func (env *renderEnv) get(sd *scaledData) table.Slice {
method getFirst (line 421) | func (env *renderEnv) getFirst(sd *scaledData) interface{} {
method Area (line 438) | func (env *renderEnv) Area() (x, y, w, h float64) {
method Size (line 442) | func (env *renderEnv) Size() (w, h float64) {
type renderCacheKey (line 391) | type renderCacheKey struct
type scaledData (line 400) | type scaledData struct
type scaledSeq (line 404) | type scaledSeq struct
function round (line 446) | func round(x float64) int {
function wrapPath (line 452) | func wrapPath(p string) string {
FILE: benchplot/vendor/github.com/aclements/go-gg/gg/scale.go
type Scaler (line 74) | type Scaler interface
type ContinuousScaler (line 164) | type ContinuousScaler interface
type Unscaled (line 204) | type Unscaled
function isCardinal (line 225) | func isCardinal(k reflect.Kind) bool {
type defaultScale (line 235) | type defaultScale struct
method String (line 243) | func (s *defaultScale) String() string {
method ExpandDomain (line 247) | func (s *defaultScale) ExpandDomain(v table.Slice) {
method ensure (line 259) | func (s *defaultScale) ensure() Scaler {
method instantiate (line 269) | func (s *defaultScale) instantiate() {
method Ranger (line 280) | func (s *defaultScale) Ranger(r Ranger) Ranger {
method RangeType (line 292) | func (s *defaultScale) RangeType() reflect.Type {
method Map (line 299) | func (s *defaultScale) Map(x interface{}) interface{} {
method Ticks (line 303) | func (s *defaultScale) Ticks(max int, pred func(major, minor table.Sli...
method SetFormatter (line 307) | func (s *defaultScale) SetFormatter(f interface{}) {
method CloneScaler (line 315) | func (s *defaultScale) CloneScaler() Scaler {
function DefaultScale (line 322) | func DefaultScale(seq table.Slice) (Scaler, error) {
function defaultRanger (line 364) | func defaultRanger(aes string) Ranger {
function NewIdentityScale (line 388) | func NewIdentityScale() Scaler {
type identityScale (line 392) | type identityScale struct
method ExpandDomain (line 396) | func (s *identityScale) ExpandDomain(v table.Slice) {
method RangeType (line 400) | func (s *identityScale) RangeType() reflect.Type {
method Ranger (line 404) | func (s *identityScale) Ranger(r Ranger) Ranger { return nil }
method Map (line 405) | func (s *identityScale) Map(x interface{}) interface{} { return x }
method Ticks (line 407) | func (s *identityScale) Ticks(max int, pred func(major, minor table.Sl...
method SetFormatter (line 411) | func (s *identityScale) SetFormatter(f interface{}) {}
method CloneScaler (line 413) | func (s *identityScale) CloneScaler() Scaler {
function NewLinearScaler (line 424) | func NewLinearScaler() ContinuousScaler {
function NewLogScaler (line 434) | func NewLogScaler(base int) ContinuousScaler {
type moremathScale (line 444) | type moremathScale struct
method String (line 454) | func (s *moremathScale) String() string {
method ExpandDomain (line 461) | func (s *moremathScale) ExpandDomain(vs table.Slice) {
method SetMin (line 483) | func (s *moremathScale) SetMin(v interface{}) ContinuousScaler {
method SetMax (line 493) | func (s *moremathScale) SetMax(v interface{}) ContinuousScaler {
method Include (line 503) | func (s *moremathScale) Include(v interface{}) ContinuousScaler {
method get (line 525) | func (s *moremathScale) get() tickMapper {
method Ranger (line 553) | func (s *moremathScale) Ranger(r Ranger) Ranger {
method RangeType (line 561) | func (s *moremathScale) RangeType() reflect.Type {
method Map (line 565) | func (s *moremathScale) Map(x interface{}) interface{} {
method Ticks (line 598) | func (s *moremathScale) Ticks(max int, pred func(major, minor table.Sl...
method SetFormatter (line 691) | func (s *moremathScale) SetFormatter(f interface{}) {
method CloneScaler (line 695) | func (s *moremathScale) CloneScaler() Scaler {
type tickMapper (line 520) | type tickMapper interface
function NewTimeScaler (line 702) | func NewTimeScaler() *timeScale {
type timeScale (line 706) | type timeScale struct
method String (line 713) | func (s *timeScale) String() string {
method ExpandDomain (line 717) | func (s *timeScale) ExpandDomain(vs table.Slice) {
method SetMin (line 732) | func (s *timeScale) SetMin(v interface{}) ContinuousScaler {
method SetMax (line 737) | func (s *timeScale) SetMax(v interface{}) ContinuousScaler {
method Include (line 742) | func (s *timeScale) Include(v interface{}) ContinuousScaler {
method Ranger (line 757) | func (s *timeScale) Ranger(r Ranger) Ranger {
method RangeType (line 765) | func (s *timeScale) RangeType() reflect.Type {
method getMinMax (line 769) | func (s *timeScale) getMinMax() (time.Time, time.Time) {
method Map (line 781) | func (s *timeScale) Map(x interface{}) interface{} {
method Ticks (line 956) | func (s *timeScale) Ticks(maxTicks int, pred func(major, minor table.S...
method SetFormatter (line 998) | func (s *timeScale) SetFormatter(f interface{}) {
method CloneScaler (line 1002) | func (s *timeScale) CloneScaler() Scaler {
type durationTicks (line 806) | type durationTicks
method Next (line 808) | func (d durationTicks) Next(t time.Time) time.Time {
type timeTicker (line 863) | type timeTicker struct
method getNextTick (line 867) | func (t *timeTicker) getNextTick(level int) func(time.Time) time.Time {
method CountTicks (line 885) | func (t *timeTicker) CountTicks(level int) int {
method TicksAtLevel (line 896) | func (t *timeTicker) TicksAtLevel(level int) interface{} {
method GuessLevel (line 905) | func (t *timeTicker) GuessLevel() int {
method MaxLevel (line 915) | func (timeTicker) MaxLevel() int {
method Label (line 919) | func (timeTicker) Label(cur, prev time.Time, level int) string {
function NewOrdinalScale (line 1013) | func NewOrdinalScale() Scaler {
type ordinalScale (line 1017) | type ordinalScale struct
method ExpandDomain (line 1025) | func (s *ordinalScale) ExpandDomain(v table.Slice) {
method Ranger (line 1034) | func (s *ordinalScale) Ranger(r Ranger) Ranger {
method RangeType (line 1042) | func (s *ordinalScale) RangeType() reflect.Type {
method makeIndex (line 1046) | func (s *ordinalScale) makeIndex() {
method Map (line 1061) | func (s *ordinalScale) Map(x interface{}) interface{} {
method Ticks (line 1096) | func (s *ordinalScale) Ticks(max int, pred func(major, minor table.Sli...
method SetFormatter (line 1126) | func (s *ordinalScale) SetFormatter(f interface{}) {
method CloneScaler (line 1130) | func (s *ordinalScale) CloneScaler() Scaler {
type Ranger (line 1144) | type Ranger interface
type ContinuousRanger (line 1148) | type ContinuousRanger interface
type DiscreteRanger (line 1154) | type DiscreteRanger interface
function NewFloatRanger (line 1160) | func NewFloatRanger(lo, hi float64) ContinuousRanger {
type floatRanger (line 1164) | type floatRanger struct
method String (line 1168) | func (r *floatRanger) String() string {
method RangeType (line 1172) | func (r *floatRanger) RangeType() reflect.Type {
method Map (line 1176) | func (r *floatRanger) Map(x float64) interface{} {
method Unmap (line 1180) | func (r *floatRanger) Unmap(y interface{}) (float64, bool) {
function NewColorRanger (line 1190) | func NewColorRanger(palette []color.Color) DiscreteRanger {
type colorRanger (line 1198) | type colorRanger struct
method RangeType (line 1202) | func (r *colorRanger) RangeType() reflect.Type {
method Levels (line 1206) | func (r *colorRanger) Levels() (min, max int) {
method MapLevel (line 1210) | func (r *colorRanger) MapLevel(i, j int) interface{} {
type defaultColorRanger (line 1221) | type defaultColorRanger struct
method RangeType (line 1233) | func (r *defaultColorRanger) RangeType() reflect.Type {
method Map (line 1237) | func (r *defaultColorRanger) Map(x float64) interface{} {
method Unmap (line 1241) | func (r *defaultColorRanger) Unmap(y interface{}) (float64, bool) {
method Levels (line 1251) | func (r *defaultColorRanger) Levels() (min, max int) {
method MapLevel (line 1255) | func (r *defaultColorRanger) MapLevel(i, j int) interface{} {
function mapMany (line 1268) | func mapMany(scaler Scaler, seq table.Slice) table.Slice {
FILE: benchplot/vendor/github.com/aclements/go-gg/gg/stepmode_string.go
constant _StepMode_name (line 7) | _StepMode_name = "StepHVStepVHStepHMidStepVMid"
method String (line 11) | func (i StepMode) String() string {
FILE: benchplot/vendor/github.com/aclements/go-gg/gg/testmain.go
function main (line 20) | func main() {
FILE: benchplot/vendor/github.com/aclements/go-gg/gg/text.go
type textMetrics (line 9) | type textMetrics struct
function measureString (line 19) | func measureString(pxSize float64, s string) textMetrics {
FILE: benchplot/vendor/github.com/aclements/go-gg/gg/transform.go
method SortBy (line 17) | func (p *Plot) SortBy(cols ...string) *Plot {
FILE: benchplot/vendor/github.com/aclements/go-gg/ggstat/agg.go
function Agg (line 24) | func Agg(xs ...string) func(aggs ...Aggregator) Aggregate {
type Aggregate (line 40) | type Aggregate struct
method F (line 55) | func (s Aggregate) F(g table.Grouping) table.Grouping {
type Aggregator (line 53) | type Aggregator
function checkConst (line 123) | func checkConst(t *table.Table, col string) bool {
function AggCount (line 146) | func AggCount(label string) Aggregator {
function AggMean (line 163) | func AggMean(cols ...string) Aggregator {
function AggGeoMean (line 170) | func AggGeoMean(cols ...string) Aggregator {
function AggMin (line 177) | func AggMin(cols ...string) Aggregator {
function AggMax (line 188) | func AggMax(cols ...string) Aggregator {
function AggSum (line 199) | func AggSum(cols ...string) Aggregator {
function AggQuantile (line 207) | func AggQuantile(prefix string, quantile float64, cols ...string) Aggreg...
function aggFn (line 218) | func aggFn(f func([]float64) float64, prefix string, cols ...string) Agg...
function AggUnique (line 256) | func AggUnique(cols ...string) Aggregator {
FILE: benchplot/vendor/github.com/aclements/go-gg/ggstat/bin.go
type Bin (line 40) | type Bin struct
method F (line 74) | func (b Bin) F(g table.Grouping) table.Grouping {
method computeBreaks (line 125) | func (b Bin) computeBreaks(g table.Grouping) reflect.Value {
FILE: benchplot/vendor/github.com/aclements/go-gg/ggstat/density.go
type Density (line 30) | type Density struct
method F (line 79) | func (d Density) F(g table.Grouping) table.Grouping {
FILE: benchplot/vendor/github.com/aclements/go-gg/ggstat/domain.go
type FunctionDomainer (line 17) | type FunctionDomainer interface
type DomainFixed (line 32) | type DomainFixed struct
method FunctionDomain (line 38) | func (r DomainFixed) FunctionDomain(g table.Grouping, col string) func...
type DomainData (line 46) | type DomainData struct
method FunctionDomain (line 68) | func (r DomainData) FunctionDomain(g table.Grouping, col string) func(...
constant defaultWiden (line 66) | defaultWiden = 1.1
FILE: benchplot/vendor/github.com/aclements/go-gg/ggstat/ecdf.go
type ECDF (line 32) | type ECDF struct
method F (line 53) | func (s ECDF) F(g table.Grouping) table.Grouping {
FILE: benchplot/vendor/github.com/aclements/go-gg/ggstat/fn.go
type Function (line 22) | type Function struct
method F (line 45) | func (f Function) F(g table.Grouping) table.Grouping {
constant defaultFunctionSamples (line 43) | defaultFunctionSamples = 200
function preserveConsts (line 113) | func preserveConsts(nt *table.Builder, t *table.Table) {
FILE: benchplot/vendor/github.com/aclements/go-gg/ggstat/loess.go
type LOESS (line 30) | type LOESS struct
method F (line 53) | func (s LOESS) F(g table.Grouping) table.Grouping {
FILE: benchplot/vendor/github.com/aclements/go-gg/ggstat/lsquares.go
type LeastSquares (line 28) | type LeastSquares struct
method F (line 46) | func (s LeastSquares) F(g table.Grouping) table.Grouping {
FILE: benchplot/vendor/github.com/aclements/go-gg/ggstat/normalize.go
type Normalize (line 23) | type Normalize struct
method F (line 53) | func (s Normalize) F(g table.Grouping) table.Grouping {
function colTypes (line 121) | func colTypes(g table.Grouping) []reflect.Type {
function canNormalize (line 145) | func canNormalize(k reflect.Kind) bool {
function denomValue (line 149) | func denomValue(s interface{}, index int) float64 {
function normalizeTo (line 157) | func normalizeTo(s interface{}, denom float64) interface{} {
FILE: benchplot/vendor/github.com/aclements/go-gg/palette/blend.go
function blendRGBA (line 11) | func blendRGBA(a, b color.RGBA, x float64) color.RGBA {
FILE: benchplot/vendor/github.com/aclements/go-gg/palette/brewer/genbrewer.go
function main (line 22) | func main() {
function parse (line 118) | func parse(cssColor string) (r, g, b uint8) {
function sortedKeys (line 133) | func sortedKeys(m interface{}) []string {
FILE: benchplot/vendor/github.com/aclements/go-gg/palette/makesrgbtab.go
function sRGBToLinear (line 16) | func sRGBToLinear(s float64) float64 {
function linearTosRGB (line 24) | func linearTosRGB(x float64) float64 {
function main (line 32) | func main() {
FILE: benchplot/vendor/github.com/aclements/go-gg/palette/palette.go
type Continuous (line 21) | type Continuous interface
type RGBGradient (line 27) | type RGBGradient struct
method Map (line 39) | func (g RGBGradient) Map(x float64) color.Color {
FILE: benchplot/vendor/github.com/aclements/go-gg/palette/srgb.go
function sRGB8ToLinear (line 11) | func sRGB8ToLinear(x uint8) uint16 {
function linearTosRGB8 (line 17) | func linearTosRGB8(x uint16) uint8 {
FILE: benchplot/vendor/github.com/aclements/go-gg/palette/srgbtab.go
constant linearTosRGBShift (line 264) | linearTosRGBShift = 4
constant linearTosRGBAddend (line 266) | linearTosRGBAddend = 0
FILE: benchplot/vendor/github.com/aclements/go-gg/palette/viridis.go
function init (line 18) | func init() {
FILE: benchplot/vendor/github.com/aclements/go-gg/table/concat.go
function Concat (line 18) | func Concat(gs ...Grouping) Grouping {
FILE: benchplot/vendor/github.com/aclements/go-gg/table/filter.go
function Filter (line 21) | func Filter(g Grouping, pred interface{}, cols ...string) Grouping {
function FilterEq (line 75) | func FilterEq(g Grouping, col string, val interface{}) Grouping {
FILE: benchplot/vendor/github.com/aclements/go-gg/table/group.go
type GroupID (line 17) | type GroupID struct
method String (line 33) | func (g GroupID) String() string {
method Extend (line 53) | func (g GroupID) Extend(label interface{}) GroupID {
method Parent (line 59) | func (g GroupID) Parent() GroupID {
method Label (line 67) | func (g GroupID) Label() interface{} {
type groupNode (line 24) | type groupNode struct
function GroupBy (line 76) | func GroupBy(g Grouping, cols ...string) Grouping {
function Ungroup (line 172) | func Ungroup(g Grouping) Grouping {
function Flatten (line 199) | func Flatten(g Grouping) *Table {
function concatRows (line 219) | func concatRows(tabs ...*Table) *Table {
FILE: benchplot/vendor/github.com/aclements/go-gg/table/head.go
function Head (line 10) | func Head(g Grouping, n int) Grouping {
function Tail (line 15) | func Tail(g Grouping, n int) Grouping {
function headTail (line 19) | func headTail(g Grouping, n int, tail bool) Grouping {
function HeadTables (line 45) | func HeadTables(g Grouping, n int) Grouping {
function TailTables (line 50) | func TailTables(g Grouping, n int) Grouping {
function headTailTables (line 54) | func headTailTables(g Grouping, n int, tail bool) Grouping {
FILE: benchplot/vendor/github.com/aclements/go-gg/table/join.go
function Join (line 19) | func Join(g1 Grouping, col1 string, g2 Grouping, col2 string) Grouping {
FILE: benchplot/vendor/github.com/aclements/go-gg/table/map.go
function MapTables (line 17) | func MapTables(g Grouping, f func(gid GroupID, table *Table) *Table) Gro...
function MapCols (line 38) | func MapCols(g Grouping, f interface{}, incols ...string) func(outcols ....
function Rename (line 129) | func Rename(g Grouping, from, to string) Grouping {
function Remove (line 154) | func Remove(g Grouping, col string) Grouping {
FILE: benchplot/vendor/github.com/aclements/go-gg/table/new.go
function TableFromStructs (line 16) | func TableFromStructs(structs Slice) *Table {
function TableFromStrings (line 55) | func TableFromStrings(cols []string, rows [][]string, coerce bool) *Table {
FILE: benchplot/vendor/github.com/aclements/go-gg/table/new_test.go
function ExampleTableFromStructs (line 13) | func ExampleTableFromStructs() {
function TestTableFromStructs (line 27) | func TestTableFromStructs(t *testing.T) {
function TestTableFromStructsEmbedded (line 37) | func TestTableFromStructsEmbedded(t *testing.T) {
function TestTableFromStructsUnexported (line 51) | func TestTableFromStructsUnexported(t *testing.T) {
function TestTableFromStructsEmbeddedUnexported (line 63) | func TestTableFromStructsEmbeddedUnexported(t *testing.T) {
function ExampleTableFromStrings (line 79) | func ExampleTableFromStrings() {
function TestTableFromStrings (line 93) | func TestTableFromStrings(t *testing.T) {
FILE: benchplot/vendor/github.com/aclements/go-gg/table/pivot.go
function Pivot (line 22) | func Pivot(g Grouping, label, value string) Grouping {
function Unpivot (line 97) | func Unpivot(g Grouping, label, value string, cols ...string) Grouping {
FILE: benchplot/vendor/github.com/aclements/go-gg/table/pivot_test.go
function ExampleUnpivot (line 19) | func ExampleUnpivot() {
function ExamplePivot (line 42) | func ExamplePivot() {
function TestUnpivot (line 63) | func TestUnpivot(t *testing.T) {
FILE: benchplot/vendor/github.com/aclements/go-gg/table/print.go
function Print (line 21) | func Print(g Grouping, formats ...string) error {
function Fprint (line 30) | func Fprint(w io.Writer, g Grouping, formats ...string) error {
FILE: benchplot/vendor/github.com/aclements/go-gg/table/print_test.go
function groupString (line 13) | func groupString(g Grouping) string {
function ExampleFprint (line 19) | func ExampleFprint() {
function ExampleFprint_Formats (line 32) | func ExampleFprint_Formats() {
function ExampleFprint_Groups (line 45) | func ExampleFprint_Groups() {
function TestFprintEmpty (line 62) | func TestFprintEmpty(t *testing.T) {
FILE: benchplot/vendor/github.com/aclements/go-gg/table/sort.go
function SortBy (line 21) | func SortBy(g Grouping, cols ...string) Grouping {
type permSort (line 69) | type permSort struct
method Len (line 74) | func (s *permSort) Len() int {
method Less (line 78) | func (s *permSort) Less(i, j int) bool {
method Swap (line 91) | func (s *permSort) Swap(i, j int) {
FILE: benchplot/vendor/github.com/aclements/go-gg/table/table.go
type Table (line 57) | type Table struct
method Len (line 263) | func (t *Table) Len() int {
method Columns (line 269) | func (t *Table) Columns() []string {
method Column (line 277) | func (t *Table) Column(name string) Slice {
method MustColumn (line 295) | func (t *Table) MustColumn(name string) Slice {
method Const (line 305) | func (t *Table) Const(name string) (val interface{}, ok bool) {
method isEmpty (line 312) | func (t *Table) isEmpty() bool {
method Tables (line 318) | func (t *Table) Tables() []GroupID {
method Table (line 327) | func (t *Table) Table(gid GroupID) *Table {
type Builder (line 67) | type Builder struct
method Add (line 160) | func (b *Builder) Add(name string, data Slice) *Builder {
method AddConst (line 219) | func (b *Builder) AddConst(name string, val interface{}) *Builder {
method Has (line 242) | func (b *Builder) Has(name string) bool {
method Done (line 253) | func (b *Builder) Done() *Table {
type Grouping (line 89) | type Grouping interface
type GroupingBuilder (line 109) | type GroupingBuilder struct
method Add (line 375) | func (b *GroupingBuilder) Add(gid GroupID, t *Table) *GroupingBuilder {
method Done (line 452) | func (b *GroupingBuilder) Done() Grouping {
type groupedTable (line 114) | type groupedTable struct
method Columns (line 461) | func (g *groupedTable) Columns() []string {
method Tables (line 465) | func (g *groupedTable) Tables() []GroupID {
method Table (line 469) | func (g *groupedTable) Table(gid GroupID) *Table {
type Slice (line 125) | type Slice interface
function reflectSlice (line 127) | func reflectSlice(s Slice) reflect.Value {
function NewBuilder (line 137) | func NewBuilder(t *Table) *Builder {
function NewGroupingBuilder (line 336) | func NewGroupingBuilder(g Grouping) *GroupingBuilder {
function colTypes (line 355) | func colTypes(t *Table) []reflect.Type {
function ColType (line 479) | func ColType(g Grouping, col string) reflect.Type {
FILE: benchplot/vendor/github.com/aclements/go-gg/table/table_test.go
function isEmpty (line 17) | func isEmpty(g Grouping) bool {
function de (line 24) | func de(x, y interface{}) bool {
function equal (line 28) | func equal(g1, g2 Grouping) bool {
function shouldPanic (line 43) | func shouldPanic(t *testing.T, re string, f func()) {
function TestEmptyTable (line 56) | func TestEmptyTable(t *testing.T) {
function TestBuilder (line 84) | func TestBuilder(t *testing.T) {
function TestTable0 (line 114) | func TestTable0(t *testing.T) {
function TestTable1 (line 149) | func TestTable1(t *testing.T) {
function TestGroupingBuilder (line 184) | func TestGroupingBuilder(t *testing.T) {
function TestColumnOrder (line 263) | func TestColumnOrder(t *testing.T) {
function TestGroupOrder (line 284) | func TestGroupOrder(t *testing.T) {
FILE: benchplot/vendor/github.com/aclements/go-moremath/cmd/dist/dist.go
function main (line 37) | func main() {
function readInput (line 69) | func readInput(r io.Reader) (sample stats.Sample) {
FILE: benchplot/vendor/github.com/aclements/go-moremath/cmd/dist/plot.go
constant printSamples (line 21) | printSamples = 500
constant printWidth (line 24) | printWidth = 70 * 2
constant printHeight (line 26) | printHeight = 3 * 4
constant printXMargin (line 28) | printXMargin = 1
constant printYMargin (line 29) | printYMargin = 1
function FprintPDF (line 36) | func FprintPDF(w io.Writer, dists ...stats.Dist) error {
function FprintCDF (line 48) | func FprintCDF(w io.Writer, dists ...stats.Dist) error {
function makeScale (line 59) | func makeScale(x1, x2 float64, y1, y2 int) scale.QQ {
function commonScale (line 66) | func commonScale(dist ...stats.Dist) (xscale scale.QQ, xs []float64) {
function fprintScale (line 84) | func fprintScale(w io.Writer, sc scale.QQ) error {
function fprintFn (line 124) | func fprintFn(w io.Writer, fn func(float64) float64, xscale scale.QQ, xs...
function fprintImage (line 157) | func fprintImage(w io.Writer, img [][]bool, trail []string) error {
function maxint (line 199) | func maxint(a, b int) int {
function minint (line 206) | func minint(a, b int) int {
FILE: benchplot/vendor/github.com/aclements/go-moremath/fit/loess.go
function LOESS (line 36) | func LOESS(xs, ys []float64, degree int, span float64) func(x float64) f...
type pairSlice (line 99) | type pairSlice struct
method Len (line 103) | func (s *pairSlice) Len() int {
method Less (line 107) | func (s *pairSlice) Less(i, j int) bool {
method Swap (line 111) | func (s *pairSlice) Swap(i, j int) {
FILE: benchplot/vendor/github.com/aclements/go-moremath/fit/loess_test.go
function TestLOESS_NIST (line 13) | func TestLOESS_NIST(t *testing.T) {
FILE: benchplot/vendor/github.com/aclements/go-moremath/fit/lsquares.go
function LinearLeastSquares (line 36) | func LinearLeastSquares(xs, ys, weights []float64, terms ...func(xs, ter...
type PolynomialRegressionResult (line 103) | type PolynomialRegressionResult struct
method String (line 112) | func (r PolynomialRegressionResult) String() string {
function PolynomialRegression (line 135) | func PolynomialRegression(xs, ys, weights []float64, degree int) Polynom...
FILE: benchplot/vendor/github.com/aclements/go-moremath/internal/mathtest/mathtest.go
function SetAeqDigits (line 20) | func SetAeqDigits(digits int) int {
function init (line 27) | func init() {
function Aeq (line 34) | func Aeq(expect, got float64) bool {
function WantFunc (line 41) | func WantFunc(t *testing.T, name string, f func(float64) float64, vals m...
FILE: benchplot/vendor/github.com/aclements/go-moremath/mathx/beta.go
function lgamma (line 9) | func lgamma(x float64) float64 {
function Beta (line 15) | func Beta(a, b float64) float64 {
function BetaInc (line 27) | func BetaInc(x, a, b float64) float64 {
function betacf (line 58) | func betacf(x, a, b float64) float64 {
FILE: benchplot/vendor/github.com/aclements/go-moremath/mathx/beta_test.go
function TestBetaInc (line 13) | func TestBetaInc(t *testing.T) {
FILE: benchplot/vendor/github.com/aclements/go-moremath/mathx/choose.go
constant smallFactLimit (line 9) | smallFactLimit = 20
function init (line 12) | func init() {
function Choose (line 22) | func Choose(n, k int) float64 {
function Lchoose (line 47) | func Lchoose(n, k int) float64 {
function lchoose (line 57) | func lchoose(n, k int) float64 {
FILE: benchplot/vendor/github.com/aclements/go-moremath/mathx/gamma.go
function GammaInc (line 13) | func GammaInc(a, x float64) float64 {
function GammaIncComp (line 33) | func GammaIncComp(a, x float64) float64 {
function gammaIncSeries (line 45) | func gammaIncSeries(a, x float64) float64 {
function gammaIncCF (line 67) | func gammaIncCF(a, x float64) float64 {
FILE: benchplot/vendor/github.com/aclements/go-moremath/mathx/gamma_test.go
function TestGammaInc (line 13) | func TestGammaInc(t *testing.T) {
FILE: benchplot/vendor/github.com/aclements/go-moremath/mathx/sign.go
function Sign (line 9) | func Sign(x float64) float64 {
FILE: benchplot/vendor/github.com/aclements/go-moremath/scale/err.go
type RangeErr (line 9) | type RangeErr
method Error (line 11) | func (r RangeErr) Error() string {
FILE: benchplot/vendor/github.com/aclements/go-moremath/scale/interface.go
type Quantitative (line 9) | type Quantitative interface
type QQ (line 43) | type QQ struct
method Map (line 49) | func (q QQ) Map(x float64) float64 {
method Unmap (line 55) | func (q QQ) Unmap(x float64) float64 {
FILE: benchplot/vendor/github.com/aclements/go-moremath/scale/linear.go
type Linear (line 13) | type Linear struct
method Map (line 33) | func (s Linear) Map(x float64) float64 {
method Unmap (line 44) | func (s Linear) Unmap(y float64) float64 {
method SetClamp (line 48) | func (s *Linear) SetClamp(clamp bool) {
method ebase (line 55) | func (s Linear) ebase() int {
method guessLevel (line 81) | func (s *Linear) guessLevel() int {
method spacingAtLevel (line 85) | func (s *Linear) spacingAtLevel(level int, roundOut bool) (firstN, las...
method CountTicks (line 110) | func (s Linear) CountTicks(level int) int {
method TicksAtLevel (line 116) | func (s Linear) TicksAtLevel(level int) interface{} {
method Ticks (line 136) | func (s Linear) Ticks(o TickOptions) (major, minor []float64) {
method Nice (line 152) | func (s *Linear) Nice(o TickOptions) {
type linearTicker (line 120) | type linearTicker struct
method CountTicks (line 125) | func (t linearTicker) CountTicks(level int) int {
method TicksAtLevel (line 130) | func (t linearTicker) TicksAtLevel(level int) interface{} {
FILE: benchplot/vendor/github.com/aclements/go-moremath/scale/linear_test.go
function TestLinear (line 15) | func TestLinear(t *testing.T) {
function ticksEq (line 65) | func ticksEq(major, wmajor, minor, wminor []float64) bool {
function TestLinearTicks (line 88) | func TestLinearTicks(t *testing.T) {
FILE: benchplot/vendor/github.com/aclements/go-moremath/scale/log.go
type Log (line 9) | type Log struct
method ebounds (line 51) | func (s *Log) ebounds() (bool, float64, float64) {
method Map (line 58) | func (s Log) Map(x float64) float64 {
method Unmap (line 81) | func (s Log) Unmap(y float64) float64 {
method SetClamp (line 94) | func (s *Log) SetClamp(clamp bool) {
method spacingAtLevel (line 111) | func (s *Log) spacingAtLevel(level int, roundOut bool) (firstN, lastN,...
method CountTicks (line 133) | func (s *Log) CountTicks(level int) int {
method TicksAtLevel (line 137) | func (s *Log) TicksAtLevel(level int) interface{} {
method Ticks (line 193) | func (s Log) Ticks(o TickOptions) (major, minor []float64) {
method Nice (line 208) | func (s *Log) Nice(o TickOptions) {
function NewLog (line 36) | func NewLog(min, max float64, base int) (Log, error) {
function logb (line 107) | func logb(x float64, b float64) float64 {
type logTicker (line 141) | type logTicker struct
method CountTicks (line 146) | func (t logTicker) CountTicks(level int) int {
method TicksAtLevel (line 156) | func (t logTicker) TicksAtLevel(level int) interface{} {
FILE: benchplot/vendor/github.com/aclements/go-moremath/scale/log_test.go
function TestLog (line 16) | func TestLog(t *testing.T) {
function TestLogTicks (line 108) | func TestLogTicks(t *testing.T) {
FILE: benchplot/vendor/github.com/aclements/go-moremath/scale/ticks.go
type TickOptions (line 15) | type TickOptions struct
method FindLevel (line 56) | func (o *TickOptions) FindLevel(ticker Ticker, guess int) (int, bool) {
type Ticker (line 30) | type Ticker interface
FILE: benchplot/vendor/github.com/aclements/go-moremath/scale/ticks_test.go
type testTicker (line 9) | type testTicker struct
method CountTicks (line 11) | func (testTicker) CountTicks(level int) int {
method TicksAtLevel (line 19) | func (t testTicker) TicksAtLevel(level int) interface{} {
function TestTicks (line 27) | func TestTicks(t *testing.T) {
FILE: benchplot/vendor/github.com/aclements/go-moremath/scale/util.go
function clamp (line 8) | func clamp(x float64) float64 {
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/alg.go
function maxint (line 15) | func maxint(a, b int) int {
function minint (line 22) | func minint(a, b int) int {
function sumint (line 29) | func sumint(xs []int) int {
function bisect (line 45) | func bisect(f func(float64) float64, low, high, tolerance float64) (floa...
function bisectBool (line 80) | func bisectBool(f func(float64) bool, low, high, xtol float64) (x1, x2 f...
function series (line 107) | func series(f func(float64) float64) float64 {
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/deltadist.go
type DeltaDist (line 12) | type DeltaDist struct
method PDF (line 16) | func (d DeltaDist) PDF(x float64) float64 {
method pdfEach (line 23) | func (d DeltaDist) pdfEach(xs []float64) []float64 {
method CDF (line 33) | func (d DeltaDist) CDF(x float64) float64 {
method cdfEach (line 40) | func (d DeltaDist) cdfEach(xs []float64) []float64 {
method InvCDF (line 48) | func (d DeltaDist) InvCDF(y float64) float64 {
method Bounds (line 55) | func (d DeltaDist) Bounds() (float64, float64) {
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/dist.go
type DistCommon (line 11) | type DistCommon interface
type Dist (line 43) | type Dist interface
type DiscreteDist (line 62) | type DiscreteDist interface
function InvCDF (line 109) | func InvCDF(dist DistCommon) func(y float64) (x float64) {
function Rand (line 189) | func Rand(dist DistCommon) func(*rand.Rand) float64 {
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/dist_test.go
type funnyCDF (line 12) | type funnyCDF struct
method CDF (line 16) | func (f funnyCDF) CDF(x float64) float64 {
method Bounds (line 31) | func (f funnyCDF) Bounds() (float64, float64) {
function TestInvCDF (line 35) | func TestInvCDF(t *testing.T) {
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/hist.go
type Histogram (line 11) | type Histogram interface
function HistogramQuantile (line 42) | func HistogramQuantile(hist Histogram, q float64) float64 {
function HistogramIQR (line 64) | func HistogramIQR(hist Histogram) float64 {
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/hypergdist.go
type HypergeometicDist (line 14) | type HypergeometicDist struct
method PMF (line 30) | func (d HypergeometicDist) PMF(k float64) float64 {
method pmf (line 39) | func (d HypergeometicDist) pmf(k int) float64 {
method CDF (line 46) | func (d HypergeometicDist) CDF(k float64) float64 {
method sum (line 69) | func (d HypergeometicDist) sum(k int) float64 {
method bounds (line 81) | func (d HypergeometicDist) bounds() (int, int) {
method Bounds (line 85) | func (d HypergeometicDist) Bounds() (float64, float64) {
method Step (line 90) | func (d HypergeometicDist) Step() float64 {
method Mean (line 94) | func (d HypergeometicDist) Mean() float64 {
method Variance (line 98) | func (d HypergeometicDist) Variance() float64 {
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/hypergdist_test.go
function TestHypergeometricDist (line 12) | func TestHypergeometricDist(t *testing.T) {
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/kde.go
type KDE (line 29) | type KDE struct
method prepare (line 141) | func (k *KDE) prepare() (kdeKernel, bool) {
method normalizedXs (line 173) | func (kde *KDE) normalizedXs(x float64) []float64 {
method PDF (line 181) | func (kde *KDE) PDF(x float64) float64 {
method CDF (line 223) | func (kde *KDE) CDF(x float64) float64 {
method Bounds (line 269) | func (kde *KDE) Bounds() (low float64, high float64) {
function BandwidthSilverman (line 64) | func BandwidthSilverman(data interface {
function BandwidthScott (line 78) | func BandwidthScott(data interface {
type KDEKernel (line 100) | type KDEKernel
constant EpanechnikovKernel (line 109) | EpanechnikovKernel KDEKernel = iota
constant GaussianKernel (line 112) | GaussianKernel
constant DeltaKernel (line 118) | DeltaKernel
type KDEBoundaryMethod (line 123) | type KDEBoundaryMethod
constant BoundaryReflect (line 133) | BoundaryReflect KDEBoundaryMethod = iota
type kdeKernel (line 136) | type kdeKernel interface
type epanechnikovKernel (line 322) | type epanechnikovKernel struct
method pdfEach (line 326) | func (d epanechnikovKernel) pdfEach(xs []float64) []float64 {
method cdfEach (line 338) | func (d epanechnikovKernel) cdfEach(xs []float64) []float64 {
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/kde_test.go
function TestKDEOneSample (line 12) | func TestKDEOneSample(t *testing.T) {
function TestKDETwoSamples (line 70) | func TestKDETwoSamples(t *testing.T) {
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/kdeboundarymethod_string.go
constant _KDEBoundaryMethod_name (line 7) | _KDEBoundaryMethod_name = "BoundaryReflect"
method String (line 11) | func (i KDEBoundaryMethod) String() string {
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/kdekernel_string.go
constant _KDEKernel_name (line 7) | _KDEKernel_name = "GaussianKernelDeltaKernel"
method String (line 11) | func (i KDEKernel) String() string {
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/linearhist.go
type LinearHist (line 8) | type LinearHist struct
method bin (line 21) | func (h *LinearHist) bin(x float64) int {
method Add (line 25) | func (h *LinearHist) Add(x float64) {
method Counts (line 36) | func (h *LinearHist) Counts() (uint, []uint, uint) {
method BinToValue (line 40) | func (h *LinearHist) BinToValue(bin float64) float64 {
function NewLinearHist (line 16) | func NewLinearHist(min, max float64, nbins int) *LinearHist {
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/locationhypothesis_string.go
constant _LocationHypothesis_name (line 7) | _LocationHypothesis_name = "LocationLessLocationDiffersLocationGreater"
method String (line 11) | func (i LocationHypothesis) String() string {
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/loghist.go
type LogHist (line 10) | type LogHist struct
method bin (line 29) | func (h *LogHist) bin(x float64) int {
method Add (line 33) | func (h *LogHist) Add(x float64) {
method Counts (line 44) | func (h *LogHist) Counts() (uint, []uint, uint) {
method BinToValue (line 48) | func (h *LogHist) BinToValue(bin float64) float64 {
method At (line 52) | func (h *LogHist) At(x float64) float64 {
method Bounds (line 60) | func (h *LogHist) Bounds() (float64, float64) {
function NewLogHist (line 20) | func NewLogHist(b int, m float64, max float64) *LogHist {
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/normaldist.go
type NormalDist (line 14) | type NormalDist struct
method PDF (line 24) | func (n NormalDist) PDF(x float64) float64 {
method pdfEach (line 29) | func (n NormalDist) pdfEach(xs []float64) []float64 {
method CDF (line 47) | func (n NormalDist) CDF(x float64) float64 {
method cdfEach (line 51) | func (n NormalDist) cdfEach(xs []float64) []float64 {
method InvCDF (line 60) | func (n NormalDist) InvCDF(p float64) (x float64) {
method Rand (line 128) | func (n NormalDist) Rand(r *rand.Rand) float64 {
method Bounds (line 138) | func (n NormalDist) Bounds() (float64, float64) {
constant invSqrt2Pi (line 22) | invSqrt2Pi = 0.398942280401432677939946059934381868475858631164934657665...
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/normaldist_test.go
function TestNormalDist (line 13) | func TestNormalDist(t *testing.T) {
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/sample.go
type Sample (line 15) | type Sample struct
method Bounds (line 51) | func (s Sample) Bounds() (min float64, max float64) {
method Sum (line 95) | func (s Sample) Sum() float64 {
method Weight (line 107) | func (s Sample) Weight() float64 {
method Mean (line 127) | func (s Sample) Mean() float64 {
method GeoMean (line 162) | func (s Sample) GeoMean() float64 {
method Variance (line 198) | func (s Sample) Variance() float64 {
method StdDev (line 212) | func (s Sample) StdDev() float64 {
method Quantile (line 232) | func (s Sample) Quantile(q float64) float64 {
method IQR (line 280) | func (s Sample) IQR() float64 {
method Sort (line 308) | func (s *Sample) Sort() *Sample {
method Copy (line 324) | func (s Sample) Copy() *Sample {
function Bounds (line 29) | func Bounds(xs []float64) (min float64, max float64) {
function Mean (line 115) | func Mean(xs []float64) float64 {
function GeoMean (line 145) | func GeoMean(xs []float64) float64 {
function Variance (line 178) | func Variance(xs []float64) float64 {
function StdDev (line 207) | func StdDev(xs []float64) float64 {
type sampleSorter (line 287) | type sampleSorter struct
method Len (line 292) | func (p *sampleSorter) Len() int {
method Less (line 296) | func (p *sampleSorter) Less(i, j int) bool {
method Swap (line 300) | func (p *sampleSorter) Swap(i, j int) {
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/sample_test.go
function TestSampleQuantile (line 9) | func TestSampleQuantile(t *testing.T) {
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/stream.go
type StreamStats (line 18) | type StreamStats struct
method Add (line 31) | func (s *StreamStats) Add(x float64) {
method Weight (line 55) | func (s *StreamStats) Weight() float64 {
method Mean (line 59) | func (s *StreamStats) Mean() float64 {
method Variance (line 63) | func (s *StreamStats) Variance() float64 {
method StdDev (line 67) | func (s *StreamStats) StdDev() float64 {
method RMS (line 71) | func (s *StreamStats) RMS() float64 {
method Combine (line 77) | func (s *StreamStats) Combine(o *StreamStats) {
method String (line 98) | func (s *StreamStats) String() string {
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/tdist.go
type TDist (line 14) | type TDist struct
method PDF (line 23) | func (t TDist) PDF(x float64) float64 {
method CDF (line 28) | func (t TDist) CDF(x float64) float64 {
method Bounds (line 40) | func (t TDist) Bounds() (float64, float64) {
function lgamma (line 18) | func lgamma(x float64) float64 {
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/tdist_test.go
function TestT (line 9) | func TestT(t *testing.T) {
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/ttest.go
type TTestResult (line 13) | type TTestResult struct
function newTTestResult (line 33) | func newTTestResult(n1, n2 int, t, dof float64, alt LocationHypothesis) ...
type TTestSample (line 49) | type TTestSample interface
function TwoSampleTTest (line 66) | func TwoSampleTTest(x1, x2 TTestSample, alt LocationHypothesis) (*TTestR...
function TwoSampleWelchTTest (line 85) | func TwoSampleWelchTTest(x1, x2 TTestSample, alt LocationHypothesis) (*T...
function PairedTTest (line 107) | func PairedTTest(x1, x2 []float64, μ0 float64, alt LocationHypothesis) (...
function OneSampleTTest (line 135) | func OneSampleTTest(x TTestSample, μ0 float64, alt LocationHypothesis) (...
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/ttest_test.go
function TestTTest (line 9) | func TestTTest(t *testing.T) {
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/udist.go
type UDist (line 29) | type UDist struct
method hasTies (line 40) | func (d UDist) hasTies() bool {
method p (line 54) | func (d UDist) p(U int) []float64 {
method PMF (line 325) | func (d UDist) PMF(U float64) float64 {
method CDF (line 347) | func (d UDist) CDF(U float64) float64 {
method Step (line 382) | func (d UDist) Step() float64 {
method Bounds (line 386) | func (d UDist) Bounds() (float64, float64) {
type ukey (line 149) | type ukey struct
function makeUmemo (line 167) | func makeUmemo(twoU, n1 int, t []int) []map[ukey]float64 {
function twoUmin (line 301) | func twoUmin(n1 int, t, a []int) int {
function twoUmax (line 313) | func twoUmax(n1 int, t, a []int) int {
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/udist_test.go
function aeqTable (line 15) | func aeqTable(a, b [][]float64) bool {
function TestUDist (line 55) | func TestUDist(t *testing.T) {
function BenchmarkUDist (line 95) | func BenchmarkUDist(b *testing.B) {
function TestUDistTies (line 103) | func TestUDistTies(t *testing.T) {
function BenchmarkUDistTies (line 213) | func BenchmarkUDistTies(b *testing.B) {
function XTestPrintUmemo (line 227) | func XTestPrintUmemo(t *testing.T) {
function udistRef (line 240) | func udistRef(n1 int, t []int) (pmf, cdf []float64) {
function printUmemo (line 316) | func printUmemo(A []map[ukey]float64, t []int) {
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/utest.go
type LocationHypothesis (line 18) | type LocationHypothesis
constant LocationLess (line 26) | LocationLess LocationHypothesis = -1
constant LocationDiffers (line 31) | LocationDiffers LocationHypothesis = 0
constant LocationGreater (line 36) | LocationGreater LocationHypothesis = 1
type MannWhitneyUTestResult (line 40) | type MannWhitneyUTestResult struct
function MannWhitneyUTest (line 127) | func MannWhitneyUTest(x1, x2 []float64, alt LocationHypothesis) (*MannWh...
function labeledMerge (line 238) | func labeledMerge(x1, x2 []float64) (merged []float64, labels []byte) {
function tieCorrection (line 270) | func tieCorrection(ties []int) float64 {
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/utest_test.go
function TestMannWhitneyUTest (line 9) | func TestMannWhitneyUTest(t *testing.T) {
FILE: benchplot/vendor/github.com/aclements/go-moremath/stats/util_test.go
function testDiscreteCDF (line 18) | func testDiscreteCDF(t *testing.T, name string, dist DiscreteDist) {
function testInvCDF (line 33) | func testInvCDF(t *testing.T, dist Dist, bounded bool) {
FILE: benchplot/vendor/github.com/aclements/go-moremath/vec/vec.go
function Vectorize (line 12) | func Vectorize(f func(float64) float64) func(xs []float64) []float64 {
function Map (line 21) | func Map(f func(float64) float64, xs []float64) []float64 {
function Linspace (line 32) | func Linspace(lo, hi float64, num int) []float64 {
function Logspace (line 46) | func Logspace(lo, hi float64, num int, base float64) []float64 {
function Sum (line 55) | func Sum(xs []float64) float64 {
function Concat (line 65) | func Concat(xss ...[]float64) []float64 {
FILE: buildstats/alg.go
function FilterInPlace (line 7) | func FilterInPlace[T any](xs []T, keep func(x T) bool) []T {
FILE: buildstats/main.go
type result (line 22) | type result
constant resNone (line 25) | resNone result = iota
constant resOK (line 26) | resOK
constant resFail (line 27) | resFail
function resultFromString (line 30) | func resultFromString(s string) result {
type grid (line 42) | type grid struct
method add (line 61) | func (g *grid) add(label string, rev *rev, result result) {
method sortedLabels (line 75) | func (g *grid) sortedLabels() []string {
method labelResults (line 88) | func (g *grid) labelResults(label string) []result {
type gridKey (line 48) | type gridKey struct
function newGrid (line 53) | func newGrid(revs []*rev) *grid {
type sum (line 96) | type sum struct
method add (line 101) | func (s *sum) add(r result) {
method failureRate (line 111) | func (s sum) failureRate() float64 {
method less (line 118) | func (s sum) less(s2 sum) bool {
function rangeBuildResults (line 125) | func rangeBuildResults(rev *rev, cb func(builder string, res result)) {
function main (line 131) | func main() {
function makeResults (line 161) | func makeResults(results []result) image.Image {
function pngURI (line 194) | func pngURI(img image.Image) []byte {
FILE: buildstats/rev.go
type rev (line 18) | type rev struct
method String (line 74) | func (r *rev) String() string {
method getLogPath (line 108) | func (r *rev) getLogPath(builder string) (string, error) {
method readLog (line 117) | func (r *rev) readLog(builder string) ([]byte, error) {
function getRevs (line 27) | func getRevs(since time.Time) []*rev {
type revMeta (line 78) | type revMeta struct
function readMeta (line 84) | func readMeta(revPath string) revMeta {
FILE: buildstats/timeflag.go
constant rfc3339Date (line 13) | rfc3339Date = "2006-01-02"
constant rfc3339DateTime (line 14) | rfc3339DateTime = "2006-01-02T15:04:05"
type timeFlag (line 21) | type timeFlag struct
method Set (line 27) | func (tf *timeFlag) Set(s string) error {
method String (line 43) | func (tf *timeFlag) String() string {
method Get (line 53) | func (tf *timeFlag) Get() interface{} {
FILE: cl-fetch/main.go
type Tag (line 32) | type Tag struct
function main (line 37) | func main() {
function git (line 165) | func git(args ...string) {
function gitOutput (line 179) | func gitOutput(args ...string) string {
function printChain (line 193) | func printChain(tags map[string]*Tag, commitID string, printed map[strin...
FILE: dashquery/compile.go
type compiler (line 16) | type compiler struct
method compile (line 24) | func (c *compiler) compile(expr string) (boolNode, error) {
method bad (line 51) | func (c *compiler) bad(ast ast.Node, format string, a ...interface{}) {
method bool (line 104) | func (c *compiler) bool(ast ast.Expr, n queryNode) boolNode {
method number (line 113) | func (c *compiler) number(ast ast.Expr, n queryNode) numberNode {
method oneOf (line 122) | func (c *compiler) oneOf(ast ast.Expr, x queryNode, typs ...string) {
method sameType (line 150) | func (c *compiler) sameType(ast *ast.BinaryExpr, x, y queryNode, typs ...
method expr (line 159) | func (c *compiler) expr(expr ast.Expr) queryNode {
function newCompiler (line 20) | func newCompiler(names map[string]queryNode) *compiler {
type compileError (line 56) | type compileError struct
method Error (line 61) | func (e *compileError) Error() string {
type queryNode (line 65) | type queryNode interface
type boolNode (line 74) | type boolNode
method typ (line 80) | func (boolNode) typ() string { return "bool" }
method cfunc (line 85) | func (n boolNode) cfunc() func(pathInfo) constant.Value {
type numberNode (line 75) | type numberNode
method typ (line 81) | func (numberNode) typ() string { return "number" }
method cfunc (line 90) | func (n numberNode) cfunc() func(pathInfo) constant.Value {
type stringNode (line 76) | type stringNode
method typ (line 82) | func (stringNode) typ() string { return "string" }
method cfunc (line 93) | func (n stringNode) cfunc() func(pathInfo) constant.Value {
type timeNode (line 77) | type timeNode
method typ (line 83) | func (timeNode) typ() string { return "time" }
method cfunc (line 98) | func (n timeNode) cfunc() func(pathInfo) constant.Value {
FILE: dashquery/compile_test.go
function TestEval (line 9) | func TestEval(t *testing.T) {
FILE: dashquery/main.go
function Compile (line 24) | func Compile(expr string) (*Query, error) {
function constNum (line 33) | func constNum(v int64) numberNode {
function startTime (line 42) | func startTime() time.Time {
type Query (line 100) | type Query struct
method AllPaths (line 151) | func (q *Query) AllPaths(fn func(string) error) error {
type pathInfo (line 104) | type pathInfo struct
method buildRev (line 110) | func (pi *pathInfo) buildRev() *types.BuildRevision {
function RevDir (line 126) | func RevDir() string {
function revs (line 131) | func revs() ([]string, error) {
FILE: dashquery/xdg.go
function xdgCacheDir (line 16) | func xdgCacheDir() string {
function xdgCreateDir (line 37) | func xdgCreateDir(path string) error {
FILE: findflakes/adtest.go
type SampleValueError (line 18) | type SampleValueError struct
method Error (line 23) | func (e *SampleValueError) Error() string {
type AndersonDarlingTestResult (line 27) | type AndersonDarlingTestResult struct
function AndersonDarlingTest (line 48) | func AndersonDarlingTest(sample []int, dist *GeometricDist) (*AndersonDa...
function andersonDarling (line 90) | func andersonDarling(sample []int, dist *GeometricDist) (float64, error) {
FILE: findflakes/flaketest.go
type FlakeTestResult (line 13) | type FlakeTestResult struct
method subdivide (line 65) | func (r *FlakeTestResult) subdivide(events []int) {
method Dump (line 139) | func (r *FlakeTestResult) Dump(w io.Writer) {
type FlakeRegion (line 17) | type FlakeRegion struct
method StillHappening (line 156) | func (r *FlakeRegion) StillHappening(t int) float64 {
method Bounds (line 168) | func (r *FlakeRegion) Bounds(p float64) (start, stop int) {
method StartedAtOrBefore (line 176) | func (r *FlakeRegion) StartedAtOrBefore(t int) float64 {
method StartedAt (line 184) | func (r *FlakeRegion) StartedAt(t int) float64 {
method Culprits (line 200) | func (r *FlakeRegion) Culprits(cumProb float64, limit int) []Culprit {
function FlakeTest (line 54) | func FlakeTest(failures []int) *FlakeTestResult {
function interarrivalAnalysis (line 109) | func interarrivalAnalysis(events []int) (mle *GeometricDist, ad *Anderso...
type Culprit (line 191) | type Culprit struct
FILE: findflakes/geodist.go
type GeometricDist (line 14) | type GeometricDist struct
method PMF (line 33) | func (d *GeometricDist) PMF(k int) float64 {
method CDF (line 40) | func (d *GeometricDist) CDF(k int) float64 {
method SF (line 47) | func (d *GeometricDist) SF(k int) float64 {
method InvCDF (line 54) | func (d *GeometricDist) InvCDF(y float64) int {
method Rand (line 58) | func (d *GeometricDist) Rand() int {
FILE: findflakes/html.go
constant htmlReport (line 16) | htmlReport = `
function printHTMLReport (line 219) | func printHTMLReport(w io.Writer, classes []*failureClass) {
FILE: findflakes/logs.go
type Revision (line 19) | type Revision struct
method String (line 28) | func (r *Revision) String() string {
method Subject (line 33) | func (r *Revision) Subject() string {
method OneLine (line 41) | func (r *Revision) OneLine() string {
type Build (line 45) | type Build struct
method LogPath (line 60) | func (b *Build) LogPath() string {
method ReadLog (line 64) | func (b *Build) ReadLog() ([]byte, error) {
type BuildStatus (line 52) | type BuildStatus
constant BuildOK (line 55) | BuildOK BuildStatus = iota
constant BuildRunning (line 56) | BuildRunning
constant BuildFailed (line 57) | BuildFailed
function LoadRevisions (line 71) | func LoadRevisions(revDir string) ([]*Revision, error) {
function readJSONFile (line 130) | func readJSONFile(path string, v interface{}) error {
FILE: findflakes/main.go
function defaultRevDir (line 34) | func defaultRevDir() string {
function main (line 87) | func main() {
function processFailureLogs (line 200) | func processFailureLogs(revs []*Revision, process func(build *Build, dat...
function extractFailures (line 261) | func extractFailures(revs []*Revision) []*failure {
function grepFailures (line 297) | func grepFailures(revs []*Revision, re *regexp.Regexp) []*failure {
type failure (line 306) | type failure struct
type failureClass (line 315) | type failureClass struct
function newFailureClass (line 340) | func newFailureClass(revs []*Revision, failures []*failure) *failureClass {
type currentSorter (line 358) | type currentSorter
method Len (line 360) | func (s currentSorter) Len() int {
method Less (line 364) | func (s currentSorter) Less(i, j int) bool {
method Swap (line 374) | func (s currentSorter) Swap(i, j int) {
FILE: findflakes/paths.go
function readPaths (line 14) | func readPaths(r io.Reader) ([]string, error) {
function pathFailures (line 26) | func pathFailures(revs []*Revision, paths []string) []*failure {
FILE: findflakes/text.go
function round (line 12) | func round(x float64) int {
function pct (line 16) | func pct(x float64) string {
function printTextReport (line 27) | func printTextReport(w io.Writer, classes []*failureClass) {
function printTextFlakeReport (line 35) | func printTextFlakeReport(w io.Writer, fc *failureClass) {
FILE: findflakes/xdg.go
function xdgCacheDir (line 16) | func xdgCacheDir() string {
function xdgCreateDir (line 37) | func xdgCreateDir(path string) error {
FILE: findtypes/main.go
constant ptrSize (line 30) | ptrSize = 8
function main (line 32) | func main() {
type typeInfo (line 140) | type typeInfo struct
method processType (line 147) | func (t *typeInfo) processType(typ dwarf.Type, offset int) {
type greyobjectFailure (line 215) | type greyobjectFailure struct
method compare (line 266) | func (f *greyobjectFailure) compare(ti *typeInfo) float64 {
method printCompare (line 287) | func (f *greyobjectFailure) printCompare(ti *typeInfo) {
function parseGreyobject (line 224) | func parseGreyobject(r io.Reader) *greyobjectFailure {
FILE: foreachplatform/main.go
type Platform (line 19) | type Platform struct
method String (line 83) | func (p Platform) String() string {
method Env (line 95) | func (p Platform) Env() []string {
method FailOK (line 110) | func (p Platform) FailOK(msg string) bool {
function main (line 27) | func main() {
function goTool (line 119) | func goTool[T any](subcmd ...string) T {
function getPlatforms (line 133) | func getPlatforms() []Platform {
function trueFalse (line 198) | func trueFalse(a, b bool) int {
function or (line 208) | func or[T comparable](vals ...T) T {
FILE: gc-S/main.go
function main (line 22) | func main() {
type Sym (line 74) | type Sym struct
method Print (line 118) | func (s Sym) Print(w io.Writer) {
method Refs (line 139) | func (s Sym) Refs() []string {
function parseSyms (line 79) | func parseSyms(r io.Reader) <-chan Sym {
FILE: gcdense/test.py
class Graph (line 11) | class Graph:
method __init__ (line 12) | def __init__(self, nnodes):
method pageOf (line 16) | def pageOf(self, node):
method bucketOf (line 19) | def bucketOf(self, node):
function addressGraph (line 26) | def addressGraph(g, density=0.7):
class TLB (line 35) | class TLB:
method __init__ (line 36) | def __init__(self):
method touch (line 40) | def touch(self, obj):
function genERGraph (line 51) | def genERGraph(n, p):
function genDeBruijn (line 66) | def genDeBruijn(degree, power):
function costLinear (line 75) | def costLinear(n):
function costSqrt (line 78) | def costSqrt(n):
function costAffine10 (line 81) | def costAffine10(n):
function argmax (line 91) | def argmax(iterable):
function pickFullest (line 94) | def pickFullest(buckets):
function pickEmptiest (line 97) | def pickEmptiest(buckets):
function pickRandom (line 104) | def pickRandom(buckets):
function pickFirst (line 108) | def pickFirst(buckets):
function pickQuantile (line 113) | def pickQuantile(quantile):
function pickAlternate10 (line 120) | def pickAlternate10(buckets):
function run (line 140) | def run(g, nroots, pick, cost):
function runGlobalQueue (line 182) | def runGlobalQueue(g, nroots):
function ecdf (line 207) | def ecdf(data):
function main (line 211) | def main():
function curve (line 227) | def curve():
FILE: git-p/gerrit.go
type GerritChangeInfo (line 21) | type GerritChangeInfo struct
type GerritChangeMessageInfo (line 44) | type GerritChangeMessageInfo struct
type GerritLabel (line 52) | type GerritLabel struct
type GerritAccount (line 61) | type GerritAccount struct
type GerritApproval (line 69) | type GerritApproval struct
type GerritRevision (line 76) | type GerritRevision struct
type Gerrit (line 81) | type Gerrit struct
method QueryChanges (line 158) | func (g *Gerrit) QueryChanges(query string, options ...string) *Gerrit...
method queryChanges (line 164) | func (g *Gerrit) queryChanges(queries []*GerritChanges) {
method queryChanges1 (line 180) | func (g *Gerrit) queryChanges1(queries []*GerritChanges, options []str...
function NewGerrit (line 87) | func NewGerrit(gerritUrl string) (*Gerrit, error) {
type GerritChanges (line 144) | type GerritChanges struct
method Wait (line 153) | func (req *GerritChanges) Wait() ([]*GerritChangeInfo, error) {
FILE: git-p/git.go
function git (line 18) | func git(args ...string) string {
function tryGit (line 32) | func tryGit(args ...string) (string, error) {
function lines (line 41) | func lines(s string) []string {
function upstreamOf (line 51) | func upstreamOf(ref string) string {
function gitPatchID (line 69) | func gitPatchID(commit string) (string, error) {
function gitCommitMessage (line 102) | func gitCommitMessage(commit string) (string, error) {
function canonGerritMessage (line 118) | func canonGerritMessage(msg string) string {
function changeIds (line 140) | func changeIds(project, forBranch string, commits []string) []string {
FILE: git-p/main.go
constant debugGerrit (line 74) | debugGerrit = false
function main (line 76) | func main() {
function showBranch (line 190) | func showBranch(gerrit *Gerrit, branch, extra string, remote string, ups...
function changeStatus (line 265) | func changeStatus(commit string, info *GerritChangeInfo) (status string,...
function printChange (line 401) | func printChange(commit string, change *GerritChanges, local bool) {
FILE: git-p/pager.go
function setupPager (line 23) | func setupPager() (inTerm bool) {
FILE: git-p/shell.go
function shellEscape (line 10) | func shellEscape(x string) string {
function shellEscapeList (line 25) | func shellEscapeList(xs []string) string {
FILE: go-weave/amb/det.go
type StrategyDFS (line 12) | type StrategyDFS struct
method Reset (line 22) | func (s *StrategyDFS) Reset() {
method maxDepth (line 28) | func (s *StrategyDFS) maxDepth() int {
method Amb (line 35) | func (s *StrategyDFS) Amb(n int) (int, bool) {
method Next (line 57) | func (s *StrategyDFS) Next() bool {
type ErrNondeterminism (line 79) | type ErrNondeterminism struct
method Error (line 83) | func (e *ErrNondeterminism) Error() string {
FILE: go-weave/amb/progress.go
constant resetLine (line 25) | resetLine = "\r\x1b[2K"
function startProgress (line 27) | func startProgress() {
function pipeFeeder (line 82) | func pipeFeeder(r, w, pstream *os.File) {
function stopProgress (line 110) | func stopProgress() {
FILE: go-weave/amb/rand.go
type StrategyRandom (line 12) | type StrategyRandom struct
method Reset (line 24) | func (s *StrategyRandom) Reset() {
method maxDepth (line 29) | func (s *StrategyRandom) maxDepth() int {
method Amb (line 36) | func (s *StrategyRandom) Amb(n int) (int, bool) {
method Next (line 44) | func (s *StrategyRandom) Next() bool {
FILE: go-weave/amb/run.go
type Strategy (line 18) | type Strategy interface
type Scheduler (line 51) | type Scheduler struct
method Run (line 64) | func (s *Scheduler) Run(root func()) {
method run1 (line 86) | func (s *Scheduler) run1(root func()) {
method Amb (line 113) | func (s *Scheduler) Amb(n int) int {
FILE: go-weave/models/cl20858.go
function mainOld (line 18) | func mainOld() {
function main (line 33) | func main() {
function runqput (line 64) | func runqput(g int) {
function runqget (line 86) | func runqget() int {
function runqemptyOld (line 112) | func runqemptyOld() bool {
function runqempty (line 122) | func runqempty() bool {
function runqemptyTest (line 138) | func runqemptyTest() bool {
FILE: go-weave/models/issue16083.go
type State (line 23) | type State struct
method worker (line 45) | func (s *State) worker() {
method gcDrain (line 72) | func (s *State) gcDrain() {
method gcMarkWorkAvailable (line 80) | func (s *State) gcMarkWorkAvailable() bool {
method gcMarkDone (line 84) | func (s *State) gcMarkDone() {
method gcMarkRootCheck (line 98) | func (s *State) gcMarkRootCheck() {
function main (line 34) | func main() {
FILE: go-weave/models/markterm.go
type State (line 21) | type State struct
method worker (line 38) | func (s *State) worker() {
method check (line 102) | func (s *State) check() {
function main (line 27) | func main() {
FILE: go-weave/models/maxtree.go
constant Depth (line 24) | Depth = 3
constant Degree (line 25) | Degree = 2
type Node (line 27) | type Node struct
method Reset (line 96) | func (n *Node) Reset() {
method Check (line 106) | func (n *Node) Check() int {
method Update (line 147) | func (n *Node) Update(val int) {
method set (line 170) | func (n *Node) set(slot, val int) (newMax int, changed bool) {
method max (line 180) | func (n *Node) max() int {
method maxNoSched (line 186) | func (n *Node) maxNoSched() int {
type State (line 38) | type State struct
method Init (line 71) | func (s *State) Init() (leaves []*Node) {
method Reset (line 92) | func (s *State) Reset() {
method worker (line 121) | func (s *State) worker(node *Node) {
function main (line 42) | func main() {
FILE: go-weave/models/rescan.go
constant writeMarks (line 25) | writeMarks = true
constant writeRestarts (line 29) | writeRestarts = false
type ptr (line 33) | type ptr
type obj (line 37) | type obj struct
constant numThreads (line 49) | numThreads = 2
constant stackBase (line 51) | stackBase ptr = 1
constant globalRoot (line 52) | globalRoot ptr = stackBase + ptr(numThreads)
constant verbose (line 57) | verbose = false
function main (line 61) | func main() {
function ambHeapPointer (line 118) | func ambHeapPointer() ptr {
function ambReachableHeapPointer (line 128) | func ambReachableHeapPointer() ptr {
function wbarrier (line 150) | func wbarrier(slot, val ptr) {
function mutator (line 179) | func mutator(id int) {
function mark (line 202) | func mark(p ptr, marked []bool, name string) {
function checkmark (line 222) | func checkmark(p ptr) {
function printMem (line 242) | func printMem(mem []obj, marked []bool) {
FILE: go-weave/models/rwmutex.go
constant verbose (line 18) | verbose = false
function main (line 20) | func main() {
function atomicXadd (line 41) | func atomicXadd(x *uint32, delta int32) uint32 {
function atomicLoad (line 48) | func atomicLoad(x *uint32) uint32 {
function lock (line 54) | func lock(m *weave.Mutex) {
function unlock (line 58) | func unlock(m *weave.Mutex) {
type m (line 62) | type m struct
type g (line 67) | type g struct
function notesleep (line 73) | func notesleep(s *weave.Semaphore) {
function notewakeup (line 77) | func notewakeup(s *weave.Semaphore) {
function noteclear (line 81) | func noteclear(s *weave.Semaphore) {
function getg (line 84) | func getg() *g {
type rwmutex (line 93) | type rwmutex struct
method rlock (line 132) | func (rw *rwmutex) rlock() {
method runlock (line 168) | func (rw *rwmutex) runlock() {
method lock (line 200) | func (rw *rwmutex) lock() {
method unlock (line 238) | func (rw *rwmutex) unlock() {
type muintptr (line 109) | type muintptr struct
method set (line 113) | func (mp *muintptr) set(x *m) {
method ptr (line 117) | func (mp *muintptr) ptr() *m {
function systemstack (line 121) | func systemstack(x func()) {
function throw (line 125) | func throw(x string) {
constant rwmutexMaxReaders (line 129) | rwmutexMaxReaders = 1 << 30
FILE: go-weave/models/yuasa.go
type barrierType (line 19) | type barrierType
constant yuasaBarrier (line 24) | yuasaBarrier barrierType = iota
constant dijkstraYuasaBarrier (line 29) | dijkstraYuasaBarrier
constant conditionalDijkstraYuasaBarrier (line 35) | conditionalDijkstraYuasaBarrier
constant dijkstraBarrier (line 40) | dijkstraBarrier
constant barrier (line 44) | barrier = conditionalDijkstraYuasaBarrier
constant stackBeforeHeap (line 48) | stackBeforeHeap = false
constant rescanStacks (line 52) | rescanStacks = false
type ptr (line 56) | type ptr
type obj (line 61) | type obj
constant numThreads (line 79) | numThreads = 2
constant stackBase (line 81) | stackBase ptr = 1
constant globalRoot (line 82) | globalRoot ptr = stackBase + numThreads
constant heapBase (line 83) | heapBase ptr = globalRoot + 1
constant heapCount (line 84) | heapCount = 3
constant verbose (line 92) | verbose = false
function main (line 96) | func main() {
type pointerSet (line 174) | type pointerSet
constant pointerNil (line 179) | pointerNil pointerSet = 1 << iota
constant pointerStack (line 183) | pointerStack
constant pointerReachable (line 187) | pointerReachable
constant pointerHeap (line 191) | pointerHeap
function ambPointer (line 197) | func ambPointer(ps pointerSet, tid int) ptr {
function ambHeapPointer (line 260) | func ambHeapPointer() ptr {
function scan (line 265) | func scan(obj ptr) {
function shade (line 283) | func shade(obj ptr) {
function drain (line 292) | func drain() {
function writePointer (line 305) | func writePointer(obj ptr, slot int, val ptr) {
function mutator (line 358) | func mutator(tid int) {
function mark (line 394) | func mark(p ptr, marked []bool) {
function checkmark (line 406) | func checkmark() {
function stringMem (line 421) | func stringMem(mem []obj, marked []bool) string {
FILE: go-weave/weave/atomic.go
type AtomicInt32 (line 7) | type AtomicInt32 struct
method Add (line 11) | func (a *AtomicInt32) Add(delta int32) (new int32) {
method CompareAndSwap (line 18) | func (a *AtomicInt32) CompareAndSwap(old, new int32) (swapped bool) {
method Load (line 27) | func (a *AtomicInt32) Load() int32 {
method Store (line 33) | func (a *AtomicInt32) Store(val int32) {
method Swap (line 38) | func (a *AtomicInt32) Swap(new int32) (old int32) {
FILE: go-weave/weave/mutex.go
type Mutex (line 9) | type Mutex struct
method Lock (line 14) | func (m *Mutex) Lock() {
method Unlock (line 24) | func (m *Mutex) Unlock() {
method reset (line 41) | func (m *Mutex) reset() {
type RWMutex (line 45) | type RWMutex struct
method Lock (line 50) | func (rw *RWMutex) Lock() {
method RLock (line 60) | func (rw *RWMutex) RLock() {
method reset (line 70) | func (rw *RWMutex) reset() {
method Unlock (line 74) | func (rw *RWMutex) Unlock() {
method RUnlock (line 79) | func (rw *RWMutex) RUnlock() {
method release (line 84) | func (rw *RWMutex) release() {
FILE: go-weave/weave/sema.go
type Semaphore (line 8) | type Semaphore struct
method Acquire (line 20) | func (s *Semaphore) Acquire(n int) {
method Release (line 36) | func (s *Semaphore) Release(n int) {
method reset (line 54) | func (s *Semaphore) reset() {
type semwait (line 14) | type semwait struct
FILE: go-weave/weave/tls.go
type TLS (line 7) | type TLS struct
method Get (line 15) | func (v *TLS) Get() interface{} {
method Set (line 19) | func (v *TLS) Set(val interface{}) {
function NewTLS (line 11) | func NewTLS() *TLS {
FILE: go-weave/weave/trace.go
type traceEntry (line 12) | type traceEntry struct
method Trace (line 17) | func (s *Scheduler) Trace(msg string) {
method Tracef (line 21) | func (s *Scheduler) Tracef(msg string, args ...interface{}) {
type errorWithTrace (line 25) | type errorWithTrace struct
method Error (line 30) | func (e errorWithTrace) Error() string {
FILE: go-weave/weave/waitgroup.go
type WaitGroup (line 7) | type WaitGroup struct
method Add (line 12) | func (g *WaitGroup) Add(delta int) {
method Done (line 23) | func (g *WaitGroup) Done() {
method Wait (line 27) | func (g *WaitGroup) Wait() {
method reset (line 37) | func (g *WaitGroup) reset() {
FILE: go-weave/weave/weave.go
type Scheduler (line 21) | type Scheduler struct
method newThread (line 61) | func (s *Scheduler) newThread() *thread {
method Run (line 71) | func (s *Scheduler) Run(main func()) {
method goNoSched (line 103) | func (s *Scheduler) goNoSched(f func()) {
method Go (line 156) | func (s *Scheduler) Go(f func()) {
method scheduler (line 165) | func (s *Scheduler) scheduler() {
method Sched (line 207) | func (s *Scheduler) Sched() {
method Amb (line 221) | func (s *Scheduler) Amb(n int) int {
type void (line 42) | type void struct
type thread (line 44) | type thread struct
method String (line 55) | func (t *thread) String() string {
method desched (line 213) | func (t *thread) desched() {
method block (line 225) | func (t *thread) block(abortf func()) {
method unblock (line 250) | func (t *thread) unblock() {
constant debug (line 59) | debug = false
FILE: goi/main.go
function main (line 22) | func main() {
function readLine (line 56) | func readLine(r io.Reader) (string, error) {
function transform (line 65) | func transform(src string) string {
function compile (line 109) | func compile(src string) string {
function run (line 159) | func run(so string) {
FILE: gover/cache.go
function resolveName (line 26) | func resolveName(name string) (path string, ok bool) {
type buildInfo (line 68) | type buildInfo struct
method fullName (line 76) | func (i buildInfo) fullName() string {
method shortName (line 83) | func (i buildInfo) shortName() string {
type listFlags (line 91) | type listFlags
constant listNames (line 94) | listNames listFlags = 1 << iota
constant listCommit (line 95) | listCommit
function listBuilds (line 98) | func listBuilds(flags listFlags) ([]*buildInfo, error) {
type commit (line 155) | type commit struct
function parseCommit (line 160) | func parseCommit(obj []byte) *commit {
FILE: gover/gover.go
function defaultVerDir (line 106) | func defaultVerDir() string {
function defaultGoroot (line 121) | func defaultGoroot() string {
function isGoroot (line 141) | func isGoroot(path string) bool {
function main (line 146) | func main() {
function goroot (line 286) | func goroot() string {
function gitCmd (line 293) | func gitCmd(cmd string, args ...string) string {
function getHash (line 304) | func getHash() (string, []byte) {
function doBuild (line 316) | func doBuild() {
function doSave (line 327) | func doSave(hash string, diff []byte) {
function doLink (line 369) | func doLink(hash, namePath string) {
type buildInfoSorter (line 376) | type buildInfoSorter
method Len (line 378) | func (s buildInfoSorter) Len() int {
method Less (line 382) | func (s buildInfoSorter) Less(i, j int) bool {
method Swap (line 386) | func (s buildInfoSorter) Swap(i, j int) {
function doList (line 390) | func doList() {
function doWith (line 413) | func doWith(name string, cmd []string) {
function doEnv (line 444) | func doEnv(name string) {
function getEnv (line 457) | func getEnv(savePath string) (goroot, path string) {
function doRemoveUnlabeled (line 470) | func doRemoveUnlabeled() {
function doGC (line 493) | func doGC() {
function cp (line 519) | func cp(src, dst string) {
function cpR (line 565) | func cpR(src, dst string) {
FILE: gover/shutil.go
function shellEscape (line 9) | func shellEscape(x string) string {
FILE: greplogs/main.go
function main (line 15) | func main() {
FILE: internal/loganal/classify.go
method canonicalMessage (line 23) | func (f *Failure) canonicalMessage() string {
method canonicalFields (line 41) | func (f *Failure) canonicalFields() []string {
function Classify (line 63) | func Classify(fs []*Failure) map[Failure][]int {
FILE: internal/loganal/failure.go
type Failure (line 16) | type Failure struct
method String (line 51) | func (f Failure) String() string {
type extractCache (line 170) | type extractCache struct
function init (line 176) | func init() {
function Extract (line 183) | func Extract(m string, os, arch string) ([]*Failure, error) {
function atoi (line 447) | func atoi(s string) int {
function firstLine (line 457) | func firstLine(s string) string {
function consumeTraceback (line 470) | func consumeTraceback(m *matcher) string {
function testFromTraceback (line 506) | func testFromTraceback(tb string) string {
function panicWhere (line 516) | func panicWhere(tb string) (fn string, file string, line int) {
FILE: internal/loganal/matcher.go
type matcher (line 14) | type matcher struct
method done (line 32) | func (m *matcher) done() bool {
method consume (line 39) | func (m *matcher) consume(r *regexp.Regexp) bool {
method peek (line 63) | func (m *matcher) peek(r *regexp.Regexp) bool {
method lineHasLiteral (line 69) | func (m *matcher) lineHasLiteral(literals ...string) bool {
method hasPrefix (line 102) | func (m *matcher) hasPrefix(s string) bool {
method line (line 108) | func (m *matcher) line() string {
method peekLine (line 123) | func (m *matcher) peekLine() (string, int) {
function newMatcher (line 28) | func newMatcher(str string) *matcher {
FILE: minutes3/gdoc.go
function getOAuthConfig (line 27) | func getOAuthConfig(scopes []string) *oauth2.Config {
type Doc (line 43) | type Doc struct
method FinishDoc (line 368) | func (d *Doc) FinishDoc(commentURLs map[int]string) {
type Issue (line 56) | type Issue struct
method URL (line 249) | func (di *Issue) URL() string {
method parseActions (line 338) | func (di *Issue) parseActions() (a action, err error) {
function parseDoc (line 75) | func parseDoc(docID string) *Doc {
type action (line 253) | type action struct
function parseSpreadsheetDate (line 471) | func parseSpreadsheetDate(cell *sheets.ExtendedValue) (time.Time, bool) {
type colMap (line 484) | type colMap
method col (line 496) | func (m colMap) col(name string) colIndex {
method getEV (line 504) | func (m colMap) getEV(row *sheets.RowData, name string) *sheets.Extend...
method getString (line 515) | func (m colMap) getString(row *sheets.RowData, name string) string {
method getterString (line 523) | func (m colMap) getterString(row *sheets.RowData) func(name string) st...
function newColMap (line 486) | func newColMap(row *sheets.RowData) colMap {
type colIndex (line 529) | type colIndex
type rowIndex (line 531) | type rowIndex
type coord (line 533) | type coord struct
method String (line 539) | func (c coord) String() string {
method Coord (line 543) | func (c coord) Coord() *sheets.GridCoordinate {
method To (line 557) | func (c coord) To(col colIndex, row rowIndex) *sheets.GridRange {
FILE: minutes3/gdoc_test.go
function TestParseActions (line 15) | func TestParseActions(t *testing.T) {
function diff (line 129) | func diff(t *testing.T, want, got string) {
FILE: minutes3/github.go
type GitHubClient (line 17) | type GitHubClient interface
type githubClient (line 44) | type githubClient struct
method CurrentUser (line 47) | func (c githubClient) CurrentUser() (string, error) {
method AddIssueComment (line 64) | func (c githubClient) AddIssueComment(issue *github.Issue, text string...
method CloseIssue (line 86) | func (c githubClient) CloseIssue(issue *github.Issue, reason schema.Is...
type GitHubLogger (line 100) | type GitHubLogger struct
method GraphQLQuery (line 107) | func (c *GitHubLogger) GraphQLQuery(query string, vars github.Vars) (*...
method GraphQLMutation (line 111) | func (c *GitHubLogger) GraphQLMutation(query string, vars github.Vars)...
method CurrentUser (line 116) | func (c *GitHubLogger) CurrentUser() (string, error) {
method SearchLabels (line 120) | func (c *GitHubLogger) SearchLabels(org string, repo string, query str...
method SearchMilestones (line 124) | func (c *GitHubLogger) SearchMilestones(org string, repo string, query...
method Issue (line 128) | func (c *GitHubLogger) Issue(org string, repo string, n int) (*github....
method IssueComments (line 132) | func (c *GitHubLogger) IssueComments(issue *github.Issue) ([]*github.I...
method AddIssueComment (line 136) | func (c *GitHubLogger) AddIssueComment(issue *github.Issue, text strin...
method AddIssueLabels (line 154) | func (c *GitHubLogger) AddIssueLabels(issue *github.Issue, labels ...*...
method RemoveIssueLabels (line 159) | func (c *GitHubLogger) RemoveIssueLabels(issue *github.Issue, labels ....
method CloseIssue (line 164) | func (c *GitHubLogger) CloseIssue(issue *github.Issue, reason schema.I...
method RetitleIssue (line 169) | func (c *GitHubLogger) RetitleIssue(issue *github.Issue, title string)...
method RemilestoneIssue (line 174) | func (c *GitHubLogger) RemilestoneIssue(issue *github.Issue, milestone...
method Projects (line 179) | func (c *GitHubLogger) Projects(org string, query string) ([]*github.P...
method ProjectItems (line 183) | func (c *GitHubLogger) ProjectItems(p *github.Project) ([]*github.Proj...
method DeleteProjectItem (line 187) | func (c *GitHubLogger) DeleteProjectItem(project *github.Project, item...
method SetProjectItemFieldOption (line 192) | func (c *GitHubLogger) SetProjectItemFieldOption(project *github.Proje...
method Discussions (line 197) | func (c *GitHubLogger) Discussions(org string, repo string) ([]*github...
type labelList (line 141) | type labelList
method String (line 143) | func (ll labelList) String() string {
type GitHubDryClient (line 202) | type GitHubDryClient struct
method GraphQLQuery (line 208) | func (c *GitHubDryClient) GraphQLQuery(query string, vars github.Vars)...
method GraphQLMutation (line 214) | func (c *GitHubDryClient) GraphQLMutation(query string, vars github.Va...
method CurrentUser (line 219) | func (c *GitHubDryClient) CurrentUser() (string, error) {
method SearchLabels (line 223) | func (c *GitHubDryClient) SearchLabels(org string, repo string, query ...
method SearchMilestones (line 227) | func (c *GitHubDryClient) SearchMilestones(org string, repo string, qu...
method Issue (line 231) | func (c *GitHubDryClient) Issue(org string, repo string, n int) (*gith...
method IssueComments (line 235) | func (c *GitHubDryClient) IssueComments(issue *github.Issue) ([]*githu...
method AddIssueComment (line 239) | func (c *GitHubDryClient) AddIssueComment(issue *github.Issue, text st...
method AddIssueLabels (line 243) | func (c *GitHubDryClient) AddIssueLabels(issue *github.Issue, labels ....
method RemoveIssueLabels (line 247) | func (c *GitHubDryClient) RemoveIssueLabels(issue *github.Issue, label...
method CloseIssue (line 251) | func (c *GitHubDryClient) CloseIssue(issue *github.Issue, reason schem...
method RetitleIssue (line 255) | func (c *GitHubDryClient) RetitleIssue(issue *github.Issue, title stri...
method RemilestoneIssue (line 259) | func (c *GitHubDryClient) RemilestoneIssue(issue *github.Issue, milest...
method Projects (line 263) | func (c *GitHubDryClient) Projects(org string, query string) ([]*githu...
method ProjectItems (line 267) | func (c *GitHubDryClient) ProjectItems(p *github.Project) ([]*github.P...
method DeleteProjectItem (line 271) | func (c *GitHubDryClient) DeleteProjectItem(project *github.Project, i...
method SetProjectItemFieldOption (line 275) | func (c *GitHubDryClient) SetProjectItemFieldOption(project *github.Pr...
method Discussions (line 279) | func (c *GitHubDryClient) Discussions(org string, repo string) ([]*git...
FILE: minutes3/minutes.go
function main (line 39) | func main() {
function getConfig (line 103) | func getConfig(path ...string) string {
function getCacheDir (line 111) | func getCacheDir() string {
type Reporter (line 123) | type Reporter struct
method Update (line 221) | func (r *Reporter) Update(doc *Doc) (*Minutes, map[int]string) {
method PostMinutes (line 463) | func (r *Reporter) PostMinutes(m *Minutes, issueNum int) {
method RetireOld (line 573) | func (r *Reporter) RetireOld() {
function NewReporter (line 131) | func NewReporter(dryRun bool) (*Reporter, error) {
type Minutes (line 206) | type Minutes struct
type Event (line 212) | type Event struct
constant checkQuestion (line 219) | checkQuestion = "Have all remaining concerns about this proposal been ad...
function markdownEscape (line 569) | func markdownEscape(s string) string {
FILE: minutes3/oauth.go
function makeOAuthClient (line 24) | func makeOAuthClient(cacheDir string, config *oauth2.Config) *http.Client {
function getTokenFromWeb (line 36) | func getTokenFromWeb(config *oauth2.Config) *oauth2.Token {
function loadCachedToken (line 84) | func loadCachedToken(file string) (*oauth2.Token, error) {
function saveCachedToken (line 95) | func saveCachedToken(path string, token *oauth2.Token) {
FILE: minutes3/tables.go
function gitWho (line 27) | func gitWho(who string) string {
function mapSet (line 37) | func mapSet[T comparable](values iter.Seq[T]) map[T]bool {
function updateMsg (line 48) | func updateMsg(old, new, reason, userName string) string {
function msgFooter (line 59) | func msgFooter(userName string) string {
FILE: pcvaluetab/alt.go
type indexScheme (line 18) | type indexScheme
constant indexFixedWidth (line 23) | indexFixedWidth indexScheme = iota
constant indexGroupVarint (line 28) | indexGroupVarint
constant indexByteOrHeader (line 34) | indexByteOrHeader
constant useIndex (line 37) | useIndex = indexByteOrHeader
type biasScheme (line 39) | type biasScheme
constant biasNone (line 43) | biasNone biasScheme = iota
constant biasFixed (line 48) | biasFixed
constant biasPerChunk (line 51) | biasPerChunk
constant biasStartValue (line 56) | biasStartValue
constant useBias (line 59) | useBias = biasStartValue
constant fixedBias (line 63) | fixedBias = -120
function linearIndex (line 66) | func linearIndex(tab *VarintPCData) []byte {
function lookupLinearIndex (line 290) | func lookupLinearIndex(data []byte, textLen, pc uint32) int32 {
function count0124Formula (line 438) | func count0124Formula(x uint8) uint {
function count0124Slow (line 463) | func count0124Slow(x uint8) uint {
function count0124 (line 496) | func count0124(x uint8) uint {
FILE: pcvaluetab/alt_test.go
function TestCount0124 (line 16) | func TestCount0124(t *testing.T) {
function BenchmarkCount0124 (line 40) | func BenchmarkCount0124(b *testing.B) {
FILE: pcvaluetab/bench_test.go
function init (line 22) | func init() {
type stringList (line 26) | type stringList struct
method String (line 30) | func (l *stringList) String() string {
method Set (line 34) | func (l *stringList) Set(x string) error {
function BenchmarkDecode (line 39) | func BenchmarkDecode(b *testing.B) {
function fileSizeStats (line 65) | func fileSizeStats(b *testing.B, bin string, symtab *SymTab) {
constant pcModeRandom (line 113) | pcModeRandom = math.MaxUint32
function decode1 (line 115) | func decode1(b *testing.B, symtab *SymTab, pcMode uint32) {
FILE: pcvaluetab/dist.go
type Dist (line 13) | type Dist struct
method Add (line 18) | func (d *Dist) Add(val int) {
method Quantile (line 23) | func (d *Dist) Quantile(q float64) int {
method StringSummary (line 31) | func (d *Dist) StringSummary() string {
FILE: pcvaluetab/enc.go
type rawPCHeader1 (line 9) | type rawPCHeader1 struct
type rawPCHeader (line 16) | type rawPCHeader struct
type rawFunc (line 28) | type rawFunc struct
type rawABIFuncID (line 51) | type rawABIFuncID
type rawABIFuncFlag (line 52) | type rawABIFuncFlag
FILE: pcvaluetab/main.go
function main (line 20) | func main() {
function diffPct (line 162) | func diffPct(before, after int) float64 {
FILE: pcvaluetab/read.go
type Decoder (line 13) | type Decoder struct
method Read (line 19) | func (d *Decoder) Read(data []byte, out any) (int, error) {
method read1 (line 40) | func (d *Decoder) read1(data []byte, out reflect.Value) (int, error) {
FILE: pcvaluetab/symtab.go
type SymTab (line 17) | type SymTab struct
type Func (line 30) | type Func struct
type PCTabKey (line 37) | type PCTabKey
type VarintPCData (line 39) | type VarintPCData struct
method Lookup (line 183) | func (t *VarintPCData) Lookup(pc uint32) int32 {
function LoadSymTab (line 46) | func LoadSymTab(path string) *SymTab {
function decodeVarintPCData (line 153) | func decodeVarintPCData(data []byte) *VarintPCData {
type pcvalueCache (line 195) | type pcvalueCache struct
type pcvalueCacheEnt (line 199) | type pcvalueCacheEnt struct
function pcvalueCacheKey (line 212) | func pcvalueCacheKey(targetpc uintptr) uintptr {
constant PtrSize (line 216) | PtrSize = 8
function fastrandn (line 219) | func fastrandn(n uint32) uint32
function lookupVarintPCData (line 221) | func lookupVarintPCData(p []byte, targetpc uintptr, cache *pcvalueCache)...
constant PCQuantum (line 287) | PCQuantum = 1
function step (line 290) | func step(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, o...
function readvarint (line 315) | func readvarint(p []byte) (read uint32, val uint32) {
FILE: ptype/main.go
function main (line 53) | func main() {
function isBuiltinName (line 148) | func isBuiltinName(typeName string) bool {
type typePrinter (line 160) | type typePrinter struct
method fmt (line 173) | func (p *typePrinter) fmt(f string, args ...interface{}) {
method setLineComment (line 213) | func (p *typePrinter) setLineComment(f string, args ...interface{}) {
method stripPkg (line 220) | func (p *typePrinter) stripPkg(name string) string {
method printType (line 227) | func (p *typePrinter) printType(typ dwarf.Type) {
method strOffset (line 393) | func (p *typePrinter) strOffset() string {
FILE: rtanalysis/directives/analysis.go
type Result (line 18) | type Result
function run (line 20) | func run(pass *analysis.Pass) (interface{}, error) {
FILE: rtanalysis/main.go
function main (line 8) | func main() { singlechecker.Main(systemstack.Analyzer) }
FILE: rtanalysis/systemstack/analysis.go
type Func (line 20) | type Func struct
method String (line 25) | func (f Func) String() string {
type Result (line 35) | type Result
function run (line 37) | func run(pass *analysis.Pass) (interface{}, error) {
FILE: scanpagemap.go
constant pageSize (line 13) | pageSize = 4096
function main (line 17) | func main() {
constant PAGEFLAG_ANON (line 58) | PAGEFLAG_ANON = 1 << 12
constant PAGEFLAG_COMPOUND_HEAD (line 59) | PAGEFLAG_COMPOUND_HEAD = 1 << 15
constant PAGEFLAG_COMPOUND_TAIL (line 60) | PAGEFLAG_COMPOUND_TAIL = 1 << 16
constant PAGEFLAG_HUGE (line 61) | PAGEFLAG_HUGE = 1 << 17
constant PAGEFLAG_THP (line 62) | PAGEFLAG_THP = 1 << 22
constant PAGEFLAG_ZERO_PAGE (line 63) | PAGEFLAG_ZERO_PAGE = 1 << 24
type pageFlags (line 66) | type pageFlags
method String (line 68) | func (p pageFlags) String() string {
function dumpRange (line 103) | func dumpRange(pagemap, pageflags *os.File, lo, hi uint64) {
FILE: split/bench_test.go
function BenchmarkCounterSplitAtomic (line 14) | func BenchmarkCounterSplitAtomic(b *testing.B) {
function BenchmarkCounterSplitLocked (line 25) | func BenchmarkCounterSplitLocked(b *testing.B) {
function BenchmarkCounterShared (line 43) | func BenchmarkCounterShared(b *testing.B) {
function BenchmarkCounterSequential (line 56) | func BenchmarkCounterSequential(b *testing.B) {
function BenchmarkRWMutex (line 72) | func BenchmarkRWMutex(b *testing.B) {
FILE: split/example_id_test.go
type UIDGenerator (line 18) | type UIDGenerator struct
method GenUID (line 44) | func (g *UIDGenerator) GenUID() uint64 {
constant batchSize (line 24) | batchSize = 256
type uidShard (line 26) | type uidShard struct
function NewUIDGenerator (line 31) | func NewUIDGenerator() *UIDGenerator {
function Example_idGenerator (line 76) | func Example_idGenerator() {
FILE: split/example_rwmutex_test.go
type RWMutex (line 19) | type RWMutex struct
method doInit (line 27) | func (m *RWMutex) doInit() {
method Lock (line 48) | func (m *RWMutex) Lock() {
method Unlock (line 62) | func (m *RWMutex) Unlock() {
method RLock (line 78) | func (m *RWMutex) RLock() RWMutexRUnlocker {
type RWMutexRUnlocker (line 70) | type RWMutexRUnlocker struct
method RUnlock (line 88) | func (c RWMutexRUnlocker) RUnlock() {
function Example_rwMutex (line 92) | func Example_rwMutex() {
FILE: split/examples_test.go
function Example_counter (line 17) | func Example_counter() {
function Example_counterConsistent (line 49) | func Example_counterConsistent() {
function Example_logging (line 116) | func Example_logging() {
function Example_randomSource (line 199) | func Example_randomSource() {
function Example_optimisticTransactions (line 230) | func Example_optimisticTransactions() {
FILE: split/value.go
constant cacheLineBytes (line 30) | cacheLineBytes = 128
type Value (line 35) | type Value struct
method Get (line 113) | func (v *Value) Get() interface{} {
method shard (line 161) | func (v *Value) shard(shard int) unsafe.Pointer {
method Range (line 191) | func (v *Value) Range(fn ...interface{}) {
type emptyInterface (line 43) | type emptyInterface struct
function New (line 54) | func New(constructor interface{}) *Value {
function runtime_procPin (line 219) | func runtime_procPin() int
function runtime_procUnpin (line 222) | func runtime_procUnpin()
function procID (line 225) | func procID() int
FILE: split/vlogger_test.go
type valueLoggerLocked (line 15) | type valueLoggerLocked struct
method append (line 27) | func (l *valueLoggerLocked) append(v uint64) {
method process (line 42) | func (l *valueLoggerLocked) process(buf *valueLoggerBuf) {
function newValueLoggerLocked (line 21) | func newValueLoggerLocked() valueLoggerLocked {
function BenchmarkLazyAggregationSplitLocked (line 48) | func BenchmarkLazyAggregationSplitLocked(b *testing.B) {
constant log2ValueLoggerBuf (line 61) | log2ValueLoggerBuf = 8
constant log2ValueLoggerBufs (line 62) | log2ValueLoggerBufs = 1
constant valueLoggerIndexShift (line 64) | valueLoggerIndexShift = 64 - (log2ValueLoggerBuf + log2ValueLoggerBufs)
constant activeWriterBits (line 65) | activeWriterBits = 1 + log2ValueLoggerBuf
constant bufMarkMask (line 66) | bufMarkMask = 1 << (activeWriterBits - 1)
type valueLoggerBuf (line 69) | type valueLoggerBuf
type valueLoggerAtomic (line 75) | type valueLoggerAtomic struct
method append (line 107) | func (l *valueLoggerAtomic) append(v uint64) {
method process (line 178) | func (l *valueLoggerAtomic) process(buf *valueLoggerBuf) {
function newValueLogger (line 99) | func newValueLogger() valueLoggerAtomic {
function BenchmarkLazyAggregationSplitAtomic (line 184) | func BenchmarkLazyAggregationSplitAtomic(b *testing.B) {
function BenchmarkLazyAggregationShared (line 195) | func BenchmarkLazyAggregationShared(b *testing.B) {
FILE: srgb/main.go
function main (line 14) | func main() {
FILE: stackmapcompress.py
class Stackmap (line 19) | class Stackmap:
method __init__ (line 20) | def __init__(self, dec=None):
method clone (line 30) | def clone(self):
method add (line 35) | def add(self, bitmap):
method sort (line 47) | def sort(self):
method encode (line 52) | def encode(self, enc, compact=False):
class PCData (line 65) | class PCData:
method __init__ (line 66) | def __init__(self):
method encode (line 69) | def encode(self, enc):
method huffSize (line 77) | def huffSize(self, pcHuff, valHuff):
method grSize (line 85) | def grSize(self, pcHuff, n):
function grSize (line 94) | def grSize(val, n):
class Decoder (line 98) | class Decoder:
method __init__ (line 99) | def __init__(self, b):
method int32 (line 102) | def int32(self):
method bitmap (line 107) | def bitmap(self, nbits):
class Encoder (line 115) | class Encoder:
method __init__ (line 116) | def __init__(self):
method uint8 (line 119) | def uint8(self, i):
method int32 (line 122) | def int32(self, i):
method bitmap (line 125) | def bitmap(self, bits, nbits):
method uvarint (line 129) | def uvarint(self, v):
method svarint (line 137) | def svarint(self, v):
function parse (line 143) | def parse(stream):
function genStackMaps (line 162) | def genStackMaps(fns, padToByte=True, dedup=True, sortBitmaps=False):
function likeStackMap (line 190) | def likeStackMap(fns, padToByte=True, dedup=True, sortBitmaps=None, huff...
function filterLiveToDead (line 248) | def filterLiveToDead(fns):
function total (line 266) | def total(dct):
function iterDeltas (line 271) | def iterDeltas(regMaps):
function countMaps (line 286) | def countMaps(fns):
function countDeltas (line 293) | def countDeltas(fns):
function huffman (line 305) | def huffman(counts, streamAlign=1):
function huffmanCoded (line 326) | def huffmanCoded(fns, streamAlign=1):
FILE: stress2/cmd.go
type Command (line 39) | type Command struct
method reader (line 127) | func (c *Command) reader(f *os.File) {
method waiter (line 153) | func (c *Command) waiter() {
method Kill (line 193) | func (c *Command) Kill() {
method Done (line 222) | func (c *Command) Done() <-chan struct{} {
function StartCommand (line 68) | func StartCommand(args []string, out io.Writer) (*Command, error) {
FILE: stress2/cmd_test.go
function TestStdoutExitRace (line 9) | func TestStdoutExitRace(t *testing.T) {
FILE: stress2/main.go
function main (line 20) | func main() {
type FlagLimit (line 106) | type FlagLimit struct
method String (line 110) | func (f FlagLimit) String() string {
method Set (line 122) | func (f FlagLimit) Set(x string) error {
type FlagRegexp (line 140) | type FlagRegexp struct
method String (line 144) | func (f FlagRegexp) String() string {
method Set (line 151) | func (f FlagRegexp) Set(x string) error {
FILE: stress2/reporter.go
type StressReporter (line 18) | type StressReporter interface
function NewStdoutReporter (line 25) | func NewStdoutReporter() StressReporter {
type ReporterDumb (line 32) | type ReporterDumb struct
method StartStatus (line 36) | func (r *ReporterDumb) StartStatus() {}
method StopStatus (line 37) | func (r *ReporterDumb) StopStatus() {}
method Status (line 38) | func (r *ReporterDumb) Status(format string, a ...interface{}) {
method Write (line 42) | func (r *ReporterDumb) Write(data []byte) (int, error) {
type ReporterVT100 (line 46) | type ReporterVT100 struct
method StartStatus (line 54) | func (r *ReporterVT100) StartStatus() {
method StopStatus (line 61) | func (r *ReporterVT100) StopStatus() {
method Status (line 66) | func (r *ReporterVT100) Status(format string, a ...interface{}) {
method Write (line 80) | func (r *ReporterVT100) Write(data []byte) (int, error) {
method run (line 88) | func (r *ReporterVT100) run() {
constant resetLine (line 74) | resetLine = "\r\x1b[2K"
constant wrapOff (line 75) | wrapOff = "\x1b[?7l"
constant moveEOL (line 76) | moveEOL = "\x1b[999C"
constant wrapOn (line 77) | wrapOn = "\x1b[?7h"
type TimeSince (line 151) | type TimeSince
method String (line 153) | func (t TimeSince) String() string {
FILE: stress2/stress.go
type Stress (line 23) | type Stress struct
method resultKind (line 62) | func (s *Stress) resultKind(res result, output []byte) ResultKind {
method Run (line 77) | func (s *Stress) Run(reporter StressReporter) ResultKind {
method runner (line 253) | func (s *Stress) runner(start <-chan startRun, stop <-chan struct{}, r...
method run1 (line 261) | func (s *Stress) run1(tok startRun, stop <-chan struct{}, results chan...
type startRun (line 42) | type startRun struct
type result (line 46) | type result struct
type ResultKind (line 53) | type ResultKind
constant ResultPass (line 56) | ResultPass ResultKind = iota
constant ResultFail (line 57) | ResultFail
constant ResultFlake (line 58) | ResultFlake
constant ResultTimeout (line 59) | ResultTimeout
function saveLog (line 312) | func saveLog(outDir, prefix string, idx *int, oldName string) (string, e...
function printTail (line 332) | func printTail(w io.Writer, data []byte) {
function formatProcessState (line 367) | func formatProcessState(state *os.ProcessState) string {
FILE: stress2/stress_test.go
function TestPrintTail (line 12) | func TestPrintTail(t *testing.T) {
FILE: varint/bench_test.go
function TestDecodeVarintAsm (line 13) | func TestDecodeVarintAsm(t *testing.T) {
function testDecodeVarintAsm (line 35) | func testDecodeVarintAsm(t *testing.T, f func([]byte) (uint64, int), bmi...
function init (line 65) | func init() {
function BenchmarkDecodeVarint (line 83) | func BenchmarkDecodeVarint(b *testing.B) {
function BenchmarkDecodeVarintN (line 93) | func BenchmarkDecodeVarintN(b *testing.B) {
function BenchmarkDecodeVarintAsmLoop (line 108) | func BenchmarkDecodeVarintAsmLoop(b *testing.B) {
function BenchmarkDecodeVarintAsmLoopN (line 118) | func BenchmarkDecodeVarintAsmLoopN(b *testing.B) {
function BenchmarkDecodeVarintAsmBMI2 (line 133) | func BenchmarkDecodeVarintAsmBMI2(b *testing.B) {
function BenchmarkDecodeVarintAsmBMI2N (line 143) | func BenchmarkDecodeVarintAsmBMI2N(b *testing.B) {
function BenchmarkDecodeVarintAsm1 (line 158) | func BenchmarkDecodeVarintAsm1(b *testing.B) {
function BenchmarkDecodeVarintAsm2 (line 168) | func BenchmarkDecodeVarintAsm2(b *testing.B) {
FILE: varint/varint.go
constant maxVarintBytes (line 7) | maxVarintBytes = 10
function EncodeVarint (line 11) | func EncodeVarint(x uint64) []byte {
function DecodeVarint (line 23) | func DecodeVarint(buf []byte) (x uint64, n int) {
function queryBMI2 (line 41) | func queryBMI2() bool
function decodeVarintAsmLoop (line 45) | func decodeVarintAsmLoop(buf []byte) (x uint64, n int)
function decodeVarintAsmBMI2 (line 46) | func decodeVarintAsmBMI2(buf []byte) (x uint64, n int)
function decodeVarintAsm1 (line 47) | func decodeVarintAsm1(buf []byte) (x uint64, n int)
function decodeVarintAsm2 (line 48) | func decodeVarintAsm2(buf []byte) (x uint64, n int)
Condensed preview — 270 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,267K chars).
[
{
"path": "LICENSE",
"chars": 1480,
"preview": "Copyright (c) 2015 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or with"
},
{
"path": "abi/abi.go",
"chars": 10988,
"preview": "// Copyright 2020 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "abi/go.mod",
"chars": 83,
"preview": "module abi\n\ngo 1.15\n\nrequire golang.org/x/tools v0.0.0-20200815165600-90abf76919f3\n"
},
{
"path": "abi/go.sum",
"chars": 2264,
"preview": "github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngolang.org/x/crypto v0.0.0-20190"
},
{
"path": "bench/parse.go",
"chars": 6827,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "bench/parse_test.go",
"chars": 2978,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "bench/print.go",
"chars": 4042,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchcmd/main.go",
"chars": 1158,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchcmd/rss_nounix.go",
"chars": 286,
"preview": "// Copyright 2025 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchcmd/rss_unix.go",
"chars": 706,
"preview": "// Copyright 2025 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchmany/benchmany.go",
"chars": 4892,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchmany/commits.go",
"chars": 5476,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchmany/readlog.go",
"chars": 4852,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchmany/run.go",
"chars": 14419,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchmany/run_test.go",
"chars": 3236,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchmany/signal_notunix.go",
"chars": 244,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchmany/signal_unix.go",
"chars": 274,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchmany/status.go",
"chars": 2978,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/git.go",
"chars": 3040,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/kza.go",
"chars": 3504,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/kza_test.go",
"chars": 1221,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/main.go",
"chars": 3257,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/plot.go",
"chars": 4557,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\n\t\"github.com/aclements/go-gg/generic/slice\"\n\t\"github.com/aclements/go-gg/gg\"\n\t\"gi"
},
{
"path": "benchplot/table.go",
"chars": 2878,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/LICENSE",
"chars": 1480,
"preview": "Copyright (c) 2016 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or with"
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/README.md",
"chars": 360,
"preview": "# gg [](https://godoc.org/github.com/aclements/go-gg)\n\ngg is"
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/generic/doc.go",
"chars": 228,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/generic/error.go",
"chars": 427,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/generic/order.go",
"chars": 2304,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/generic/slice/concat.go",
"chars": 1046,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/generic/slice/concat_test.go",
"chars": 692,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/generic/slice/convert.go",
"chars": 1424,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/generic/slice/convert_test.go",
"chars": 1034,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/generic/slice/cycle.go",
"chars": 1146,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/generic/slice/doc.go",
"chars": 225,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/generic/slice/find.go",
"chars": 1360,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/generic/slice/index.go",
"chars": 1749,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/generic/slice/min.go",
"chars": 2468,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/generic/slice/min_test.go",
"chars": 2327,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/generic/slice/nub.go",
"chars": 1283,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/generic/slice/select_test.go",
"chars": 1099,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/generic/slice/seq.go",
"chars": 807,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/generic/slice/sort.go",
"chars": 3173,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/generic/slice/util_test.go",
"chars": 610,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/gg/example_scale_test.go",
"chars": 1122,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/gg/facet.go",
"chars": 9939,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/gg/group.go",
"chars": 1353,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/gg/layer.go",
"chars": 11667,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/gg/layout/grid.go",
"chars": 5461,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/gg/layout/layout.go",
"chars": 2413,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/gg/layout.go",
"chars": 15935,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/gg/mark.go",
"chars": 14614,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/gg/package.go",
"chars": 5557,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/gg/plot.go",
"chars": 7821,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/gg/render.go",
"chars": 12897,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/gg/scale.go",
"chars": 34048,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/gg/stepmode_string.go",
"chars": 392,
"preview": "// Code generated by \"stringer -type StepMode\"; DO NOT EDIT\n\npackage gg\n\nimport \"fmt\"\n\nconst _StepMode_name = \"StepHVSte"
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/gg/testmain.go",
"chars": 1320,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/gg/text.go",
"chars": 838,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/gg/transform.go",
"chars": 834,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/ggstat/agg.go",
"chars": 8770,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/ggstat/bin.go",
"chars": 5823,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/ggstat/common.go",
"chars": 293,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/ggstat/density.go",
"chars": 3524,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/ggstat/domain.go",
"chars": 3158,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/ggstat/ecdf.go",
"chars": 3598,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/ggstat/fn.go",
"chars": 3279,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/ggstat/loess.go",
"chars": 2257,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/ggstat/lsquares.go",
"chars": 1837,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/ggstat/normalize.go",
"chars": 4439,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/palette/blend.go",
"chars": 2541,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/palette/brewer/brewer.go",
"chars": 65735,
"preview": "// Generated by genbrewer. DO NOT EDIT.\n// Please see license at http://colorbrewer.org/export/LICENSE.txt\n\npackage brew"
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/palette/brewer/colorbrewer.json",
"chars": 35144,
"preview": "{ \n\"Spectral\": {\"3\": [\"rgb(252,141,89)\", \"rgb(255,255,191)\", \"rgb(153,213,148)\"], \"4\": [\"rgb(215,25,28)\", \"rgb(253,174,"
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/palette/brewer/genbrewer.go",
"chars": 3326,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/palette/brewer/package.go",
"chars": 1316,
"preview": "// Copyright (c) 2002 Cynthia Brewer, Mark Harrower, and The\n// Pennsylvania State University.\n// Please see license at "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/palette/makesrgbtab.go",
"chars": 4137,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/palette/palette.go",
"chars": 1808,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/palette/srgb.go",
"chars": 560,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/palette/srgbtab.go",
"chars": 26139,
"preview": "// Generated by makesrgbtab. DO NOT EDIT.\n\npackage palette\n\nvar sRGBToLinearTab = [256]uint16{\n\t0,\n\t19,\n\t39,\n\t59,\n\t79,\n\t"
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/palette/viridis.go",
"chars": 6714,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/table/concat.go",
"chars": 2254,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/table/filter.go",
"chars": 2594,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/table/group.go",
"chars": 6137,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/table/head.go",
"chars": 1489,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/table/join.go",
"chars": 1992,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/table/map.go",
"chars": 4459,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/table/new.go",
"chars": 2612,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/table/new_test.go",
"chars": 3085,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/table/pivot.go",
"chars": 4652,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/table/pivot_test.go",
"chars": 1627,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/table/print.go",
"chars": 3309,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/table/print_test.go",
"chars": 1565,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/table/sort.go",
"chars": 2388,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/table/table.go",
"chars": 13208,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-gg/table/table_test.go",
"chars": 9123,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/LICENSE",
"chars": 1479,
"preview": "Copyright (c) 2015 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or with"
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/README.md",
"chars": 361,
"preview": "These packages provide more specialized math routines than are\navailable in the standard Go math package. go-moremath cu"
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/cmd/dist/dist.go",
"chars": 2068,
"preview": "// dist reads newline-separated numbers and describes their distribution.\n//\n// For example,\n//\n// $ seq 1 20 | grep -v"
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/cmd/dist/plot.go",
"chars": 5241,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/fit/loess.go",
"chars": 3112,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/fit/loess_test.go",
"chars": 1565,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/fit/lsquares.go",
"chars": 4635,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/fit/package.go",
"chars": 234,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/internal/mathtest/mathtest.go",
"chars": 1320,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/mathx/beta.go",
"chars": 2413,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/mathx/beta_test.go",
"chars": 729,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/mathx/choose.go",
"chars": 1406,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/mathx/gamma.go",
"chars": 2100,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/mathx/gamma_test.go",
"chars": 1381,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/mathx/package.go",
"chars": 354,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/mathx/sign.go",
"chars": 409,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/scale/err.go",
"chars": 334,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/scale/interface.go",
"chars": 1970,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/scale/linear.go",
"chars": 4588,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/scale/linear_test.go",
"chars": 4761,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/scale/log.go",
"chars": 5092,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/scale/log_test.go",
"chars": 5584,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/scale/package.go",
"chars": 488,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/scale/ticks.go",
"chars": 3333,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/scale/ticks_test.go",
"chars": 1517,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/scale/util.go",
"chars": 310,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/alg.go",
"chars": 2462,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/deltadist.go",
"chars": 1070,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/dist.go",
"chars": 6640,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/dist_test.go",
"chars": 907,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/hist.go",
"chars": 1973,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/hypergdist.go",
"chars": 2559,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/hypergdist_test.go",
"chars": 585,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/kde.go",
"chars": 9974,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/kde_test.go",
"chars": 2138,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/kdeboundarymethod_string.go",
"chars": 454,
"preview": "// generated by stringer -type=KDEBoundaryMethod; DO NOT EDIT\n\npackage stats\n\nimport \"fmt\"\n\nconst _KDEBoundaryMethod_nam"
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/kdekernel_string.go",
"chars": 388,
"preview": "// generated by stringer -type=KDEKernel; DO NOT EDIT\n\npackage stats\n\nimport \"fmt\"\n\nconst _KDEKernel_name = \"GaussianKer"
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/linearhist.go",
"chars": 1003,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/locationhypothesis_string.go",
"chars": 511,
"preview": "// generated by stringer -type LocationHypothesis; DO NOT EDIT\n\npackage stats\n\nimport \"fmt\"\n\nconst _LocationHypothesis_n"
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/loghist.go",
"chars": 1989,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/normaldist.go",
"chars": 3374,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/normaldist_test.go",
"chars": 749,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/package.go",
"chars": 710,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/sample.go",
"chars": 7377,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/sample_test.go",
"chars": 449,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/stream.go",
"chars": 2329,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/tdist.go",
"chars": 848,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/tdist_test.go",
"chars": 2774,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/ttest.go",
"chars": 4467,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/ttest_test.go",
"chars": 2304,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/udist.go",
"chars": 12186,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/udist_test.go",
"chars": 9138,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/utest.go",
"chars": 8645,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/utest_test.go",
"chars": 2518,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/stats/util_test.go",
"chars": 1702,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/vec/package.go",
"chars": 276,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/github.com/aclements/go-moremath/vec/vec.go",
"chars": 1785,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "benchplot/vendor/update",
"chars": 338,
"preview": "#!/bin/sh\n\nset -e\n\nmv github.com github.com.old || true\n\nmkdir -p github.com/aclements/go-gg\ngit -C $GOPATH/src/github.c"
},
{
"path": "benchscripts/bench-many",
"chars": 1717,
"preview": "#!/bin/zsh\n\nset -e\n\nif [[ $# != 3 ]]; then\n echo \"usage: bench-many rev-file out-dir iterations\" >&2\n exit 1\nfi\n\nr"
},
{
"path": "benchscripts/benchstat2",
"chars": 3906,
"preview": "#!/usr/bin/python3\n\nimport os\nimport sys\nimport tempfile\nimport subprocess\nimport argparse\nimport re\n\ndef expandHash(com"
},
{
"path": "benchscripts/plot-time",
"chars": 4836,
"preview": "#!/usr/bin/env python3\n# -*- python -*-\n\n# Copyright 2015 The Go Authors. All rights reserved.\n# Use of this source code"
},
{
"path": "benchscripts/plot-time-2",
"chars": 4705,
"preview": "#!/usr/bin/env python3\n# -*- python -*-\n\n# Copyright 2015 The Go Authors. All rights reserved.\n# Use of this source code"
},
{
"path": "buildstats/alg.go",
"chars": 352,
"preview": "// Copyright 2022 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "buildstats/go.mod",
"chars": 129,
"preview": "module github.com/aclements/go-misc/buildstats\n\ngo 1.18\n\nrequire golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d // "
},
{
"path": "buildstats/go.sum",
"chars": 207,
"preview": "golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d h1:vtUKgx8dahOomfFzLREU8nSv25YHnTgLBn4rDnWZdU0=\ngolang.org/x/exp v0."
},
{
"path": "buildstats/main.go",
"chars": 4379,
"preview": "// Copyright 2022 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "buildstats/rev.go",
"chars": 2499,
"preview": "// Copyright 2022 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "buildstats/timeflag.go",
"chars": 1089,
"preview": "// Copyright 2021 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "cl-fetch/main.go",
"chars": 4728,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "dashquery/compile.go",
"chars": 6737,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "dashquery/compile_test.go",
"chars": 1009,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "dashquery/main.go",
"chars": 4614,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "dashquery/xdg.go",
"chars": 888,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "findflakes/adtest.go",
"chars": 2933,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "findflakes/flaketest.go",
"chars": 6617,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "findflakes/geodist.go",
"chars": 1473,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "findflakes/html.go",
"chars": 6630,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "findflakes/logs.go",
"chars": 2770,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "findflakes/main.go",
"chars": 9948,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "findflakes/paths.go",
"chars": 1016,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "findflakes/text.go",
"chars": 2000,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "findflakes/xdg.go",
"chars": 883,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "findtypes/main.go",
"chars": 6542,
"preview": "// Copyright 2017 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "foreachplatform/go.mod",
"chars": 61,
"preview": "module github.com/aclements/go-misc/foreachplatform\n\ngo 1.21\n"
},
{
"path": "foreachplatform/main.go",
"chars": 4649,
"preview": "// Copyright 2023 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "gc-S/go.mod",
"chars": 50,
"preview": "module github.com/aclements/go-misc/gc-S\n\ngo 1.20\n"
},
{
"path": "gc-S/main.go",
"chars": 3009,
"preview": "// Copyright 2024 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "gcdense/test.py",
"chars": 6650,
"preview": "#!/usr/bin/python3\n# -*- coding: utf-8 -*-\n\nimport math\nimport random\nimport collections\n\nimport numpy as np\nimport matp"
},
{
"path": "git-p/gerrit.go",
"chars": 6470,
"preview": "// Copyright 2017 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "git-p/git.go",
"chars": 5642,
"preview": "// Copyright 2017 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "git-p/go.mod",
"chars": 132,
"preview": "module github.com/aclements/go-misc/git-p\n\ngo 1.17\n\nrequire golang.org/x/term v0.16.0\n\nrequire golang.org/x/sys v0.16.0 "
},
{
"path": "git-p/go.sum",
"chars": 308,
"preview": "golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=\ngolang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQU"
},
{
"path": "git-p/main.go",
"chars": 13782,
"preview": "// Copyright 2017 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "git-p/pager.go",
"chars": 1998,
"preview": "// Copyright 2017 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "git-p/shell.go",
"chars": 774,
"preview": "// Copyright 2017 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "git-p/style.go",
"chars": 671,
"preview": "// Copyright 2017 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "go-weave/amb/det.go",
"chars": 1989,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "go-weave/amb/progress.go",
"chars": 2340,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "go-weave/amb/rand.go",
"chars": 1110,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "go-weave/amb/run.go",
"chars": 3279,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "go-weave/models/cl20858.go",
"chars": 2286,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "go-weave/models/issue16083.go",
"chars": 2163,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "go-weave/models/markterm.go",
"chars": 2267,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "go-weave/models/maxtree.go",
"chars": 3466,
"preview": "// Copyright 2017 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "go-weave/models/rescan.go",
"chars": 5411,
"preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
}
]
// ... and 70 more files (download for full content)
About this extraction
This page contains the full source code of the aclements/go-misc GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 270 files (1.1 MB), approximately 403.7k tokens, and a symbol index with 1621 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.