Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
benchmark_test.go306 linesDownload Raw Back to testing
1// Copyright 2013 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.4 5package testing_test6 7import (8	"bytes"9	"cmp"10	"context"11	"errors"12	"internal/asan"13	"internal/msan"14	"internal/race"15	"internal/testenv"16	"runtime"17	"slices"18	"strings"19	"sync/atomic"20	"testing"21	"text/template"22	"time"23)24 25var prettyPrintTests = []struct {26	v        float6427	expected string28}{29	{0, "         0 x"},30	{1234.1, "      1234 x"},31	{-1234.1, "     -1234 x"},32	{999.950001, "      1000 x"},33	{999.949999, "       999.9 x"},34	{99.9950001, "       100.0 x"},35	{99.9949999, "        99.99 x"},36	{-99.9949999, "       -99.99 x"},37	{0.000999950001, "         0.001000 x"},38	{0.000999949999, "         0.0009999 x"}, // smallest case39	{0.0000999949999, "         0.0001000 x"},40}41 42func TestPrettyPrint(t *testing.T) {43	for _, tt := range prettyPrintTests {44		buf := new(strings.Builder)45		testing.PrettyPrint(buf, tt.v, "x")46		if tt.expected != buf.String() {47			t.Errorf("prettyPrint(%v): expected %q, actual %q", tt.v, tt.expected, buf.String())48		}49	}50}51 52func TestResultString(t *testing.T) {53	// Test fractional ns/op handling54	r := testing.BenchmarkResult{55		N: 100,56		T: 240 * time.Nanosecond,57	}58	if r.NsPerOp() != 2 {59		t.Errorf("NsPerOp: expected 2, actual %v", r.NsPerOp())60	}61	if want, got := "     100\t         2.400 ns/op", r.String(); want != got {62		t.Errorf("String: expected %q, actual %q", want, got)63	}64 65	// Test sub-1 ns/op (issue #31005)66	r.T = 40 * time.Nanosecond67	if want, got := "     100\t         0.4000 ns/op", r.String(); want != got {68		t.Errorf("String: expected %q, actual %q", want, got)69	}70 71	// Test 0 ns/op72	r.T = 073	if want, got := "     100", r.String(); want != got {74		t.Errorf("String: expected %q, actual %q", want, got)75	}76}77 78func TestRunParallel(t *testing.T) {79	if testing.Short() {80		t.Skip("skipping in short mode")81	}82	testing.Benchmark(func(b *testing.B) {83		procs := uint32(0)84		iters := uint64(0)85		b.SetParallelism(3)86		b.RunParallel(func(pb *testing.PB) {87			atomic.AddUint32(&procs, 1)88			for pb.Next() {89				atomic.AddUint64(&iters, 1)90			}91		})92		if want := uint32(3 * runtime.GOMAXPROCS(0)); procs != want {93			t.Errorf("got %v procs, want %v", procs, want)94		}95		if iters != uint64(b.N) {96			t.Errorf("got %v iters, want %v", iters, b.N)97		}98	})99}100 101func TestRunParallelFail(t *testing.T) {102	testing.Benchmark(func(b *testing.B) {103		b.RunParallel(func(pb *testing.PB) {104			// The function must be able to log/abort105			// w/o crashing/deadlocking the whole benchmark.106			b.Log("log")107			b.Error("error")108		})109	})110}111 112func TestRunParallelFatal(t *testing.T) {113	testing.Benchmark(func(b *testing.B) {114		b.RunParallel(func(pb *testing.PB) {115			for pb.Next() {116				if b.N > 1 {117					b.Fatal("error")118				}119			}120		})121	})122}123 124func TestRunParallelSkipNow(t *testing.T) {125	testing.Benchmark(func(b *testing.B) {126		b.RunParallel(func(pb *testing.PB) {127			for pb.Next() {128				if b.N > 1 {129					b.SkipNow()130				}131			}132		})133	})134}135 136func TestBenchmarkContext(t *testing.T) {137	testing.Benchmark(func(b *testing.B) {138		ctx := b.Context()139		if err := ctx.Err(); err != nil {140			b.Fatalf("expected non-canceled context, got %v", err)141		}142 143		var innerCtx context.Context144		b.Run("inner", func(b *testing.B) {145			innerCtx = b.Context()146			if err := innerCtx.Err(); err != nil {147				b.Fatalf("expected inner benchmark to not inherit canceled context, got %v", err)148			}149		})150		b.Run("inner2", func(b *testing.B) {151			if !errors.Is(innerCtx.Err(), context.Canceled) {152				t.Fatal("expected context of sibling benchmark to be canceled after its test function finished")153			}154		})155 156		t.Cleanup(func() {157			if !errors.Is(ctx.Err(), context.Canceled) {158				t.Fatal("expected context canceled before cleanup")159			}160		})161	})162}163 164// Some auxiliary functions for measuring allocations in a b.Loop benchmark below,165// where in this case mid-stack inlining allows stack allocation of a slice.166// This is based on the example in go.dev/issue/73137.167 168func newX() []byte {169	out := make([]byte, 8)170	return use1(out)171}172 173//go:noinline174func use1(out []byte) []byte {175	return out176}177 178// An auxiliary function for measuring allocations with a simple function argument179// in the b.Loop body.180 181//go:noinline182func use2(x any) {}183 184func TestBenchmarkBLoopAllocs(t *testing.T) {185	testenv.SkipIfOptimizationOff(t)186	if race.Enabled || asan.Enabled || msan.Enabled {187		t.Skip("skipping in case sanitizers alter allocation behavior")188	}189 190	t.Run("call-result", func(t *testing.T) {191		bRet := testing.Benchmark(func(b *testing.B) {192			b.ReportAllocs()193			for b.Loop() {194				newX()195			}196		})197		if bRet.N == 0 {198			t.Fatalf("benchmark reported 0 iterations")199		}200		if bRet.AllocsPerOp() != 0 {201			t.Errorf("want 0 allocs, got %d", bRet.AllocsPerOp())202		}203	})204 205	t.Run("call-arg", func(t *testing.T) {206		bRet := testing.Benchmark(func(b *testing.B) {207			b.ReportAllocs()208			for b.Loop() {209				use2(make([]byte, 1000))210			}211		})212		if bRet.N == 0 {213			t.Fatalf("benchmark reported 0 iterations")214		}215		if bRet.AllocsPerOp() != 0 {216			t.Errorf("want 0 allocs, got %d", bRet.AllocsPerOp())217		}218	})219}220 221func ExampleB_RunParallel() {222	// Parallel benchmark for text/template.Template.Execute on a single object.223	testing.Benchmark(func(b *testing.B) {224		templ := template.Must(template.New("test").Parse("Hello, {{.}}!"))225		// RunParallel will create GOMAXPROCS goroutines226		// and distribute work among them.227		b.RunParallel(func(pb *testing.PB) {228			// Each goroutine has its own bytes.Buffer.229			var buf bytes.Buffer230			for pb.Next() {231				// The loop body is executed b.N times total across all goroutines.232				buf.Reset()233				templ.Execute(&buf, "World")234			}235		})236	})237}238 239func TestReportMetric(t *testing.T) {240	res := testing.Benchmark(func(b *testing.B) {241		b.ReportMetric(12345, "ns/op")242		b.ReportMetric(0.2, "frobs/op")243	})244	// Test built-in overriding.245	if res.NsPerOp() != 12345 {246		t.Errorf("NsPerOp: expected %v, actual %v", 12345, res.NsPerOp())247	}248	// Test stringing.249	res.N = 1 // Make the output stable250	want := "       1\t     12345 ns/op\t         0.2000 frobs/op"251	if want != res.String() {252		t.Errorf("expected %q, actual %q", want, res.String())253	}254}255 256func ExampleB_ReportMetric() {257	// This reports a custom benchmark metric relevant to a258	// specific algorithm (in this case, sorting).259	testing.Benchmark(func(b *testing.B) {260		var compares int64261		for b.Loop() {262			s := []int{5, 4, 3, 2, 1}263			slices.SortFunc(s, func(a, b int) int {264				compares++265				return cmp.Compare(a, b)266			})267		}268		// This metric is per-operation, so divide by b.N and269		// report it as a "/op" unit.270		b.ReportMetric(float64(compares)/float64(b.N), "compares/op")271		// This metric is per-time, so divide by b.Elapsed and272		// report it as a "/ns" unit.273		b.ReportMetric(float64(compares)/float64(b.Elapsed().Nanoseconds()), "compares/ns")274	})275}276 277func ExampleB_ReportMetric_parallel() {278	// This reports a custom benchmark metric relevant to a279	// specific algorithm (in this case, sorting) in parallel.280	testing.Benchmark(func(b *testing.B) {281		var compares atomic.Int64282		b.RunParallel(func(pb *testing.PB) {283			for pb.Next() {284				s := []int{5, 4, 3, 2, 1}285				slices.SortFunc(s, func(a, b int) int {286					// Because RunParallel runs the function many287					// times in parallel, we must increment the288					// counter atomically to avoid racing writes.289					compares.Add(1)290					return cmp.Compare(a, b)291				})292			}293		})294 295		// NOTE: Report each metric once, after all of the parallel296		// calls have completed.297 298		// This metric is per-operation, so divide by b.N and299		// report it as a "/op" unit.300		b.ReportMetric(float64(compares.Load())/float64(b.N), "compares/op")301		// This metric is per-time, so divide by b.Elapsed and302		// report it as a "/ns" unit.303		b.ReportMetric(float64(compares.Load())/float64(b.Elapsed().Nanoseconds()), "compares/ns")304	})305}306 
codekingpro/portable-devtools · Team Ai