mirror of
https://github.com/golang/go
synced 2024-11-15 11:30:36 -07:00
b0b1d42db3
Doing this because the slices functions are slightly faster and slightly easier to use. It also removes one dependency layer. This CL does not change packages that are used during bootstrap, as the bootstrap compiler does not have the required slices functions. It does not change the go/scanner package because the ErrorList Len, Swap, and Less methods are part of the Go 1 API. Change-Id: If52899be791c829198e11d2408727720b91ebe8a Reviewed-on: https://go-review.googlesource.com/c/go/+/587655 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Ian Lance Taylor <iant@google.com> Auto-Submit: Ian Lance Taylor <iant@google.com> Commit-Queue: Ian Lance Taylor <iant@google.com> Reviewed-by: Damien Neil <dneil@google.com>
215 lines
5.6 KiB
Go
215 lines
5.6 KiB
Go
// Copyright 2013 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 testing_test
|
|
|
|
import (
|
|
"bytes"
|
|
"cmp"
|
|
"runtime"
|
|
"slices"
|
|
"strings"
|
|
"sync/atomic"
|
|
"testing"
|
|
"text/template"
|
|
"time"
|
|
)
|
|
|
|
var prettyPrintTests = []struct {
|
|
v float64
|
|
expected string
|
|
}{
|
|
{0, " 0 x"},
|
|
{1234.1, " 1234 x"},
|
|
{-1234.1, " -1234 x"},
|
|
{999.950001, " 1000 x"},
|
|
{999.949999, " 999.9 x"},
|
|
{99.9950001, " 100.0 x"},
|
|
{99.9949999, " 99.99 x"},
|
|
{-99.9949999, " -99.99 x"},
|
|
{0.000999950001, " 0.001000 x"},
|
|
{0.000999949999, " 0.0009999 x"}, // smallest case
|
|
{0.0000999949999, " 0.0001000 x"},
|
|
}
|
|
|
|
func TestPrettyPrint(t *testing.T) {
|
|
for _, tt := range prettyPrintTests {
|
|
buf := new(strings.Builder)
|
|
testing.PrettyPrint(buf, tt.v, "x")
|
|
if tt.expected != buf.String() {
|
|
t.Errorf("prettyPrint(%v): expected %q, actual %q", tt.v, tt.expected, buf.String())
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestResultString(t *testing.T) {
|
|
// Test fractional ns/op handling
|
|
r := testing.BenchmarkResult{
|
|
N: 100,
|
|
T: 240 * time.Nanosecond,
|
|
}
|
|
if r.NsPerOp() != 2 {
|
|
t.Errorf("NsPerOp: expected 2, actual %v", r.NsPerOp())
|
|
}
|
|
if want, got := " 100\t 2.400 ns/op", r.String(); want != got {
|
|
t.Errorf("String: expected %q, actual %q", want, got)
|
|
}
|
|
|
|
// Test sub-1 ns/op (issue #31005)
|
|
r.T = 40 * time.Nanosecond
|
|
if want, got := " 100\t 0.4000 ns/op", r.String(); want != got {
|
|
t.Errorf("String: expected %q, actual %q", want, got)
|
|
}
|
|
|
|
// Test 0 ns/op
|
|
r.T = 0
|
|
if want, got := " 100", r.String(); want != got {
|
|
t.Errorf("String: expected %q, actual %q", want, got)
|
|
}
|
|
}
|
|
|
|
func TestRunParallel(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping in short mode")
|
|
}
|
|
testing.Benchmark(func(b *testing.B) {
|
|
procs := uint32(0)
|
|
iters := uint64(0)
|
|
b.SetParallelism(3)
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
atomic.AddUint32(&procs, 1)
|
|
for pb.Next() {
|
|
atomic.AddUint64(&iters, 1)
|
|
}
|
|
})
|
|
if want := uint32(3 * runtime.GOMAXPROCS(0)); procs != want {
|
|
t.Errorf("got %v procs, want %v", procs, want)
|
|
}
|
|
if iters != uint64(b.N) {
|
|
t.Errorf("got %v iters, want %v", iters, b.N)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestRunParallelFail(t *testing.T) {
|
|
testing.Benchmark(func(b *testing.B) {
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
// The function must be able to log/abort
|
|
// w/o crashing/deadlocking the whole benchmark.
|
|
b.Log("log")
|
|
b.Error("error")
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestRunParallelFatal(t *testing.T) {
|
|
testing.Benchmark(func(b *testing.B) {
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
if b.N > 1 {
|
|
b.Fatal("error")
|
|
}
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestRunParallelSkipNow(t *testing.T) {
|
|
testing.Benchmark(func(b *testing.B) {
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
if b.N > 1 {
|
|
b.SkipNow()
|
|
}
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
func ExampleB_RunParallel() {
|
|
// Parallel benchmark for text/template.Template.Execute on a single object.
|
|
testing.Benchmark(func(b *testing.B) {
|
|
templ := template.Must(template.New("test").Parse("Hello, {{.}}!"))
|
|
// RunParallel will create GOMAXPROCS goroutines
|
|
// and distribute work among them.
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
// Each goroutine has its own bytes.Buffer.
|
|
var buf bytes.Buffer
|
|
for pb.Next() {
|
|
// The loop body is executed b.N times total across all goroutines.
|
|
buf.Reset()
|
|
templ.Execute(&buf, "World")
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestReportMetric(t *testing.T) {
|
|
res := testing.Benchmark(func(b *testing.B) {
|
|
b.ReportMetric(12345, "ns/op")
|
|
b.ReportMetric(0.2, "frobs/op")
|
|
})
|
|
// Test built-in overriding.
|
|
if res.NsPerOp() != 12345 {
|
|
t.Errorf("NsPerOp: expected %v, actual %v", 12345, res.NsPerOp())
|
|
}
|
|
// Test stringing.
|
|
res.N = 1 // Make the output stable
|
|
want := " 1\t 12345 ns/op\t 0.2000 frobs/op"
|
|
if want != res.String() {
|
|
t.Errorf("expected %q, actual %q", want, res.String())
|
|
}
|
|
}
|
|
|
|
func ExampleB_ReportMetric() {
|
|
// This reports a custom benchmark metric relevant to a
|
|
// specific algorithm (in this case, sorting).
|
|
testing.Benchmark(func(b *testing.B) {
|
|
var compares int64
|
|
for i := 0; i < b.N; i++ {
|
|
s := []int{5, 4, 3, 2, 1}
|
|
slices.SortFunc(s, func(a, b int) int {
|
|
compares++
|
|
return cmp.Compare(a, b)
|
|
})
|
|
}
|
|
// This metric is per-operation, so divide by b.N and
|
|
// report it as a "/op" unit.
|
|
b.ReportMetric(float64(compares)/float64(b.N), "compares/op")
|
|
// This metric is per-time, so divide by b.Elapsed and
|
|
// report it as a "/ns" unit.
|
|
b.ReportMetric(float64(compares)/float64(b.Elapsed().Nanoseconds()), "compares/ns")
|
|
})
|
|
}
|
|
|
|
func ExampleB_ReportMetric_parallel() {
|
|
// This reports a custom benchmark metric relevant to a
|
|
// specific algorithm (in this case, sorting) in parallel.
|
|
testing.Benchmark(func(b *testing.B) {
|
|
var compares atomic.Int64
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
s := []int{5, 4, 3, 2, 1}
|
|
slices.SortFunc(s, func(a, b int) int {
|
|
// Because RunParallel runs the function many
|
|
// times in parallel, we must increment the
|
|
// counter atomically to avoid racing writes.
|
|
compares.Add(1)
|
|
return cmp.Compare(a, b)
|
|
})
|
|
}
|
|
})
|
|
|
|
// NOTE: Report each metric once, after all of the parallel
|
|
// calls have completed.
|
|
|
|
// This metric is per-operation, so divide by b.N and
|
|
// report it as a "/op" unit.
|
|
b.ReportMetric(float64(compares.Load())/float64(b.N), "compares/op")
|
|
// This metric is per-time, so divide by b.Elapsed and
|
|
// report it as a "/ns" unit.
|
|
b.ReportMetric(float64(compares.Load())/float64(b.Elapsed().Nanoseconds()), "compares/ns")
|
|
})
|
|
}
|